2012-12-21 62 views
1

以前也有类似的问题,但是我无法解决我目前遇到的任何问题。保留iOS块的问题

现状:

CustomType *Object; 
BOOL (^doAverage)(CustomType *, int, int) = ^(CustomType *Trigger, int Total, int Pulse) { 
    //Calculate Average from Total and Pulse 
    Total /= Pulse; 
    [Trigger setValue:Total]; 
}; 

Object = [CustomType CreateObject]; //Autoreleased Object 
[Object addCallback:^{ return doAverage(Object, 56, 32); }]; 
[Array addObject:Object];  //Adds to collection. 

问题在手,你可能已经想通保留周期。
Object保留对addCallback中的块的引用,并且块doAverage保留对Object的引用。

使用实例变量是不可能的,因为我想为多个对象重用变量Object。 (临时变量)。
使用本地变量会导致保留计数。
并且使用__block CustomType *Object也不起作用,因为无论出于何种原因,Trigger都会在实际调用回调后变为零。

任何想法?

我有一个临时解决方案,但它似乎相当...哈克。

+0

刚指出它,总是使对象小写,并且你在第一行中缺少一个指针。 – NSAddict

+0

@NSAddict感谢您的指针,我解决了这个问题。关于小写......为什么?你看,我已经用C++“长大”了,因此赞成CamelCase符号。 (带大写字母的大写字母) – ATaylor

+1

这是大多数编程语言的标准。类>从大写字母开始,变量>从小写字母开始,它更具可读性,因为您可以调用类和对象的方法。 – NSAddict

回答

1

如前所述,这个答案是相当哈克,我会很高兴,如果有人能在一个更好的方向指向我。
很显然,一个原始数据类型与__block变量结合起来,虽然这有点复杂。

void *Ptr;    //Variable for Block. 
__block CustomType *Obj; //Function variable, mutable by block. 
BOOL (^doAverage)(void *, int, int) = ^(void *Trigger, int Total, int Pulse) { 
    CustomType *T = (CustomType *)Trigger; //Conversion 
    //Calculate Average from Total and Pulse 
    Total /= Pulse; 
    [T setValue:Total]; 
}; 

//Convenience method. 
CustomObject *(^Add)(CustomObject *) = ^(CustomObject *)NewObject { 
    [Array addObject:NewObject]; 
    Obj = NewObject; //Assigns to the local block-Variable. 
    return Obj; 
}; 

Ptr = Add([CustomObject CreateObject]); //Creates the Object, and adds it to the array. 
[Obj addCallback:^{ return doAverage(Ptr, 56, 32); }]; 

由于Ptr是原始类型,它不会被保留,也不必被释放。同时,它假设对象的地址,从而加倍。

一旦对象被释放,带指针的块也是一切都很好。 一旦块被调用,指针需要被转换为所讨论的类型,但这只是一个小问题。

Add是可选的,当然,但我不喜欢的语法Ptr = Obj = [CustomObject CreateObject];

+0

这甚至不是有效的代码。 'Add'块有返回类型,但是在主体中没有返回 – newacct

+0

@newacct我请求你的原谅。我一定在复制代码时忘记了返回语句。 – ATaylor

-3

尝试宣告对象为

__weak CustomType *Object 
+2

XCode引发了一个警告:'不能在自动变量上指定__weak属性。 – ATaylor

+0

这会在分配对象后尽快释放该对象。 或者因为它是一个自动释放对象,只要它已被自动释放。 – NSAddict

0

如果您的部署目标是至少的iOS 5(或OS X 10.7),你可以使用“归零弱引用”:

CustomType *object = [CustomType makeObject]; 
__weak CustomType *weakObject = object; 
[object addCallback:^{ 
    CustomType *strongObject = weakObject; 
    if (strongObject) 
     return doAverage(weakObject, 56, 32); 
    else 
     return 0; 
}]; 

(我已经使用了makeObject代替CreateObject的“工厂法”的名字,因为在他们的名字“创造”的方法有望重返一(+1)保留计数的对象,而不是一个自动释放对象)

__weak引用不会增加保留计数,因此不会创建保留周期。如果object由于最后一次强参考消失而被破坏,则weakSelf设置为nil。在块内创建一个强引用,该引用或者指向该对象,如果它仍然存在,或者是nil,如果它不再存在。

