本文介绍了使对象保持活动状态,直到后台任务完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现一种方法,该方法在后台执行任务,然后在主线程上调用一个块:

+ (void)migrateStoreWithCompletionHandler:(MigrationControllerCompletion)completion
{
    MigrationController *controller = [[MigrationController alloc] initWithCompletionBlock:completion];

    [controller migrateStore];
}

这是-initWithCompletionBlock:方法:

- (id)initWithCompletionBlock:(MigrationControllerCompletion)completion
{
    self = [super init];

    if (self)
    {
        _completion = [completion copy];
    }

    return self;
}

后台工作发生在-migrateStore中.问题是ARC在[controller migrateStore]之后释放controller.因为controller是保存在块上的对象,所以我永远无法调用它.有人对如何解决此问题有任何建议吗?

解决方案

使用可怕的保留周期".

基本上,控制器对象强烈引用其_completion iVar,因此,如果使该块强烈引用self,则您将拥有一个保留周期,该保留周期可以使对象一直保持活动状态.

编译指示暂时使保留周期警告静音.

然后您可以通过在调用处理程序后将完成块设置为nil来手动中断保留周期.

- (id)initWithCompletionBlock:(MigrationControllerCompletion)completion
{
    self = [super init];

    if (self)
    {
        _completion = ^(BOOL success) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
            if (completion) completion(self, success);
#pragma clang diagnostic pop
            _completion = nil;
        };
    }

    return self;
}

然后,在您的代码中,当您要调用完成处理程序时,不必传递self,因为它已经存在了...

_completion(success);

I am trying to implement a method that executes a task in the background and then calls a block on the main thread:

+ (void)migrateStoreWithCompletionHandler:(MigrationControllerCompletion)completion
{
    MigrationController *controller = [[MigrationController alloc] initWithCompletionBlock:completion];

    [controller migrateStore];
}

This is the -initWithCompletionBlock: method:

- (id)initWithCompletionBlock:(MigrationControllerCompletion)completion
{
    self = [super init];

    if (self)
    {
        _completion = [completion copy];
    }

    return self;
}

The background work happens in -migrateStore. The problem is that ARC releases controller after [controller migrateStore]. Because controller is the object that holds onto the block, I am not able to ever call it. Does anyone have any suggestions on how to work around this issue?

解决方案

Use the dreaded "retain cycle" in your favor.

Basically, the controller object is strongly referencing its _completion iVar, so if you make that block strongly reference self then you have a retain cycle, which keeps the object alive for as long as you want.

The pragmas temporarily silence the retain cycle warning.

You can then manually break the retain cycle by setting the completion block to nil after calling the handler.

- (id)initWithCompletionBlock:(MigrationControllerCompletion)completion
{
    self = [super init];

    if (self)
    {
        _completion = ^(BOOL success) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
            if (completion) completion(self, success);
#pragma clang diagnostic pop
            _completion = nil;
        };
    }

    return self;
}

Then, in your code, when you want to call the completion handler, you don't have to pass self because it's already there...

_completion(success);

这篇关于使对象保持活动状态,直到后台任务完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-26 07:56