选择器和PerformSelector



我有一个包含多个部分的UITableView。每个部分都包含一组不同的数据:电话号码、地址。。。。

对于每一套,我都有一个模型:电话号码,地址。它们完全不同,但有一些共同的方法。

在我的UITableView中,我有一个包含以下模型/类名的数组:

NSMutableArray*classNames;

在我的UITableViewviewDidLoad中,我对所有这些部分进行了一些初始化:

//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并没有指向你认为的对象。

最新更新