我有一个Objective-C对象,我将一个Block传递给它的构造函数。这是一个特殊情况,我想在视图控制器完全加载时触发该块。但是,在那个Block中我还想引用我传递Block的对象。考虑这个例子:
typedef void (^MyBlock)();
//constructor of my object
-(id)initMyObjectWithBlock:(MyBlock)block{
self = [super init];
if(self){
myivar = block; //to be used later
}
}
//somewhere else in my app
MyObject *obj = [[MyObject alloc] initMyObjectWithBlock:^{
[obj doSomething];
}];
在那个[obj doSomething]
行,我得到“当被块捕获时,变量未初始化”警告,这是有道理的。在那个Block中,我需要一个对“父”对象的引用(在这种情况下为obj
)。有没有办法实现这个目标?我确实知道我的具体问题的解决方法和模式,但我想知道这样的引用是否可行。
答案 0 :(得分:3)
typedef void (^MyBlock)(MyObject*);
//constructor of my object
-(id)initMyObjectWithBlock:(MyBlock)block{
self = [super init];
if(self){
myivar = block;
}
}
//somewhere else in app
MyObject *obj = [[MyObject alloc] initMyObjectWithBlock:^(MyObject* myObj){
[myObj doSomething];
}];
//and somewhere else in app
obj.myivar(obj);
答案 1 :(得分:0)
如果您在创建实例之前将对象设置为nil
,则应该注意您的警告。
__block TestClass *obj = nil;
obj = [[TestClass alloc] initMyObjectWithBlock:^{
[obj doSomething];
}];
关于object,它会退出,因为你没有在initMyObjectWithBlock
初始化程序中调用阻塞。
尽管上面的代码有效,但正如Josh所说,有一个保留周期。要绕过保留周期,您可以执行以下操作:
TestClass *obj = nil;
__block __weak TestClass *objWeak = nil;
obj = [[TestClass alloc] initMyObjectWithBlock:^{
TestClass *newObj = objWeak;
[newObj doSomething];
}];
objWeak = obj;
您只是创建一个虚拟变量以传入您的块。
答案 2 :(得分:0)
这是对Cy-4AH答案的补充。很快就把它写进了评论。
首先:遇到“解决方法”是一种代码气味。可能有两个原因:
一个。 MyObject
是两个不同任务的共生:1。火,当$ $发生时。 2.在解雇时做一些事情。将MyObject
分解为MyObject1
和MyObject2
可能有所帮助。但当然我们需要更多信息。
B中。通常情况下,这是一个概念的一部分,当一个对象触发时,某些东西应该完全发生在这个对象上。 (获取更多信息,更改状态,......)在这种情况下,模式非常简单:将self
传递给块:
来自Cy-4AH:
typedef void (^MyBlock)(MyObject*);
//constructor of my object
-(id)initMyObjectWithBlock:(MyBlock)block{
self = [super init];
if(self){
myivar = block;
}
return self; // Added this line for obvious reasons
}
//somewhere else in app
MyObject *obj = [[MyObject alloc] initMyObjectWithBlock:^(MyObject* myObj){
[myObj doSomething];
}];
现在有点变化:
在MyObject
内,当它调用块
self.myivar( self );
正如Cy-4AH所说,那么你不需要所有__block
__unsafe_unretained
__weak
垃圾来涵盖概念问题。