如果我明白你的代码正确,如果对象已被释放,回调将不会被调用。在这种情况下,一个__unsafe_unretained参考就足够了(这也适用于iOS 4):

CustomType *object = [CustomType makeObject]; 
__unsafe_unretained CustomType *unsafeObject = object; 
[object addCallback:^{ 
    return doAverage(unsafeObject, 56, 32); 
}]; 
+0

假设他正在使用ARC,即 – newacct

+0

@newacct:是的,我假设这一点。 __unsafe_unretained在没有ARC的情况下可用,但可能无助于此。 –

+0

'__unsafe_unretained'不会在MRC下做你想要的。它仍将保留。您需要MRC下的'__block'。 – newacct

1

几件事情。首先,我想看看你的addCallback:方法。您可能错误地实现了它。例如,如果您存储一个块供以后使用,则必须将其复制。如果这是不正确的,所有的投注都在其余的东西上。

而且使用__block CustomType *对象也不管用,因为 不管是什么原因触发最终成为零一旦回调实际上是 调用。

所以,如果它是nil,则意味着您分配给nil某处Object

+0

是的,我注意到'复制'是必要的。这就是为什么'addCallback'创建一个对象(一个容器)用'[Block copy]保存引用'的原因。是的,分配一个“零”值是可能的。然而,我想要的是一个“非保留的对象拷贝”,一旦相应的对象被释放,这个拷贝就会“丢失”。 – ATaylor

+0

@ATaylor:你是否在做循环内部的'addCallback',但是在循环之外声明了__block'变量?如果是这样,那么所有块将引用相同的'__block'变量,如果该变量的值在循环的迭代之间改变,则会导致问题。如果你正在做这样的事情,你可能想把'__block'变量放在循环里面 – newacct

+0

不是,但它是一个类似的行为。我有一个使用相同变量添加到同一个数组的语句列表。虽然这给了我一个想法,即一组'__block'变量可能是解决方案......但是,对于这样一个简单的任务来说,这看起来非常复杂......尽管现在又出现了另一个想法。如果我声明另一个名为'addWithCallback'的块,会发生什么情况,它会同时使用对象和块? – ATaylor

1
CustomType *Object; 
BOOL (^doAverage)(CustomType *, int, int) = ^(CustomType *Trigger, int Total, int Pulse) { 
//Calculate Average from Total and Pulse 
Total /= Pulse; 
[Trigger setValue:Total]; 
}; 

Object = [CustomType CreateObject]; //Autoreleased Object 
[Object addCallback:^{ return doAverage(Object, 56, 32); }]; 

泰勒说 - >“但是什么我要的是有问题,这将是‘丢失’,一旦相应的对象被释放一个‘对象的非保留副本’。”

此代码似乎并不除非你或的addCallback([^ {}副本])内使用拷贝引起保留-cyle; ..

它在哪里完全复制中使用您的码?在addCallback内部?如果这是这样的:

addCallback(o) { 

o = [o copy]; 
o(); 

then do a [o release]; when you done with a block object.. do not release it in dealloc() 
} 

如果你从来没有使用复制的任何地方,没有什么可担心的..这一切都发生在堆栈中的意思是不能保持在个循环所有,除非它是不是一个全球性!

如果有一个零售cyle,不要使用__block __weak等,而不是做释放它是什么对象在块的末尾..并记住,没有副本没有保留周期..

+0

虽然我在'addCallback'中使用'copy',只是因为否则在我使用它之前块会被释放。虽然我猜想'一次性'回调可能会诀窍。 (使用一次,然后释放)。谢谢您的意见。 – ATaylor

+0

所以在你的回调中使用副本是做它的正确形式..复制它,调用它,并在完成后释放块,这将立即释放对象..你在哪里看到该方案中的保留周期不是对我清楚吗?它不是创建保留循环的运行时,而是设计器/编码器。在将其添加到回调并使用dispatch_async(0,{block(); [block release]})后释放“Object”;以查看结果即使工作没有复制它,如果它是一个即时操作(不持久)..保留周期块的最终解决方案是中间obj,thnx – DeniziOS

+0

是的,就是这一点,我没有释放它在使用后,但当我完成了包含回调的对象时,该回调被块保留下来......电脑......只要他们做了我想让他们做的事情,而不是我告诉他们做的事,对吧? :) – ATaylor