Как получить UITableViewCell из одного из его подзонов
У меня есть UITableView
с UITextField
в каждом из UITableViewCells
. У меня есть метод в моем ViewController, который обрабатывает событие "Did End On Exit" для текстового поля каждой ячейки, и то, что я хочу сделать, - это обновить мои данные модели новым текстом.
В настоящее время у меня есть:
- (IBAction)itemFinishedEditing:(id)sender {
[sender resignFirstResponder];
UITextField *field = sender;
UITableViewCell *cell = (UITableViewCell *) field.superview.superview.superview;
NSIndexPath *indexPath = [_tableView indexPathForCell:cell];
_list.items[indexPath.row] = field.text;
}
Конечно, работает field.superview.superview.superview
, но это просто кажется таким взломанным. Есть ли более элегантный способ? Если я установил тег UITextField
в indexPath.row
ячейки, в которой он находится в cellForRowAtIndexPath
, этот тег всегда будет правильным даже после вставки и удаления строк?
Для тех, кто уделяет пристальное внимание, вы можете подумать, что у меня есть один .superview
слишком много, а для iOS6 вы были бы правы. Тем не менее, в iOS7 есть дополнительный вид (NDA предотвращает разработку формы) в иерархии между представлением содержимого ячейки и самой ячейкой. Это точно иллюстрирует, почему выполнение элемента супервизора немного хакерское, поскольку оно зависит от того, как реализовано UITableViewCell
, и может ломаться с обновлениями ОС.
Ответы
Ответ 1
Поскольку ваша цель - получить индексный путь для текстового поля, вы можете сделать это:
- (IBAction)itemFinishedEditing:(UITextField *)field {
[field resignFirstResponder];
CGPoint pointInTable = [field convertPoint:field.bounds.origin toView:_tableView];
NSIndexPath *indexPath = [_tableView indexPathForRowAtPoint:pointInTable];
_list.items[indexPath.row] = field.text;
}
Ответ 2
Один из лучших способов сделать это - перебирать иерархию представлений, проверяя каждый супервизор, если он UITableViewCell
, используя метод class
. Таким образом, вы не ограничены количеством наблюдений между вашим UITextField
и ячейкой.
Что-то по строкам:
UIView *view = field;
while (view && ![view isKindOfClass:[UITableViewCell class]]){
view = view.superview;
}
Ответ 3
Вы можете прикрепить UITableViewCell
себя как слабую связь с UITextField
, а затем вырвать ее в методе UITextFieldDelegate
.
const char kTableViewCellAssociatedObjectKey;
В подклассе UITableViewCell:
- (void)awakeFromNib {
[super awakeFromNib];
objc_setAssociatedObject(textField, &kTableViewCellAssociatedObjectKey, OBJC_ASSOCIATION_ASSIGN);
}
В вашем методе UITextFieldDelegate:
UITableViewCell *cell = objc_getAssociatedObject(textField, &kTableViewCellAssociatedObjectKey);
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
//...
Я также рекомендую повторно ассоциировать каждый раз, когда ячейка удаляется из UITableView, чтобы гарантировать, что текстовое поле связано с правильной ячейкой.
Ответ 4
В основном в этом случае я бы предпочел, чтобы вы поместили метод IBAction в ячейку вместо контроллера. И затем, когда действие инициируется, ячейка отправляет делегат в экземпляр контроллера вида.
Вот пример:
@protocol MyCellDelegate;
@interface MyCell : UITableViewCell
@property (nonatomic, weak) id<MyCellDelegate> delegate;
@end
@protocol MyCellDelegate <NSObject>
- (void)tableViewCell:(MyCell *)cell textFieldDidFinishEditingWithText:(NSString *)text;
@end
В реализации ячейки:
- (IBAction)itemFinishedEditing:(UITextField *)sender
{
// You may check respondToSelector first
[self.delegate tableViewCell:self textFieldDidFinishEditingWithText:sender.text];
}
Итак, теперь клетка передаст себя и текст через метод делегата.
Предположим, что контроллер представления задал делегат ячейки для себя. Теперь контроллер представления реализует метод делегата.
В реализации вашего контроллера вида:
- (void)tableViewCell:(MyCell *)cell textFieldDidFinishEditingWithText:(NSString *)text
{
NSIndexPath *indexPath = [_tableView indexPathForCell:cell];
_list.items[indexPath.row] = text;
}
Этот подход также будет работать независимо от того, как Apple изменит иерархию представлений ячейки таблицы.