我发现当一个对象没有明确地处理它们时,一些 Obj-C 消息没有得到正确转发。
这是一个例子:
创建一个新的 UITableView,如:
UITableView *v ? [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 0, 0) style:UITableViewStylePlain];
然后使用以下方法创建一个 NSObject 的实例:
(A) - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(@"tableView:numberOfRowsInSection:");
return 1;
}
(B) - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"tableView:cellForRowAtIndexPath:");
return nil;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSLog(@"methodSignatureForSelector: %@", NSStringFromSelector(aSelector));
return [NSMethodSignature signatureWithObjCTypes:"@@:@"];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
NSLog(@"forwardInvocation: %@", NSStringFromSelector(anInvocation.selector));
}
让我们将此对象称为 ds 并将其设置为表格视图的数据源:
v.dataSource = ds;
当您运行代码时,您应该看到方法 (A) 和 (B) 都被表视图以预期的顺序调用:
LOG: tableView:numberOfRowsInSection:
LOG: tableView:cellForRowAtIndexPath:
现在它会变得有趣,尝试删除(或只是更改名称)方法(A),你应该得到:
LOG: methodSignatureForSelector: tableView:numberOfRowsInSection:
LOG: forwardInvocation: tableView:numberOfRowsInSection:
这很好,因为表视图尝试调用tableView:numberOfRowsInSection:并且由于该方法不存在,消息被转发到forwardInvocation:
显然,这是所有引用未在对象中定义的方法的消息的默认行为。
但是尝试恢复(A)方法并删除(B),你应该得到:
LOG: tableView:numberOfRowsInSection:
...和一个错误告诉你tableView:cellForRowAtIndexPath:被调用但没有返回一个单元格。
由于某种原因tableView:cellForRowAtIndexPath:被调用(或不被调用)但没有遵循预期的forwardInvocation:路径。
这是一个错误吗?
难道我做错了什么?
是否有一些明确不转发的消息?
即使respondsToSelector:应该向这两个函数返回 FALSE,但在实现中的某处将cellForRowAtIndexPath:的消息发送到其他对象并破坏默认的预期行为......
我学到的基本上是:
如果您计划响应对象中的消息,即使通过forwardInvocation:的某些实现,您也应该始终重载respondsToSelector:方法并为您计划在对象中实现的所有消息返回 TRUE。