2

Я вижу в моем коде действительно странную и случайную проблему, которую я не могу отслеживать. Я получаю сбои в методах init модели данных при возврате из методов запроса AFNetworking JSON. Когда приложение аварийно завершает работу, я могу вернуться в стек вызовов, чтобы отладить то, что было запросом/ответом JSON. Странная часть - это когда я проверяю URL, запрос и resonseJSON. Ответ JSON не соответствует ожидаемому результату URL/запроса. Это похоже на то, что я получаю вызов других методов API и данных. Поскольку данные/JSON не являются тем, что я ожидаю, приложение столкнется с модой init.AFNetworking получает ответ JSON с неправильной конечной точки

Данные, которые я возвращаю, обычно разные и не всегда одинаковые. Иногда данные от конечной точки A, а иногда и от B, это никогда не бывает согласованным. Тем не менее он, похоже, постоянно падает в одном и том же объекте модели.

Запросить конечную точку Данные, но я возвращаю данные конечной точки B. Когда я отлаживаю AFHttpOperation, когда он падает, я вижу, что это результат. Это почти как 2 звонка, которые пересекаются, и это какое-то состояние гонки. Ниже приведен образец моего объекта модели, клиента Rest и слоя доступа к модели.

объектная модель

@implementation Applications 

- (id)initWithData:(NSDictionary *)appData forLocation:(Location *)location inCategory:(Category *)category { 
    // appData is the JSON returned by The Rest Client and AFNetworking 
    self = [super init]; 
    DDLogVerbose(@"appData = %@", appData); 
    if (self) { 
     _location = location; 
     _listeners = [NSMutableArray mutableArrayUsingWeakReferences]; 
     _devices = [[NSMutableDictionary alloc] init]; 
     _category = category; 
     _subscriptions = [Utility sanitizeArray:appData[@"Subscriptions"]]; 
    } 
    return self; 
} 

@end 

@implementation Location 

- (void)refreshApplications { 
    [[Model shared] appsForLocation:self 
          success:^(NSObject *obj) { 
     self.apps = nil; //we have to get our apps again 
     self.apps = [NSMutableArray array]; 

     NSArray *newApps = (NSArray *) obj; 
     for (NSDictionary *app in newApps) { 
      **// This is where it's crashing!** 
      Applications *newApp = [[Applications alloc] initWithData:app 
                  forLocation:self 
                  inCategory:[[SmartAppCategory alloc] init]]; 
      [self.apps addObject:newApp]; 
     } 

     [self notifyListeners]; 
    } 
          error:nil]; 
} 

@end 

Остальной Клиент

@interface Rest 

+ (Rest *)sharedClient; 
- (void)GET:(NSString *)path parameters:(NSDictionary *)params success:(SuccessCallback)sCallback error:(ErrorCallback)eCallback; 

@end 

@implementation Rest 

+ (Rest *)sharedClient { 
    static dispatch_once_t token; 
    static Rest *shared = nil; 
    dispatch_once(&token, ^{ 
     shared = [[Rest alloc] init]; 
    }); 
    return shared; 
} 

- (id)init { 
    self = [super init]; 
    if (self) { 
     [self createClients]; 
    } 
    return self; 
} 

- (void)createClients { 
    // Setup the Secure Client 
    // Private implementation properties 
    self.secureClient = [[AFOAuth2Client alloc] initWithBaseURL:baseUrl clientID:OAUTH2_CLIENT_ID secret:OAUTH2_CLIENT_SECRET]; 
    [self.secureClient setParameterEncoding:AFJSONParameterEncoding]; 
    AFOAuthCredential *credential = (AFOAuthCredential *) [NSKeyedUnarchiver unarchiveObjectWithData:[KeyChainStore dataForKey:KEYCHAIN_SETTINGS_AFOAuthCredential]]; 
    if (credential) { 
     [self.secureClient setAuthorizationHeaderWithToken:credential.accessToken]; 
    } 

    // Setup the Anonymous Client 
    self.anonymousClient = [[AFHTTPClient alloc] initWithBaseURL:baseUrl]; 
    [self.anonymousClient setParameterEncoding:AFJSONParameterEncoding]; 
    [self.anonymousClient registerHTTPOperationClass:[AFJSONRequestOperation class]]; 
} 

