我有一个包含多个部分的UITableView
。每个部分都包含一组不同的数据:电话号码、地址。。。。
对于每一套,我都有一个模型:电话号码,地址。它们完全不同,但有一些共同的方法。
在我的UITableView
中,我有一个包含以下模型/类名的数组:
NSMutableArray*classNames;
在我的UITableView
的viewDidLoad
中,我对所有这些部分进行了一些初始化:
//section 1: PhoneNumbers
phoneNumbers = [PhoneNumbers getAllIDs];
if (phoneNumbers && (phoneNumbers.count >0)) {
[classNames addObject:@"PhoneNumber"];
[dataIDs addObject:phoneNumbers];
}
我对所有其他部分/型号再次这样做:
//section 2: Addresses
addresses = [Address getAllIDs];
if (addresses && (addresses.count >0)) {
[classNames addObject:@"Address"];
[dataIDs addObject:addresses];
}
// section 3: .....
到目前为止,初始化还可以。这看起来不错,效果也不错。
然后,在我的cellForRowAtIndexPath
中,我将通过这些ID的检索实际数据
NSInteger section = [indexPath section];
NSInteger row = [indexPath row];
NSArray *rows = [dataIDs objectAtIndex:section];
NSNumber *recordID = [rows objectAtIndex:row];
然后我计算出我们必须在什么类中获取实际数据:
Class displayedDataClass = NSClassFromString ([classNames objectAtIndex:section]);
并获取数据以填充单元格。
id displayedRecord = [[displayedDataClass alloc] init];
[displayedRecord getByID:recordID];
然后我可以使用在我的手机中设置标签
[cell.someLabel setText:[displayRecord fullDesciption]];
到目前为止,一切都很好,我成功地抽象了所有东西,cellForRowAtIndexPath
不需要知道东西从哪里来,只要这些类响应于检索标签数据的方法(在上面的例子中是fullDescription)
现在我需要在每个单元格中都有一个actionButton来执行某种操作为了确保我理解选择器和性能选择的概念,我只是在我的TableView类中快速而肮脏地进行了操作:
- (void) buttonTarget {
NSLog (@"yes");
}
在我的cellForRowAtIndexPath
方法中创建了一个具有以下目标的按钮:
button addTarget:self action:@selector(buttonTarget) forControlEvents:UIControlEventTouchUpInside];
好的,到目前为止还不错,一切都如预期。但这不是我真正想要的。操作不应该在这里执行,而是在实际的类(电话号码、地址…)中执行
为了保持干净,我制作了一个Action模型,其中包含按钮的图标、描述和选择器:
@interface Action : NSObject
@property (nonatomic, strong) NSString *description;
@property (nonatomic, strong) UIImage *icon;
@property (nonatomic ) SEL selector;
@end
在我的PhoneNumber类(以及类似类)中,操作被设置为正确的选择器:
Action *phoneAction = [[Action alloc] init];
phoneAction.description = NSLocalizedString(@"Call", @"Call button description");
phoneAction.icon = [UIImage imageNamed:@"phone"];
phoneAction.selector = @selector(callPhone);
当然,callPhone是在PhoneNumber类中实现的。
在我的TableView中,我得到了该单元格的操作
action = [displayedRecord action];
然后我试着在我的按钮中使用选择器:
[button addTarget:displayedRecord action:[action selector] forControlEvents:UIControlEventTouchUpInside];
但这里出现了问题:我们从未采用这种方法,我得到了以下错误:
[UIDeviceWhiteColor callPhone]:无法识别的选择器已发送到实例0x874af90 2013-12-29 23:23:03.629 thinx[227242:907]*终止应用程序由于未捕获异常"NSInvalidArgumentException",原因:'-[UIDeviceWhiteColor callPhone]:无法识别的选择器已发送到实例0x874af90'
听起来你有一个僵尸。当你收到一个发送到一个没有意义的对象的操作时,这通常意味着你的对象在你可以向它发送消息之前就被解除分配了
在您的情况下,您将添加"displayedRecord"作为按钮的目标。
为了实现这一点,您需要在按钮对象的生存期内保留对displayedRecord调用的强引用。是什么拥有您显示的Record对象?
如果你不能通过查看代码来调试它,你可以使用僵尸工具来尝试解决它。
在无法识别的选择器错误中,您将消息发送到一个名为UIDeviceWhiteColor的对象。那个类有一个名为callPhone的方法吗?在我看来,displayedRecord并没有指向你认为的对象。