GCD内存管理

时间:2015-09-29 16:37:06

标签: macos cocoa grand-central-dispatch

在我的代码中,我需要观察NSBlockOperation已完成并通过 block 值进行通知。

我想在没有KVO,代表或子类的情况下这样做。为此,我使用了GCD和dispatch_group_notify。这段代码适合我,但我不确定内存管理。这种方法会导致崩溃吗?例如,一个潜在的问题可能是在dispatch_release(group)之后阻止调用;

- (void)collectLastRunnedDate: (void (^)()) block
{
    NSAssert(block, @"Block should not be nil");

    dispatch_group_t group = dispatch_group_create();

    dispatch_group_notify(group, dispatch_get_main_queue(), block);

    NSBlockOperation * blockOperation = [NSBlockOperation blockOperationWithBlock:^{

        dispatch_group_enter(group);

        self.lastRunnedDate = [self lastRunnedDateForPeriodicName:@"daily"];

        if(!self.lastRunnedDate)
        {
            self.lastRunnedDate = [self lastRunnedDateForPeriodicName:@"weekly"];
        }

        if(!self.lastRunnedDate)
        {
            self.lastRunnedDate = [self lastRunnedDateForPeriodicName:@"monthly"];
        }

        if(!self.lastRunnedDate)
        {
            self.lastRunnedDate = [[Preferences sharedInstance] periodicsLastRunned];
        }

        dispatch_group_leave(group);

        dispatch_release(group);
    }];

    [[NSOperationQueue queue] addOperation:blockOperation];
}

2 个答案:

答案 0 :(得分:0)

来自dispatch_release的{​​{3}}:

  

组 - 观察派遣小组。系统保留该组,直到该块运行完成。

注意:如果您使用ARC,则无需拨打{{1}}。

HTH

答案 1 :(得分:0)

您正在错误地使用该群组。

在输入任何内容之前,您正在呼叫dispatch_group_notify()。来自文档:

  

如果组为空(没有块对象与调度组关联),则立即提交通知块对象。

这适用于您如何使用它。

与上述相关的是您使用与其相同的代码输入块。那不是正常模式。您通常在提交之前调用dispatch_group_enter()将调用dispatch_group_leave()的异步任务,以便该组在同步代码中具有正数。

所以,你可以这样做:

- (void)collectLastRunnedDate: (void (^)()) block
{
    NSAssert(block, @"Block should not be nil");

    dispatch_group_t group = dispatch_group_create();

    dispatch_group_enter(group);

    NSBlockOperation * blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        // whatever work the block should do goes here

        dispatch_group_leave(group);
    }];

    [[NSOperationQueue queue] addOperation:blockOperation];

    dispatch_group_notify(group, dispatch_get_main_queue(), block);

    dispatch_release(group); // Only needed if you're not using ARC
}

由于您似乎只是将操作对象提交到匿名操作队列,因此您可以轻松使用dispatch_group_async()。这有效地为您进入和离开操作。

此外,如果您不知道,NSOperation具有completionBlock属性,该属性是在操作完成时自动运行的块。当然,NSBlockOperation继承了这一点。您可以将其设置为一个块,它将您的block参数异步提交到主队列,并完全避免使用调度组:

- (void)collectLastRunnedDate: (void (^)()) block
{
    NSAssert(block, @"Block should not be nil");

    NSBlockOperation * blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        // whatever work the block should do goes here
    }];

    blockOperation.completionBlock = ^{
        dispatch_async(dispatch_get_main_queue(), block);
    };

    [[NSOperationQueue queue] addOperation:blockOperation];
}