1

我以前也问过类似的问题,但这次情况有点不同。

一方面,这一次我使用了 ARC(引发了一个全新的问题世界)。第二:我的代码基本上可以工作,但我想知道我是否可以用更少的代码来做。

现在,我的代码如下所示:

__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.
}

现在,更进一步,我正在这样做:

Object = Add(-1, [CustomType makeObjectWithParameters]);
[Object addCallback:^{ doAverage(Object, 56, 57); }];

在内部addCallback,带有调用的传递块doAverage被发送一条copy消息并保存以供以后执行。

这有效,没有保留周期,如果对象被释放,回调折叠。

但这并不像我想要的那样“优雅”。

我想要的是这些方面的东西:

__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;
}

更进一步:

[Add(-1, [CustomType makeObjectWithParameters]) addCallback:^{ doAverage(Object, 56, 57); }];

但是,如果我这样做,它会将Object传递给回调的内容更改为Add我最后调用的任何内容,这不是我想要的。

基本上我需要一个块中set的值,Object然后copy将该引用作为参数,而不是将引用传递给变量本身。

此外,作为第二步,如果我不必首先传递参数Object,但可以在块中使用它,那将是完美的。但是如果我这样做,当块最终被调用时,块中的变量将默认为 nil(远远超过它定义的范围的到期)。

所以而不是:

void (^doAverage)(CustomType *, int, int) = ^(CustomType *Trigger, int Val1, int Val2) {
    //Calculations with Trigger
}

我想使用:

void (^doAverage)(int, int) = ^(int Val1, int Val2) {
    //Calculations with Object
}

Object无论当时的价值(弱参考)有什么价值。

两者中的任何一个都有可能吗?

非常感谢。

编辑:

按照以下建议,我重构了我的代码,如下所示:

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];
}

我试图用以下方式调用这个构造:

[Add(-1, CustomType makeObjectWithParameters]) addCallBack:^{ doAverage(Object, 56, 57); }];

但是由于某种原因Object没有为块定义doAverage,我不太清楚为什么。毕竟,它是一个 type 块CallBlock_t,它接受一个 type 参数id和 name Object。那么它不应该“知道”变量Object吗?

编辑2:经过一番修改(即使用实际类型和东西),它现在给了我一个不同的错误消息:Incompatible block pointer types sending 'void (^)(void)' to parameter of type 'CallBlock_t'虽然我不是。我希望该块返回 aBOOL并接受参数Object......我做错了什么?

编辑3:我可能已经找到了。我在addCallback通话中遗漏了一些东西。我还没有测试它,但似乎我需要这样称呼它:

[Add(-1, CustomType makeObjectWithParameters]) addCallBack:^(CustomObject *Object){ doAverage(Object, 56, 57); }];

仔细想想,说的有道理……看的眼花缭乱,但说的有道理。它就像一个魅力。我什至不再需要多余的类型变量__block

4

2 回答 2

1

该块只是捕获对存储位置的引用(强或弱),因此它的实例计数和生命周期与该存储位置相关(除了第一次复制块时堆栈指针被堆分配的魔法酱,并且参考更新)。

所以知道了这一点,为什么 Object 总是相同的值应该是相当明显的;所有复制的块都指向相同的捕获位置,就像您使用堆栈分配的值在单个函数中完成所有这些一样。

在 addCallback 中,您可以这样做:

- (void)addCallback:(void^(CustomType*))action {
   void(^stackBlock)(void) = ^{
      __weak CustomType *localObj = Object;
      action(localObj);
   };
   self.callback = [stackBlock copy];
}

这将导致它捕获调用 addCallback 时的任何当前值,这应该与您要求的第一部分匹配。

考虑到一切的设置方式,我认为第二部分是不可能的。只有 addCallback 捕获 Object 的时间点值,并且不使用参数它无法将它传递给 doAverage 因为它甚至不知道它正在调用什么函数。不幸的是,没有一种干净、简单的方法来进行动态块调度,否则您可以让 addCallback 获取一个块和一个可变参数列表,然后使用对象和提供的参数调用该块。

于 2013-06-24T05:15:17.313 回答
0

“可以保存作用于单独局部变量的代码的东西”看起来像一个类的实例

于 2013-12-02T11:51:46.153 回答