我想实现的是在后台执行任务的方法,然后调用主线程块:
+ (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
之后[controller migrateStore]
由于controller
是保存到块的对象,我不能够永远调用它。 有没有人对如何解决这个问题有什么建议?
使用对你有利的可怕的“保留周期”。
基本上,控制器对象强烈引用其_completion伊娃,所以如果你把该块强烈引用self
,那么你有一个保留周期,这使物体活着,只要你想要的。
编译指示暂时关闭的保留周期警告。
然后,您可以手动调用处理程序后设置完成块零突破保留周期。
- (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);
你可以考虑具有含类+migrateStoreWithCompletionHandler:
跟踪所有生成的MigrationController实例的私人阵列或相似。 这将保持controller
被过早地释放,并允许你打电话给你完成块。
你需要找到一种方法后来将他们释放,不过,为了避免缓慢增长你的内存使用情况为您做出MigrationControllers。 你可能会考虑在年底发布来自控制器的通知-migrateStore
调用完成块之后,然后让你的工厂类侦听该通知和解除分配适当的控制器。 (你也可以得到类似的行为与委托模式,如果你是这样的倾向。)
这是ARC的唯一真正的限制,我到目前为止已经处理了。 有简单的方法来解决它,但是:
1)可以创建用于一个静态变量MigrationController
对象,并将其设置为nil
被调用完成块时。
2) 只有做到这一点,当你真的知道你在做什么!
使用CFRetain()
和CFRelease()
直接:
+ (void)migrateStoreWithCompletionHandler:(MigrationControllerCompletion)completion
{
MigrationController *controller = [[MigrationController alloc] initWithCompletionBlock:^(MigrationController *migrationController, BOOL finished, ...) {
if (completion != nil)
completion(migrationController, finished, ...);
CFRelease((__bridge void *)migrationController);
}];
[controller migrateStore];
// Make 'controller' live until the completion block is invoked
CFRetain((__bridge void *)controller);
}