Similar things have been asked before, but I was unable to solve my current problem with any of these answers.
Situation:
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.
The issue at hand is a retain cycle as you probably already figured.
Object
keeps a reference to the block in addCallback
, and the block doAverage
retains the reference to Object
.
Using an instance variable is out of the question, because I want to reuse the variable Object
for multiple objects. (Temporary variable).
Using a local variable results in the retain count.
And using __block CustomType *Object
doesn't work either, because for whatever reason Trigger
ends up as nil once the callback is actually called.
Any ideas?
I have a makeshift solution, but it seems rather...hacky.
As already stated, this answer is rather hacky and I'd be very happy if someone could point me in a better direction.
Apparently a primitive datatype in combination with a __block
variable does the trick, though this is a bit complicated.
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); }];
Since Ptr
is a primitive type, it will NOT be retained and does not have to be released. At the same time, it assumes the address of the Object in question and thereby doubles as it.
Once the object is released, so is the block with the pointer and everything is good. Once the block is called, the pointer needs to be cast to the type in question, but that's only a minor problem.
Add
is optional of course, but I don't like the syntax Ptr = Obj = [CustomObject CreateObject];