我很确定我知道发生了什么,但我想知道是否有一种阻止它发生的好方法。
基本上,我有一个从核心数据存储中查找内容的类方法,如果不存在则尝试从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
的{{1}}方法看起来像这样
MPRequest
答案 0 :(得分:1)
您的MPRequest
对象需要在连接运行时保持活动状态。最简单的方法是在连接启动时保留自己,然后在调用完成块后释放自己。在ARC下,最简单的方法是
CFRetain((__bridge CFTypeRef)self);
和
CFRelease((__bridge CFTypeRef)self);
从概念上讲,运行循环使请求保持活动状态。这就是NSURLConnection
的运作方式。但由于MPRequest
实际上并未附加到运行循环,它只是NSURLConnection
的包装器,您需要做一些工作以使其在相同的时间段内保持活动状态。
另请注意,NSURLConnection
需要添加到相应的runloop中。方便方法会将它添加到当前线程的runloop中,但是如果你在后台队列中,则不会起作用。你可以使用像
_connection = [[NSURLConnection alloc] initWithRequest:request delegate:delegate startImmediately:NO];
[_connection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
答案 1 :(得分:-1)
将此MPRequest设置在context performBlock:^{...}
之外,如下所示:
__strong MPRequest = // allocate or set the MPRequest.
[context performBlock:^{...}
现在performBlock
完成后,MPRequest将不会被释放,仍然可以设置为__strong
子句中指定的变量。