Я вижу в моем коде действительно странную и случайную проблему, которую я не могу отслеживать. Я получаю сбои в методах 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 для других конечных точек, похоже, возились с данными ответа.
Вопросы
- Как это могло случиться с AFNetworking?
- Я слишком быстро обвиняю AFNetowrking и должен ли я искать другие места в моей системе, которые могли бы пересекать ответы? У меня есть балансировка нагрузки, размещенная на Amazon.
- Это проблема с конечной точкой?
- Как лучше отладить и воспроизвести эту проблему? Это происходит только в случайные моменты времени и очень сложно реплицировать. Я должен постоянно запускать и повторно запускать приложение в надежде, что он сбой.
- Есть ли какие-либо усовершенствованные методы отладки, которые я могу использовать для отслеживания этого вызова/сбоя с помощью xcode?
Вы можете включить точки прерывания исключения, которые могут показать вам точную строку, где появится сбой, также он покажет вам поток, на котором появится сбой. Также он действительно поможет увидеть журнал сбоев. – danypata
У меня уже есть это, вот как я знаю, где он рушится. –
Вы пытались использовать Postman или любой другой клиент REST для проверки того, что данные всегда согласованы с сервером? Я все время использую AFNetworking и никогда не видел перекрестных запросов. Кроме того, можете ли вы опубликовать любой отчет о сбое? –