Обработчик NSJSONSerialization, возвращающий массив или словарь

Я звоню в API твиттеров, чтобы загрузить некоторые твиты для определенного раздела моего приложения.

Небольшая часть пользователей сообщает о сбое при загрузке просмотра твитов, в то время как у остальных проблем нет.

Я отправил код в службу технической поддержки Apple, и они ответили, сообщив мне, что NSJSONSerialization может иногда возвращать NSArray или NSDictionary.

Очевидно, что он выдаст ошибку objectAtIndex: вызывается для объекта NSDictionary, который, как я считаю, является виновником для всех моих пользователей.

Частичное решение состоит в том, чтобы определить, является ли это массивом или NSDictionary.

Вот где я сейчас:

id feedData = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&jsonError];

if ([feedData isKindOfClass:[NSArray class]]) {
     //Is array


} else if ([feedData isKindOfClass:[NSDictionary class]]) {
     //is dictionary


} 

Мне в основном нужен NSArray каждый раз. Итак, в блоке массива is я в основном просто использую feedData, но в NSDictionary, как я могу преобразовать его в NSArray, который будет соответствовать нужной мне структуре.

Честно говоря, самая большая проблема заключается в том, что я не вижу, как выглядит структура NSDictionary, потому что ни одно из моих тестовых устройств или симуляторов не возвращает данные NSDictionary, все они возвращают NSArray.

Вот как выглядит весь метод getUserFeed, который отправляет запрос в Twitter:

// Get the twitter feed
    NSURL *requestURL = [NSURL URLWithString:TW_API_TIMELINE];

    // Set up proper parameters
    NSMutableDictionary *timelineParameters = [[NSMutableDictionary alloc] init];
    [timelineParameters setObject:kNumTweets forKey:@"count"];
    [timelineParameters setObject:@"1" forKey:@"include_entities"];

    // Create the Social Request
    SLRequest *postRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodGET URL:requestURL parameters:timelineParameters];
    postRequest.account = self.delegate.userAccount;

    // Perform the request
    [postRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
        dispatch_async(dispatch_get_main_queue(), ^{
            // Check if we reached the reate limit
            if ([urlResponse statusCode] == 429) {

                // Rate limit reached
                // Display an alert letting the user know we have hit the rate limit

                UIAlertView *twitterAlert = [[UIAlertView alloc] initWithTitle:kRateLimitTitle
                                                                       message:kRateLimitMessage
                                                                      delegate:nil
                                                             cancelButtonTitle:@"Ok"
                                                             otherButtonTitles:nil];
                [twitterAlert show];


                // Stop animating the pull to refresh if it is animating
                [self.feedTableView.pullToRefreshView stopAnimating];

                return;

            }
            // Check if there was an error
            if (error) {

                NSLog(@"Error: %@", error.localizedDescription);

                // Stop animating the pull to refresh if it is animating
                [self.feedTableView.pullToRefreshView stopAnimating];

                return;

            }
            // Check if there is some response data
            if (responseData) {
                NSError *jsonError = nil;

                id feedData = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:&jsonError];

                if ([feedData isKindOfClass:[NSArray class]]) {
                    //Is array
                    NSLog(@"It's an Array");

                } else if ([feedData isKindOfClass:[NSDictionary class]]) {
                    //Is dictionary
                    NSLog(@"It's a Dictionary");




                } else {
                    //is something else


                }

                if (!jsonError) {

                    [self gatherTweetsFromArray:feedData];

                } else {

                    // Stop animating the pull to refresh if it is animating
                    [self.feedTableView.pullToRefreshView stopAnimating];


                    // Alert the user with the error
                    UIAlertView *twitterAlert = [[UIAlertView alloc] initWithTitle:kErrorTitle
                                                                           message:kErrorMessage
                                                                          delegate:nil
                                                                 cancelButtonTitle:@"Ok"
                                                                 otherButtonTitles:nil];
                    [twitterAlert show];


                }
            } else {

                // Stop animating the pull to refresh if it is animating
                [self.feedTableView.pullToRefreshView stopAnimating];

                // Alert the user with the error
                UIAlertView *twitterAlert = [[UIAlertView alloc] initWithTitle:kErrorTitle
                                                                       message:kErrorMessage
                                                                      delegate:nil
                                                             cancelButtonTitle:@"Ok"
                                                             otherButtonTitles:nil];
                [twitterAlert show];


            }


        });
    }];

Это ГЛАВНАЯ ошибка, и мне нужно ее устранить, поэтому любые идеи или информация будут очень признательны! Спасибо!


person Kyle Begeman    schedule 11.12.2013    source источник
comment
без представления о структуре словаря невозможно найти идеальное решение. Я предполагаю, поскольку только некоторые пользователи сообщают о сбое, что структура словаря возвращается в исключительных случаях, например. когда на твиттер-сервере возникла внутренняя ошибка. Я думаю, у вас все в порядке, когда вы показываете предупреждение о неизвестной ошибке всякий раз, когда возвращается что-то еще, кроме массива. Кроме того, вы можете сделать некоторые отчеты о сбоях либо с помощью стороннего репортера сбоев (рекомендуется Crashlytics), либо с помощью самодельного решения, ...   -  person Kai Huppmann    schedule 12.12.2013
comment
... напр. попросить пользователя отправить вам электронное письмо, к которому автоматически прикрепляется отладочное описание словаря.   -  person Kai Huppmann    schedule 12.12.2013
comment
Я разместил некоторый код, отображающий фактический блок вызова в Twitter API. Если это была внутренняя ошибка Twitter, должна ли она каждый раз затрагивать только определенных пользователей? Это небольшое число, но оно постоянно и никогда не работает. Спасибо за информацию и ссылку на Crashlytics, я обязательно изучу это!   -  person Kyle Begeman    schedule 12.12.2013
comment
Я не понял, что у немногих пользователей проблема постоянно. Знаете ли вы кого-нибудь из этих пользователей? если это так, просто найдите их общие черты (iOS-версия, брандмауэр, ...?), чтобы иметь возможность воспроизвести ошибку.   -  person Kai Huppmann    schedule 12.12.2013
comment
Вы знакомы с тем, как я могу скомпилировать feedData в строку, которую можно отправить по электронной почте и прочитать? Это кажется наиболее логичным способом хотя бы прочитать ошибку, которую получает пользователь.   -  person Kyle Begeman    schedule 12.12.2013
comment
просто используйте stringWithFormat и %@, чтобы получить не очень красивое, но работающее описание NSArray или NSDictionary. Возможно, вот несколько советов по украшению: 7121120/   -  person Kai Huppmann    schedule 12.12.2013
comment
Уродливое описание сработало просто отлично. Похоже, что твиттер передает ошибку, которая возвращается как NSDictionary. До сих пор у всех, у кого были сбои, была одна и та же ошибка. Ошибка имеет код ошибки 220. Ваши учетные данные не имеют доступа к этому запросу, что является очень странной ошибкой для вызова API iOS. Но это совсем другая проблема, которой я не занимаюсь. Спасибо за вашу помощь!   -  person Kyle Begeman    schedule 12.12.2013
comment
Добро пожаловать. Может быть, вам следует опубликовать все, что вы узнали, в качестве ответа на свой вопрос   -  person Kai Huppmann    schedule 12.12.2013