2014-10-20 2 views
23

У меня есть следующиеКак ссылаться контроллер из класса UITableViewCell в Swift

  1. ViewController
  2. Tableview
  3. CustomCell

Я использовал СИБ (файл .xib) для ячейка, которая использует класс CustomCell. Этот пользовательский класс ячейки обрабатывает IBAction для некоторого касания кнопки ячейки. Я хотел бы ссылаться на ViewController и некоторые его переменные внутри него. Как я должен это делать (доступ к ViewController)?

Спасибо!

ответ

31

Я бы не создавал такую ​​зависимость между ячейкой и контроллером представления, что делает архитектуру более сложной, а ячейка не может использоваться повторно.

Я предлагаю вам использовать шаблон делегирования, который может звучать немного сложнее - хотя вы уже используете (UITableViewDelegate является типичным примером):

  • создать протокол MyCellProtocol с одним методом didTapCell, принимая UITableViewCell и/или некоторые пользовательские данные, которые вы хотите передать в контроллер просмотра
  • создать свойство общественного делегата в пользовательской ячейке: var cellDelegate: MyCellProtocol?
  • в didTapXXX обработчиком или didSelectRowAtIndexPath вашей клетки, вызовите self.cellDelegate?.didTapCell(), передавая ожидаемые параметры
  • в контроллере представления, реализовать MyCellProtocol
  • в cellForRowAtIndexPath вашего контроллера представления, при создании/извлечение из ячейки, установите его свойство cellDelegate к self

В этот момент, когда в вашей ячейке делается кратковременное нажатие, вызывается метод контроллера вида, и оттуда вы можете делать все, что вам нужно.

Ключевым моментом является то, что вместо того, чтобы манипулировать ячейкой кран/выборка соты, уведомить диспетчер представлений и позволить ему выполнять работу.

+0

. Вторая пуля выше для Objective-C. Быстро это можно сделать: позвольте делегировать: ClasThatImplementsProtocol – zeeple

+0

спасибо @ user1639164, код исправлен – Antonio

+1

Это может сработать. Но при инкапсуляции источника данных в другой класс, как и следовало (не вставляйте DS в контроллер), вам нужно найти другой способ подключения ячеек и контроллера. Одна вещь, которую вы могли бы сделать, - использовать метод делегата tableView, чтобы DisisplayCell назначил tableview в качестве делегата для ячейки. Затем вам необходимо отключить их в prepareForReuse и dealloc или deinit в зависимости от того, какой язык вы используете. Уведомления также не идеальное решение, если несколько активных контроллеров, которые прослушивают одно и то же уведомление. –

7

Я не думаю, что вы должны это сделать, и, вероятно, вы делаете что-то не так, но если вы действительно действительно нуждаетесь в этом, просто получите свойство в своем классе CustomCell.

var viewController : UIViewController 

тогда, когда вы создаете ячейку в cellForRowAtIndexPath установить свойство

cell.viewController = self 

после этого вы можете легко получить доступ к контроллеру вид из кода клетки:

self.viewController.doSomething() 

Но опять же, на мой взгляд, вы должны перепроектировать свой код. Ячейка не должна заботиться о контроллере. Он должен заботиться только о том, чтобы отображать себя и ничего больше

+0

> «Клетка не должна заботиться о контроллере. Он должен заботиться только об отображении себя и больше ничего» Означает ли это, что это также плохая практика, чтобы добавить кнопки в пользовательской ячейке, если действие этой кнопки будет для доступа или изменения какого-либо свойства модели? Потому что в этом случае модель может получить доступ только от контроллера, так как она является источником представления таблицы ... –

+3

это не конечно. плохая практика заключалась бы в том, чтобы иметь код, который обрабатывает много элементов модели в действии кнопки. хорошей практикой в ​​этом случае является наличие только одной строки кода в действии кнопки. строка должна опубликовать уведомление или вызвать метод делегата. а затем контроллер должен реагировать на этот вызов или это уведомление и запускать весь необходимый код. контроллер, а не ячейка. я надеюсь, вы понимаете, что я говорю о –

+2

в большинстве интерфейсов пользовательского интерфейса, очень распространенных для доступа к контейнеру объекта, например, в ActionScript вы можете вызвать родителя с помощью этого.parent, и по моему опыту на Apple, Apple кажется Apple недостаточно опыт с визуальным языком программирования, поэтому я думаю, что это решение очень приемлемо и умно, и я дам ему +1 –

0

Читать другие комментарии по поводу действительно хочет использовать альтернативный подход, прежде чем пытаться это, но используя это расширение позволит вам добраться до dataSource и delegate оба из которых должны быть UITableViewController

extension UITableViewCell { 
    var tableView:UITableView? { 
     get { 
      for var view = self.superview ; view != nil ; view = view!.superview { 
       if view! is UITableView { 
        return (view! as UITableView) 
       } 
      } 
      return nil 
     } 
    } 

    var tableViewDataSource:UITableViewDataSource? { 
     get { 
      return self.tableView?.dataSource 
     } 
    } 

    var tableViewDelegate:UITableViewDelegate? { 
     get { 
      return self.tableView?.delegate 
     } 
    } 
} 
11
extension UIView { 
    var parentViewController: UIViewController? { 
     var parentResponder: UIResponder? = self 
     while parentResponder != nil { 
      parentResponder = parentResponder!.nextResponder() 
      if let viewController = parentResponder as? UIViewController { 
       return viewController 
      } 
     } 
     return nil 
    } 
} 

В вашей ячейке

if let myViewController = parentViewController as? MyViewController { 
    print(myViewController.title) 
} 
+0

Я хотел выполнить segue из uicollectionviewcell, вложенного внутри uitableviewcell, и это сработало отлично! , Благодарю. – webjunkie

+0

Работает в шаблоне проекта мастера. Спасибо. –

+1

в Swift 4, '.nextResponder()' изменен на '.next' – troligtvis

1

Лучший способ - реализовать делегирование. Ваш делегат сообщит контроллеру просмотра о нажатии кнопки. И, в свою очередь, ваш контроллер просмотра (который соответствует протоколу для вышеуказанного делегата) будет обрабатывать задачу, которую вы хотите выполнить при событии клика. (Учебники по шаблонам делегаций доступны в Интернете, вы можете пройти через них, если хотите знать, как делать делегирование).

Смежные вопросы