0

我有一个 IOS 项目(禁用 ARC),它有几个视图控制器。一个特定的控制器初始化 MyClass 类型的成员对象,但是当视图控制器被解除时,我正在为使用线程(使用调度异步)的对象调用清理方法来进行一些耗时的操作,然后当这些操作完成我在对象的主队列上执行 [self release]。这是一个好习惯,会导致任何错误吗?下面是一个与我正在做的类似的例子:

@implementation ViewController

- (void)viewDidLoad
{
    myObj = [[MyClass alloc] init];
}

-(void)viewWillDisappear
{
    [myObj cleanup];
}

@end

//myClass
@implementation MyClass

- (void)cleanup()
{
   dispatch_queue_t myQueue = dispatch_queue_create ("MyClassDeallocQueue", NULL);
   dispatch_async(myQueue, ^{
        //time consuming operations        

        dispatch_async(dispatch_get_main_queue(), ^{
        [self release];
        });
   });

}

@end
4

1 回答 1

0

这是一个好习惯,会导致任何错误吗?

目前,您的代码具有不平衡的保留/释放。这绝对是一个错误(过度发布)。

“这是好习惯吗?” - 好吧,我不知道你想要完成什么。但是如果你的目标是保持self存活,直到块被执行之后,它已经完全通过self将被捕获的事实来完成。因此,严格来说 arelease是不需要的。

但是,如果您没有self在主线程上显式释放,则会引入一个微妙的错误:可能会发生该块具有对 的最后引用self,并且由于它可能在某个任意线程上执行,因此它将self在该非主线程上释放。这是被禁止的:UIKit 方法(包括 dealloc)必须在主线程上调用!

因此,这可能是有道理的:

   [self retain];
   dispatch_async(myQueue, ^{
        // time consuming operation, which captures `self`        
        [self doSomething];
        ...
        // ensure that `dealloc` will be executed on the main thread, if 
        // last reference is held by the block:
        dispatch_async(dispatch_get_main_queue(), ^{
            [self release];
        });
   });

或更短:

   dispatch_async(myQueue, ^{
        // time consuming operation, which captures `self`        
        [self doSomething];
        ...
        // ensure that `dealloc` will be executed on the main thread, if 
        // last reference is held by the block:
        dispatch_async(dispatch_get_main_queue(), ^{
            [self self];
        });
   });

编辑:

这是一个有趣的问题,“短”版本实际上是安全的还是有比赛的:

假设,self将在myQueue上执行的块中释放,作为捕获self 之前的效果,它将保留在同一个self块中,作为在主队列上执行的块的捕获效果。然后,我们有一个问题。评论赞赏。

于 2014-01-21T15:33:53.343 回答