0

我正在通过对过去编写的代码进行现代化改造来设计一个新的应用程序。这个旧代码使用类/委托模型,我试图将它们转换为使用块作为回调,而不是委托的东西。

我所做的是创建一个像

@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.

这可能吗?

4

2 回答 2

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(); }

无论您在哪里运行该块。

于 2013-09-22T17:03:06.200 回答
1

首先,我强烈建议定义类型来表示您的块- 使它们更容易使用,尤其是在您需要重构参数时。

您无法编写区分“我将此属性设置为 nil”或“运行时将此属性初始化为 nil”的代码,至少在没有一些疯狂的运行时代码来检查堆栈时不能。我能想到的唯一选择是使用空对象模式。在我详细说明之前,请记住,我实际上并没有尝试对此进行测试,但它应该可以工作。定义一个表示“没有价值”的块,并将您的属性设置为在初始化时指向该块。然后,您可以NullBlock在运行时进行比较,以确定是否有人将属性显式设置为 nil(因为此时它将为 nil)或给它一个真正的非 nil 值。

或者,如果您不介意手动编写 set 访问器,则可以使用 BOOL 来跟踪是否有人明确设置了属性。然后,当您调用该块时,只需检查是否有人实际设置了该值。

@synthesize onTouchBlock=_onTouchBlock;
MyBlock _onTouchBlock;
BOOL _onTouchBlockWasSet;

- (void)setOnTouchBlock:(MyBlock)block {
 _onTouchBlockWasSet = YES;
 _onTouchBlock = block;
}

我不建议在初始化程序中传递值,因为这使它与该对象类型的创建相关联。如果您想根据某些条件更改代码中的块,您将回到原点。此外,它还会阻止您使用创建该对象的情节提要。

于 2013-09-22T17:27:11.510 回答