在非弧环境中使用块内的自身和自身属性

时间:2014-11-03 11:00:24

标签: ios objective-c iphone objective-c-blocks self

我在使用自身内部块时一直在使用块并熟悉内存管理 非ARC环境

但我有两个具体问题:

1)我明白我可以使用__block来避免保留周期一个保留的块,而后者又可以使用self创建,如下所示:

__block MyClass *blockSelf = self; 
self.myBlock = ^{  
     blockSelf.someProperty = abc;  
     [blockSelf someMethod]; 
};

这肯定会避免保留周期,但是通过这样做,我创建了一个自我发布的范围,并最终由其他人解除分配。所以当这种情况发生时,自我就消失了,而且blockSelf指向了垃圾值。在取消分配self之后执行块时可能存在条件,然后块将在尝试使用释放的实例时崩溃。我们怎样才能避免这种情况?如何在块执行时检查blockSelf是否有效,或者在取消分配self时检查块执行是否有效。

2)在类似的行上假设我使用如下的块:

__block MyClass *blockSelf = self; 
self.myBlock = ^{  
         [blockSelf someMethod:blockSelf.someProperty]; 
    };

// I am taking someProperty in an method argument
-(void) someMethod:(datatype*)myClassProperty
{
  myClassProperty = abc;
}

现在可能存在self未释放但在someMethod执行开始之前释放someProperty的情况(当有多个线程时可能会发生这种情况)。即使我做self.someProperty = nil;当它被释放时,myClassProperty不是nil并且指向一些垃圾,因此当执行someMethod时,第一行将导致崩溃。我该如何避免这种情况?

2 个答案:

答案 0 :(得分:3)

  1. 这与非ARC代码中的其他地方的非归零弱引用相同,例如:代表等(MRC没有将弱引用归零;因此这些是MRC中唯一的弱引用。但是人们仍然能够在ARC前的日子里编写安全代码。)

    基本上,解决方案是您需要一张清晰的所有权地图。要么self负责保持块活着;或其他一些对象负责保持块活着。

    例如,对于代表,通常是"父母" object是" child"的代表。宾语;在这种情况下,"父母"对象负责保持"孩子"对象存活,所以"父母"对象将比孩子更长寿#34;对象,因此后引用可以是弱的并且是安全的(因为子对象的方法只能在父对象处于活动状态时由父对象调用)。

    另一方面,如果你有一个异步操作,并且该块作为回调被赋予操作,那么通常操作负责保持块。在这种情况下,self不会保留在块上。该块将保留对self的强引用,以便在操作完成后,它仍然可以安全地执行它在self上需要执行的任何操作。实际上,无论对象self是什么,它都不需要由任何使用它的人保留,因为它是由异步操作间接保留的 - 它可以只是一个创建,触发和忘记那种事。

    如果你有一些东西,有时块被self保持活着,有时还被其他东西保持活着,那么你应该重新思考你的设计。你说"在取消分配self之后执行块时可能存在条件&#34 ;;好吧,你应该描述你的整个设计以及如何发生这种情况。因为通常,对于异步执行的事情,self不需要保留在块上。

  2. 您的代码真的很混乱,没有意义。例如,为什么要分配参数(myClassProperty)?无论如何,当参数被覆盖时,传递参数的重点是什么?为什么要命名一个局部变量" myClassProperty"?

    我认为您要问的是访问可以在不同线程上更改的属性,以及如何处理内存管理。 (这个问题与块或ARC / MRC无关。它同样是ARC中的一个问题。)

    答案是你需要一个原子属性。您可以创建同步属性atomic,或者如果您知道如何手动实现原子属性。对象指针类型的原子属性需要做的是它的getter不仅需要返回底层变量,还需要保留并自动释放它,并返回结果。 getter中的检索和保留发生在一个关键部分,该部分与setter中的关键部分同步,包括旧值的释放和新值的保留。基本上,这种同步保证了在检索值并将其保留在getter中之间不会在setter中释放该值。并且从getter返回的值将被保留并自动释放,因此保证在范围的持续时间内保持活动状态。

答案 1 :(得分:-2)

解决方案2)

__block MyClass *blockSelf = self; 
self.myBlock = ^{
         datatype* p = [blockSelf.someProperty retain];
         [blockSelf someMethod:p]; 
         [p release];
    };

// I am taking someProperty in an method argument
-(void) someMethod:(datatype*)myClassProperty
{
  myClassProperty = abc;
}

1)不知道你如何使用myBlock。如果仅由self使用,那么一切都会好的。如果它被其他一些对象使用,那么它也应该保留self的引用,然后一切都会好的。