- (void)GET:(NSString *)path parameters:(NSDictionary *)params success:(SuccessCallback)sCallback error:(ErrorCallback)eCallback { 

    [_secureClient getPath:path 
       parameters:params 
        success:^(AFHTTPRequestOperation *operation, id responseObject) { 
         DDLogVerbose(@"Success Path: %@ JSON: %@", path, responseObject); 
         if (sCallback) sCallback(responseObject); 
        } 
        failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
         [Rest callErrorBlock:eCallback withOperation:operation]; 
        }]; 
} 

@end 

Модель доступа Слой

@interface Model 

+ (Model *)shared; 
- (void)appsForLocation:(Location *)location success:(SuccessCallback)success error:(ErrorCallback)error; 

@end 

@implementation Model 

- (void)appsForLocation:(Location *)location success:(SuccessCallback)success error:(ErrorCallback)error { 
    NSString *path = [NSString stringWithFormat:@"/api/locations/%@/apps/", location.locationId]; 

    [[Rest sharedClient] GET:path parameters:nil success:success error:error]; 
} 

@end 

Ло cation - это корневой объект в приложении, и ему будет сказано часто обновлять. Либо через взаимодействие, события или данные пользовательского интерфейса, десериализационные действия refreshApplications будут выполняться для получения большего количества данных с сервера. Между тем другие запросы и события в приложении для получения и отправки данных в API - это JSON. Некоторые из этих вызовов GET для других конечных точек, похоже, возились с данными ответа.

Вопросы

  1. Как это могло случиться с AFNetworking?
  2. Я слишком быстро обвиняю AFNetowrking и должен ли я искать другие места в моей системе, которые могли бы пересекать ответы? У меня есть балансировка нагрузки, размещенная на Amazon.
  3. Это проблема с конечной точкой?
  4. Как лучше отладить и воспроизвести эту проблему? Это происходит только в случайные моменты времени и очень сложно реплицировать. Я должен постоянно запускать и повторно запускать приложение в надежде, что он сбой.
  5. Есть ли какие-либо усовершенствованные методы отладки, которые я могу использовать для отслеживания этого вызова/сбоя с помощью xcode?
+0

Вы можете включить точки прерывания исключения, которые могут показать вам точную строку, где появится сбой, также он покажет вам поток, на котором появится сбой. Также он действительно поможет увидеть журнал сбоев. – danypata

+0

У меня уже есть это, вот как я знаю, где он рушится. –

+0

Вы пытались использовать Postman или любой другой клиент REST для проверки того, что данные всегда согласованы с сервером? Я все время использую AFNetworking и никогда не видел перекрестных запросов. Кроме того, можете ли вы опубликовать любой отчет о сбое? –

ответ

4

Я рекомендую вам использовать прокси-сервер Charles, чтобы дважды проверить, что данные, которые вы получаете, верны. Доступна пробная версия, которая работает идентично зарегистрированной версии в течение 30 дней. Мое первое предположение заключается в том, что между вами и вашим сервером существует какой-то плохой кэш-уровень, или ваш сервер неисправен. Прокси-сервер HTTP, такой как Charles, позволит вам подтвердить или отклонить эту гипотезу.

This page объясняет, как настроить подключение к прокси-серверу без подключения HTTPS с устройств iOS.

1

Для отладки, не HTTPS, а также HTTPS трафика с помощью mitmproxy

Это позволяет проверить все пакеты, а также их повторно и многое другое. С этим вы можете проверить, что на самом деле происходит, и если проблема с базой данных или если у AFNetworking есть ошибка.

И как прохладный побочный эффект mitmproxy является абсолютно бесплатным и открыт под лицензией MIT. На своем веб-сайте вы найдете несколько удобных обучающих программ для iOS.

Смежные вопросы