dispatch_group_t问题,dispatch_group_notify在离开组之前回调

时间:2014-05-10 14:10:07

标签: objective-c parse-platform objective-c-blocks grand-central-dispatch

下面我有以下代码片段,它们在后台使用PFQueues从Parse获取数据并返回数据和状态。该结构基于等待dispatch_group_t通知它已完成所有输入的组。不幸的是dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{ 在完成块调用dispatch_group_leave之前调用。在任何完成块上调用dispatch_group_leave()时,将抛出EXC_BAD_INSTRUCTION。我已在下面附上了一张图片,说明了指令错误。有没有人知道我做错了什么,或者Parse有些烦恼阻止我使用这种方法?

    - (void)downloadAndCacheObjectsWithCompletion:(void (^)(NSError *))callback
{

    __block NSError *downloadError1;
    __block NSError *downloadError2;
    __block NSError *downloadError3;
    __block NSError *downloadError4;

    NSLog(@"%@", NSStringFromSelector(_cmd));

        dispatch_group_t downloadGroup = dispatch_group_create();

        dispatch_group_enter(downloadGroup);
        [self fetchDataWithCompletion:^(NSArray *artwork, NSError *error) {
            downloadError1 = error;
            dispatch_group_leave(downloadGroup);
        }];

        dispatch_group_enter(downloadGroup);
        [self fetchDataWithCompletion:^(NSArray *artworkPhotos, NSError *error) {
            downloadError2 = error;
            dispatch_group_leave(downloadGroup);
        }];

        dispatch_group_enter(downloadGroup);
        [self fetchDataWithCompletion:^(NSArray *artists, NSError *error) {
            downloadError3 = error;
            dispatch_group_leave(downloadGroup);
        }];

        dispatch_group_enter(downloadGroup);
        [self fetchDataWithCompletion:^(NSArray *badges, NSError *error) {
            downloadError4 = error;
            dispatch_group_leave(downloadGroup);
        }];


        dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{
            NSError *returnError;
            if (downloadError1 || downloadError2 || downloadError3 || downloadError4) {
                returnError = [[NSError alloc] initWithDomain:@"ParseFactory" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"There was an error retrieving the content"}];
            }
            if (callback) {
              callback(returnError);
            }
        });

}



 - (void)fetchDataWithCompletion:(void(^)(NSArray *data, NSError *error))callback
{
    NSLog(@"Fetching Data");
    if ([self.cachedData objectForKey:kDataClassName]) {
        if (callback) {
            callback([self.cachedData objectForKey:kDataClassName], nil);
        }
        return;
    }
    PFQuery *dataQueue = [PFQuery queryWithClassName:kDataClassName];
    dataQueue.cachePolicy = kPFCachePolicyCacheThenNetwork;
    [dataQueue findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {

        if (!error) {
            [self.cachedData setObject:objects forKey:kDataClassName];
        } else {
           NSLog(@"Fetching Data Error: %@", error);
        }
        if (callback) {
            callback(objects, error);
        }
    }];

}

上面列出的下载过程是从AppDelegate中调用的

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//Register PFObject subclasses
    [Data registerSubclass];

[Parse setApplicationId:@"appkey" clientKey:@"clientkey"];
    [[ParseFactory sharedInstance] downloadAndCacheObjectsWithCompletion:^(NSError *error) {

    }];

    return YES;
}

enter image description here

堆栈跟踪: enter image description here enter image description here

2 个答案:

答案 0 :(得分:3)

您看到的错误表示您的程序调用{​​{1}}次数太多。重现它是微不足道的。我用这个程序复制了它:

dispatch_group_leave

因此,我推断您的int main(int argc, const char * argv[]) { @autoreleasepool { dispatch_group_t group = dispatch_group_create(); dispatch_group_leave(group); } return 0; } 方法不止一次调用其完成块。如果您无法弄清楚原因,请编辑您的问题以包含该方法的源代码(以及任何相关的方法或声明)。

答案 1 :(得分:0)

我来晚了,但很明显你的问题来自kPFCachePolicyCacheThenNetwork。 Parse将调用完成块两次,一次使用缓存数据(即使是第一次),一次使用下载数据...因此,dispatch_group_leave将被调用为dispatch_group_enter的两倍。