我正在通过现代化我过去编写的代码来设计一个新的应用程序。这个旧代码使用类/委托模型,我试图将它们转换为使用块作为回调,而不是委托的东西。
我所做的就是创建一个像
这样的属性@property (nonatomic, copy) void (^onTouch)(NSInteger index);
那将使用该类传递给对象一个可以插入代码的块,在这种情况下可以触摸执行。
但我的问题是这个。当您使用委托并且您在委托协议上有方法时,如果您使用该类并且忘记实现委托协议,Xcode将发出警告。这是用块做到这一点的方法吗?或者换句话说:如果调用者没有定义回调块,有没有办法让Xcode抱怨?
我的意思是这是正确的:
MyClass *obj = [[MyClass alloc] init];
obj.onTouch = ^(NSInteger *index){ //call back code to be executed };
这也没关系
MyClass *obj = [[MyClass alloc] init];
obj.onTouch = nil;
但这会生成一条消息
MyClass *obj = [[MyClass alloc] init];
// no callback block defined.
这可能吗?
答案 0 :(得分:2)
如果要强制设置某个参数,我会将其包含在初始值设定项中。
MyClass *obj = [[MyClass alloc] initWithBlock:^(NSInteger *index) { /* code*/ }];
然后,在MyClass
:
- (id)init {
// This will result in a runtime error if you use the wrong initializer.
NSAssert(NO, @"Use initWithBlock instead.");
}
- (id)initWithBlock(initWithBlock:^(NSInteger *)block) {
self = [super init];
if (self) {
self.onTouch = block;
}
return self;
}
另请注意,尝试执行NULL
阻止会导致崩溃,因此请务必执行以下操作:
if (self.onTouch) { self.onTouch(); }
无论你在哪里跑步。
答案 1 :(得分:1)
首先,我强烈推荐defining types to represent your blocks - 使它们更容易使用,特别是如果你需要重构参数。
你不能编写区分“我将此属性设置为nil”或“运行时将此属性初始化为nil”的代码,至少在没有一些疯狂的运行时代码来检查堆栈的情况下。我能想到的唯一选择就是使用null object pattern。在我详细说明之前,请记住我实际上并没有尝试过测试,但它应该可行。定义一个意味着“没有值”的块,并将您的属性设置为指向init上的该块。然后,您可以在运行时与NullBlock
进行比较,以确定是否有人将该属性显式设置为nil(因为此时它将为零)或者给它一个真正的非零值。
或者,如果您不介意手动编写set访问器,则可以使用BOOL跟踪是否有人明确设置了该属性。然后当你调用块时,只检查是否有人实际设置了值。
@synthesize onTouchBlock=_onTouchBlock;
MyBlock _onTouchBlock;
BOOL _onTouchBlockWasSet;
- (void)setOnTouchBlock:(MyBlock)block {
_onTouchBlockWasSet = YES;
_onTouchBlock = block;
}
我不建议在初始值设定项中传递值,因为这会使其与该对象类型的创建联系起来。如果你想根据某些条件在代码中更改块,你将回到原点。此外,它会阻止您使用创建该对象的故事板。