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); }];
[Array addObject:Object];       //Adds to collection.

手头的问题是您可能已经想到的保留周期。
Object保留对 in块的引用addCallback,并且块doAverage保留对 的引用Object

使用实例变量是不可能的,因为我想Object为多个对象重用该变量。(临时变量)。
使用局部变量会导致保留计数。
并且 using__block CustomType *Object也不起作用,因为无论出于何种原因Trigger,一旦实际调用回调,最终结果为 nil 。

有任何想法吗?

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

4

5 回答 5

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([^{}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()
} 

如果您从未在任何地方使用过副本,则无需担心。这一切都发生在堆栈中,这意味着根本没有保留周期,除非它不是全局的!

如果有零售周期,请不要使用 __block __weak 等,而是释放块末尾的任何对象..并记住没有复制没有保留周期..

于 2013-01-14T05:18:17.473 回答
1

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

并且使用 __block CustomType *Object 也不起作用,因为无论出于何种原因,一旦实际调用回调,Trigger 就会以 nil 结束。

因此,如果它是nil,那么这意味着您分配nilObject某个地方。

于 2012-12-22T00:57:14.627 回答
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];

于 2012-12-21T12:01:15.843 回答
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;
}];

(我使用 amakeObject而不是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);
}];
于 2012-12-21T12:54:24.400 回答
-3

尝试将对象声明为

__weak CustomType *Object
于 2012-12-21T12:01:05.787 回答