ios - AFNetworking 从错误端点获取响应 JSON

标签 ios objective-c debugging objective-c-blocks afnetworking

我在我的代码中发现了一个非常奇怪且随机的问题,但我无法追踪。从 AFNetworking JSON 请求方法返回时,我的数据模型 init 方法发生崩溃。当应用程序崩溃时,我可以退回调用堆栈来调试 JSON 请求/响应。奇怪的部分是当我检查 URL、请求和 resonseJSON 时。 responseJSON 与 URL/请求的预期结果不匹配。就像我正在获取其他一些 API 方法调用和数据一样。因为数据/JSON 不是我所期望的,所以应用程序将在模型初始化时崩溃。

我得到的数据通常是不同的,并且并不总是相同。有时数据来自端点 A,有时来自 B,它永远不会一致。然而,它似乎在同一个模型对象中始终崩溃。

请求端点 A 数据,但我得到端点 B 数据。当我调试 AFHttpOperation 崩溃时,我看到这就是结果。这几乎就像两个调用交叉,并且是某种类型的竞争条件。下面是我的模型对象、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

位置是应用程序中的根对象,它会被告知经常刷新。通过 UI 交互、事件或数据反序列化,refreshApplications 将执行以从服务器获取更多数据。与此同时,应用程序中正在发生其他请求和事件,以 JSON 格式获取数据并将数据发送到 API。其中一些对其他端点的 GET 调用似乎扰乱了响应数据。

问题

  1. AFNetworking 怎么会发生这种情况?
  2. 我是否太快地指责 AFNetowrking?我是否应该在系统中寻找可能交叉响应的其他位置?我确实有一个托管在 Amazon 上的负载平衡后端。
  3. 这是端点问题吗?
  4. 如何更好地调试和重现此问题?它只会随机出现,并且很难复制。我必须不断运行并重新运行该应用程序,希望它会崩溃。
  5. 是否有任何高级调试技术可用于使用 xcode 来回溯此调用/崩溃?

最佳答案

我建议您使用 Charles 代理来仔细检查您收到的数据是否正确。有一个试用版,在 30 天内与注册版的工作方式相同。我的第一个猜测是,您和服务器之间存在某种有缺陷的缓存层,或者您的服务器有缺陷。像 Charles 这样的 HTTP 代理将允许您确认或拒绝这个假设。

This page解释如何设置 Charles 来代理来自 iOS 设备的非 HTTPS 连接。

关于ios - AFNetworking 从错误端点获取响应 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17128169/

相关文章:

ios - 如何防止单击叠加层时调用背景 View 中的 UITapGestureRecognizer

objective-c - 数组中的NSIndexSet

ios - 如何正确初始化类

ios - 以编程方式创建的按钮缺少圆角

ios - 创建重复事件而不在 iOS 的日历中显示这些事件

JavaScript 调试工具

c - atof 产生奇怪的结果

iphone - 为什么我的 .aif 短声音文件只能在 iOS 模拟器上播放,而不能在设备上播放?

iphone - 我想在 iOS 中实现图像处理算法,你能推荐一些好的入门指南吗

php - xdebug 跟踪/跟踪 php 回显,打印调用