【发布时间】:2013-11-05 20:23:57
【问题描述】:
我发现某些 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: strong> 方法并为您计划在对象中实现的所有消息返回 TRUE。
【问题讨论】:
-
另外,您不应该将答案放在问题中。如果您想回答自己的问题,请添加答案。
标签: ios objective-c cocoa