1

我很确定我知道发生了什么,但是我想知道是否有阻止它发生的好方法。

基本上,我有一个类方法,它从核心数据存储中查找某些内容,如果不存在,则尝试从 Web 服务器获取它。核心数据查找和请求在托管对象上下文performBlock方法中执行。

我有以下代码块:

[context performBlock:^{
    __block NSError *error;
    NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:NSStringFromClass([self class])];
    [request setSortDescriptors:@[[[NSSortDescriptor alloc] initWithKey:key ascending:asc selector:@selector(caseInsensitiveCompare:)]]];

    NSFetchedResultsController *controller = [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                                                                 managedObjectContext:context
                                                                                   sectionNameKeyPath:keyPath
                                                                                            cacheName:nil];

    [controller performFetch:&error];

    if (!controller.fetchedObjects || controller.fetchedObjects.count == 0) {
        // Nothing found or an error, query the server instead
                NSString *url = [NSString stringWithFormat:@"%@%@", kMP_BASE_API_URL, [self baseURL]];
        MPRequest *objRequest = [MPRequest requestWithURL:url];

        [objRequest setRequestMethod:@"GET"];
        [MPUser signRequest:objRequest];

        [objRequest submit:^(MPResponse *resp, NSError *err) {
            if (err) {
                block(nil, err);
            } else {
                NSArray *objects = [self createListWithResponse:resp];
                         objects = [MPModel saveAllLocally:objects forEntityName:NSStringFromClass([self class])];
                [controller performFetch:&error];
                block(controller, nil);
            }

        }];
    } else {
        // Great, we found something :)
        block (controller, nil);
    }
}];

正在发生的事情是创建并触发了 MPRequest 对象,但是 submit 方法触发了异步请求,因此几乎立即返回。我假设 ARC 正在释放 MPRequest 对象。执行请求时,内部请求对象的委托不再存在,因为 ARC 已将其释放(MPRequest 对象是它所拥有的内部请求的委托)。因此,不会调用提交方法提供的块。

有什么方法可以防止 ARC 在不使请求同步的情况下执行此操作?

编辑

submit方法MPRequest看起来像这样

_completionBlock = block;
   _responseData = [[NSMutableData alloc] init];

[self prepareRequest];

[self prepareRequestHeaders];
_connection = [[NSURLConnection alloc] initWithRequest:_urlRequest
                                              delegate:self];
[self requestStarted];
4

2 回答 2

1

您的MPRequest对象需要在连接运行时保持活动状态。最简单的方法可能是在连接开始时保留自己,然后在调用完成块后释放自己。在 ARC 下,最简单的方法是

CFRetain((__bridge CFTypeRef)self);

CFRelease((__bridge CFTypeRef)self);

从概念上讲,运行循环使请求保持活动状态。就是这样NSURLConnection运作的。但由于MPRequest它实际上并没有附加到运行循环,它只是一个包装器NSURLConnection,你需要做一些工作来让它在同一时间段内保持活动状态。

另请注意,NSURLConnection需要将其添加到相应的运行循环中。便捷方法会将其添加到当前线程的运行循环中,但如果您在后台队列中,那将无法正常工作。你可以使用类似的东西

_connection = [[NSURLConnection alloc] initWithRequest:request delegate:delegate startImmediately:NO];
[_connection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
于 2013-01-08T22:12:03.990 回答
-1

将此 MPRequest 设置在context performBlock:^{...}类似之外:

__strong MPRequest = // allocate or set the MPRequest.
[context performBlock:^{...}

现在一旦performBlock完成, MPRequest 将不会被释放,并且仍然设置为您在__strong子句中指定的任何变量。

于 2013-01-08T20:36:30.570 回答