在dispatch_async中设置属性,但在块完成后属性为NULL

时间:2013-05-21 01:26:31

标签: ios objective-c grand-central-dispatch

我使用以下代码在视图控制器中更改名为topPlaces的属性。行[FlickrFetcher topPlaces]返回NSArray,我的属性topPlaces当然也是NSArray。

dispatch_queue_t downloadQueue = dispatch_queue_create("flickr topPlace", NULL);
dispatch_async(downloadQueue, ^{
    NSArray *topPlaces = [FlickrFetcher topPlaces];
    dispatch_async(dispatch_get_main_queue(), ^{
        self.topPlaces = topPlaces;
    });
});
dispatch_release(downloadQueue);

但是,在块完成执行后,如果我记录self.topPlaces的值,由于某种原因仍然是NULL。有什么我想念的吗?

2 个答案:

答案 0 :(得分:3)

在您当前的方法完成之后,您的ivar将不会被设置。您对[FlickrFetcher topPlaces]的呼叫与您当前的方法并行运行,需要一段随机时间才能完成。当它完成时,它会回调主线程,这将在运行循环的下一次迭代中执行

这意味着在第二个dispatch_async()块中,您需要在设置ivar后调用任何方法来显示数据。

答案 1 :(得分:2)

请先尝试将self.topPlaces存储起来:

dispatch_queue_t downloadQueue = dispatch_queue_create("flickr topPlace", NULL);
dispatch_async(downloadQueue, ^{
    NSArray *topPlaces = [FlickrFetcher topPlaces];
    dispatch_async(dispatch_get_main_queue(), ^{
        self.topPlaces = @[@"test", @"test2", @"test3"];
    });
});

然后检查self.topPlaces的值。如果它仍然是NULL那么我需要询问您的财产self.topPlaces有哪些终身限定符(例如强,弱,分配)?如果是weak那么当然,topPlaces的值在分配之后将为NULL,因为它不会有任何强指针。如果是strong,那么当执行到达NSArray *topPlaces = [FlickrFetcher topPlaces];时,NULL的值为self.topPlaces = topPlaces;

另一件需要考虑的事情是,当您执行异步操作时,主线程上的执行将继续执行。所以,如果你正在做以下......

dispatch_queue_t downloadQueue = dispatch_queue_create("flickr topPlace", NULL);
dispatch_async(downloadQueue, ^{
    NSArray *topPlaces = [FlickrFetcher topPlaces];
    dispatch_async(dispatch_get_main_queue(), ^{
        self.topPlaces = topPlaces;
    });
});
NSLog(@"topPlaces = %@", self.topPlaces);

然后我希望self.topPlaces在遇到NULL时始终为NSLog,因为它不会在[FlickrFetcher topPlaces]完成并返回之后设置执行继续进入dispatch_async(dispatch_get_main_queue()...。此时应设置该值。您可能希望执行以下操作,以确保您不仅设置了属性,而且在异步操作完成后执行某种更新操作来更新UI ...

dispatch_queue_t downloadQueue = dispatch_queue_create("flickr topPlace", NULL);
dispatch_async(downloadQueue, ^{
    NSArray *topPlaces = [FlickrFetcher topPlaces];
    dispatch_async(dispatch_get_main_queue(), ^{
        [self updateUIWithTopPlaces:topPlaces];
    });
});

- (void)updateUIWithTopPlaces:(NSArray*)topPlaces {
    self.topPlaces = topPlaces;
    // Perform your UI updates here
}