之前已经提出了类似的问题,但我无法用这些答案来解决我当前的问题。
情况:
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
在实际调用回调后最终为nil。
有什么想法吗?
我有一个临时解决方案,但它似乎相当...... hacky。
答案 0 :(得分: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];
答案 1 :(得分:1)
有几件事。首先,我想看看你的addCallback:
方法。你可能错误地实现了它。例如,如果存储块以供以后使用,则必须复制它。如果不正确,所有投注都将被取消。
使用__block CustomType * Object也不起作用,因为 无论什么原因,一旦实际回调,Trigger最终为nil 调用。
因此,如果它是nil
,则表示您已将nil
分配给Object
某处。
答案 2 :(得分: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); }];
泰勒说 - > “但我想要的是对象的'未保留副本',一旦相应的对象被解除分配,它将被'丢失'。”
此代码似乎不会导致retain-cyle,除非您在addCallback([^ {} copy])上使用copy; ...
您的代码中使用的副本到底在哪里?在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()
}
如果你从来没有在任何地方使用过拷贝,没什么可担心的。这一切都发生在堆栈中,这意味着根本不会保留cyles,除非它不是全局的!
如果有零售商,请不要使用__block __weak等来代替它在块的末尾释放任何对象..并记住没有副本没有保留周期..
答案 3 :(得分: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
作为“工厂方法”的名称,因为名称中带有“create”的方法应返回(+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);
}];
答案 4 :(得分:-3)
尝试将对象声明为
__weak CustomType *Object