Имам UITableView
с няколко секции. Всеки раздел съдържа различен набор от данни: телефонни номера, адреси....
За всеки от тези комплекти имам модел: телефонен номер, адрес. Те са напълно различни, но имат някои общи методи.
В моя UITableView
имам масив, съдържащ тези модели/имена на класове:
NSMutableArray *classNames;
В viewDidLoad
на моя UITableView
правя някои инициализации за всички тези секции:
//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
извличам действителните данни чрез тези идентификатори
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
не трябва да знае откъде идват нещата, стига тези класове да отговарят на методите за извличане на данните за етикетите (в случая по-горе fullDesciption)
Сега имам нужда от actionButton във всяка клетка, изпълняваща някакво действие. За да съм сигурен, че разбирам концепцията за селектори и performSelection, просто направих бързо и мръсно в действие в моя клас TableView:
- (void) buttonTarget {
NSLog (@"yes");
}
И в моя cellForRowAtIndexPath
метод създадох бутон със следната цел:
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
В моя клас 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[27242:907] * Прекратяване на приложението поради неуловено изключение „NSInvalidArgumentException“, причина: „-[ UIDeviceWhiteColor callPhone]: неразпознат селектор, изпратен до екземпляр 0x874af90'