块内发布的对象

时间:2013-01-08 20:13:35

标签: objective-c ios cocoa-touch core-data

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

基本上,我有一个从核心数据存储中查找内容的类方法,如果不存在则尝试从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

2 个答案:

答案 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子句中指定的变量。