Note that there are some explanatory texts on larger screens.

plurals
  1. POAFNetworking getting response JSON from the wrong endpoint
    primarykey
    data
    text
    <p>I am seeing a really weird and random issue in my code that I can't track down. I am getting crashes in my data model init methods when returning from AFNetworking JSON request methods. When the app does crash I am able to step back in the call stack to debug the what the JSON request/response was. The weird part is when I check the URL, request, and resonseJSON. The responseJSON does not match the expected result of the URL/request. It's like I am getting some other API methods call and data. Because the data/JSON is not what I expect the app will crash on model init. </p> <p>The data I get back is usually different and not always the same. Sometimes the data is from endpoint A and sometimes it is from B, it's never consistent. It does however seem to crash consistently in the same model object.</p> <p>Request endpoint A data but I get back endpoint B data. When I debug the AFHttpOperation when it crashes I see this is the result. It's almost like 2 calls are getting crossed and is some type of race condition. Below is a sample of my model object, Rest client, and model access layer.</p> <p><strong>Model Object</strong></p> <pre><code>@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 </code></pre> <p><strong>Rest Client</strong></p> <pre><code>@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(&amp;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 </code></pre> <p><strong>Model Access Layer</strong></p> <pre><code>@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 </code></pre> <p>A Location is a root object in the application and it will be told to refresh often. Either through UI interaction, events, or data Deserialization the the refreshApplications will execute to get more data from the server. Meanwhile other requests and events are going on in the application to get and send data to the API is JSON. Some of these GET calls to other endpoints seem to be messing with the response data.</p> <p><strong>Questions</strong></p> <ol> <li>How could this be happening with AFNetworking?</li> <li>Am I being too quick to blame AFNetowrking and should I be looking for other places in my system that could be crossing the responses? I do have a load balanced backend hosted at Amazon.</li> <li>Is this an endpoint issue?</li> <li>How can I better debug and reproduce this issue? It only comes up at random times and is very hard to replicate. I have to continually run and re-run the application in hopes that it is crash.</li> <li>Are there any advanced debugging techniques that I can use to back trace this call/crash using xcode?</li> </ol>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload