Ios 选择器和性能选择器
我有一个带有几个部分的Ios 选择器和性能选择器,ios,uitableview,selector,Ios,Uitableview,Selector,我有一个带有几个部分的UITableView。每个部分包含一组不同的数据:电话号码、地址 对于每一组,我都有一个模型:电话号码、地址。它们完全不同,但有一些共同的方法 在我的UITableView中,我有一个数组,其中包含这些模型/类名: NSMutableArray*类名 在我的UITableView的viewDidLoad中,我对所有这些部分进行了一些初始化: //section 1: PhoneNumbers phoneNumbers = [PhoneNumbers getAllIDs];
UITableView
。每个部分包含一组不同的数据:电话号码、地址
对于每一组,我都有一个模型:电话号码、地址。它们完全不同,但有一些共同的方法
在我的UITableView
中,我有一个数组,其中包含这些模型/类名:
NSMutableArray*类名
在我的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: .....
到目前为止,初始化还没有问题。这看起来不错,效果也不错
随后,在我的cellforrowatinexpath
中,我将通过这些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]];
到目前为止,我成功地抽象了所有内容,cellforrowatinexpath
不需要知道内容来自何处,只要这些类响应检索标签数据的方法(在上面的完整描述中)
现在我需要一个动作按钮在每个单元格中执行某种动作
为了确保我理解选择器和performSelection的概念,我在TableView类中使用了quick and dirty:
- (void) buttonTarget {
NSLog (@"yes");
}
在我的cellforrowatinexpath
方法中,创建了一个具有以下目标的按钮:
button addTarget:self action:@selector(buttonTarget) forControlEvents:UIControlEventTouchUpInside];
好的,到目前为止一切都很好,一切正常。但这不是我真正想要的。该操作不应在此处执行,而应在实际类(PhoneNumber、Address,…)中执行
为了保持整洁,我制作了一个模型动作,包含按钮图标、说明和选择器:
@interface Action : NSObject
@property (nonatomic, strong) NSString *description;
@property (nonatomic, strong) UIImage *icon;
@property (nonatomic ) SEL selector;
@end
Action *phoneAction = [[Action alloc] init];
phoneAction.description = NSLocalizedString(@"Call", @"Call button description");
phoneAction.icon = [UIImage imageNamed:@"phone"];
phoneAction.selector = @selector(callPhone);
在my PhoneNumber类(和类似类)中,操作设置为正确的选择器:
@interface Action : NSObject
@property (nonatomic, strong) NSString *description;
@property (nonatomic, strong) UIImage *icon;
@property (nonatomic ) SEL selector;
@end
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[27242:907]*终止应用程序
由于未捕获的异常“NSInvalidArgumentException”,原因:
'-[UIDeviceWhiteColor callPhone]:无法识别的选择器已发送到
实例0x874af90'
在无法识别的选择器错误中,您将消息发送到名为UIDeviceWhiteColor的对象。该类是否有一个名为callPhone的方法?在我看来,displayedRecord并没有指向你认为它是的对象。听起来你有一个僵尸。当您将一个操作发送到一个毫无意义的对象时,通常意味着您的对象在您向其发送消息之前被解除分配 在您的例子中,您正在添加“displayedRecord”作为按钮的目标 为了使其工作,您需要在button对象的生命周期内保持对displayedRecord调用的强引用。什么拥有您的displayedRecord对象
如果您无法通过查看代码来调试此问题,您可以使用zombies工具来尝试解决。我的代码中没有UIDeviceWhiteColor类。My PhoneNumber类确实有一个callPhone类。堆栈跟踪告诉您正在调用的对象UIDeviceWhiteColor(一个Apple SDK私有类)正在接收您的消息。也就是说,出于某种原因,您的变量displayedRecord指向了那个。我猜你在某个地方意外地分配了它。设置一些断点并检查它的类类型,正如另一位绅士指出的那样,你可能有一个僵尸。进入调试设置并启用僵尸可能会有所帮助。这可能是正确的答案!!“displayedRecord”是在cellForRowAtIndexPath中定义的(如我的问题中所述)。但由于它是一个局部变量,它可能不够强。我如何做到这一点?是只有一个displayedRecord对象,还是为每个单元格创建一个?如果只有一个,则将其作为视图控制器的属性。如果每个单元格都有不同的子类,请使用属性(类型id)创建UITableViewCell的自定义子类,以保存该单元格的displayedDataClass对象。非常感谢Duncan。这才是真正的解决办法。我知道我们有一个很好的实现,其中功能被抽象并放在它所属的地方!我已经为我的UITableViewCell创建了一个自定义类,因此添加该属性很容易(起初它不起作用,但我忘了将自定义UITableViewCell中的实例变量设置为strong!)