I've asked a similar question before, but this time the situation is a bit different.
For one, this time around I'm using ARC (inviting a whole new world of problems). Second: The code I have basically works, but I'm wondering if I could do with less code.
Right now, my code looks like this:
__weak CustomType *Object;
void (^doAverage)(CustomType *, int, int) = ^(CustomType *Trigger, int Val1, int Val2) {
//Calculations with Trigger
}
CustomType *(^Add)(int, CustomType *) = ^(int Val1, CustomType *NewObject) {
//Checks prerequisites, and returns either the passed object after adding it to
//an array or nil, if the prerequisites haven't been met.
}
Now, further down the line, I'm doing this:
Object = Add(-1, [CustomType makeObjectWithParameters]);
[Object addCallback:^{ doAverage(Object, 56, 57); }];
Inside addCallback
, the passed block with the call to doAverage
is sent a copy
message and saved for later execution.
This works, no retain cycles, the callbacks fold if the object is deallocated.
But it's not 'as elegant' as I'd like.
What I'd like would be something along these lines:
__block __weak CustomType *Object;
CustomType *(^Add)(int, CustomType *) = ^(int Val1, CustomType *NewObject) {
//Checks prerequisites, and returns either the passed object after adding it to
//an array or nil, if the prerequisites haven't been met.
Object = NewObject;
}
And further down the line:
[Add(-1, [CustomType makeObjectWithParameters]) addCallback:^{ doAverage(Object, 56, 57); }];
However if I do it like this, it'll change the Object
passed to the callback to whatever Add
I called last, which isn't what I want.
Basically I'd need to set
the value of Object
in a block and then copy
that reference as a parameter, instead of passing the reference to the variable itself.
Furthermore, as a second step, it'd be about perfect, if I didn't have to pass the parameter Object
in the first place, but could use it in the block.
But if I do that, the variable in the block will default to nil when the block is finally called (well past the expiration of the scope it was defined in).
So instead of:
void (^doAverage)(CustomType *, int, int) = ^(CustomType *Trigger, int Val1, int Val2) {
//Calculations with Trigger
}
I'd like to do use:
void (^doAverage)(int, int) = ^(int Val1, int Val2) {
//Calculations with Object
}
With whatever value Object
(weak reference) had at that moment in time.
Is either of the two somehow possible?
Thank you very much.
Edit:
Following the below suggestion, I refactored my code like this:
typedef BOOL (^stackBlock_t)();
typedef BOOL (^CallBlock_t)(__weak id Object);
-(void) addCallback(CallBlock_t)B {
stackBlock_t stackBlock = ^{
__weak id Object = self;
return B(Object);
};
Callback = [stackBlock copy];
}
I'm trying to call this construct with:
[Add(-1, CustomType makeObjectWithParameters]) addCallBack:^{ doAverage(Object, 56, 57); }];
However Object
isn't defined for the doAverage
block for some reason, and I don't quite know why. After all, it's a block of type CallBlock_t
, which takes a parameter of type id
and the name Object
. Shouldn't it 'know' about the variable Object
then?
Edit 2: After a bit of tinkering around (namely using the actual type and stuff), it now gives me a different error message: Incompatible block pointer types sending 'void (^)(void)' to parameter of type 'CallBlock_t'
, though I'm not. I want that block to return a BOOL
and take the argument Object
...what am I doing wrong?
Edit 3: I may have found it. I was missing something in my addCallback
call.
I have yet to test it, but it would seem, that I'm required to call it like this:
[Add(-1, CustomType makeObjectWithParameters]) addCallBack:^(CustomObject *Object){ doAverage(Object, 56, 57); }];
Thinking about it, it makes sense...it's horrible on the eyes, but it makes sense. And it works like a charm. I don't even need excess variables of type __block
any more.