2014-10-20 20 views
23

Ho il seguenteCome riferimento del regolatore da una classe UITableViewCell a Swift

  1. ViewController
  2. tableView
  3. CustomCell

ho usato un NIB (un file .xib) per la cella, che utilizza una classe CustomCell. Questa classe di celle personalizzate gestisce IBAction per un tocco sul pulsante della cella. Mi piacerebbe fare riferimento al ViewController e alcune delle sue variabili al suo interno. Come dovrei farlo (accesso a ViewController)?

Grazie!

risposta

31

Non creerei questo tipo di dipendenza tra la cella e il controller di visualizzazione - ciò rende l'architettura più complessa e la cella non riutilizzabile.

suggerisco di utilizzare il modello di delega, che può sembrare un po 'complicato - anche se si sta già utilizzando (UITableViewDelegate è un tipico esempio):

  • creare un protocollo MyCellProtocol con un metodo didTapCell, accettando un UITableViewCell e/o di alcuni dati personalizzata che si desidera passare al controller della vista
  • creare una proprietà pubblica delegato in cella personalizzato: var cellDelegate: MyCellProtocol?
  • nel gestore didTapXXX o.210 del vostro cellulare, chiamare self.cellDelegate?.didTapCell(), passando i parametri previsti
  • nel vostro controller della vista, l'attuazione del MyCellProtocol
  • in cellForRowAtIndexPath del vostro controller della vista, quando si crea/accodamento cella, impostare la proprietà cellDelegate-self

A questo punto, quando un tocco viene eseguito nella cella, viene chiamato il metodo didTapCell del controller di visualizzazione e da lì è possibile eseguire qualsiasi operazione necessaria.

Il punto chiave è: invece di fare in modo che la cella gestisca il tocco/selezione della cella, avvisare il controller di visualizzazione e lasciare che esegua il lavoro.

+0

Il secondo punto sopra sembra essere per Objective-C. In uno veloce potrebbe fare questo: lasciare delegare: ClasThatImplementsProtocol – zeeple

+0

grazie @ user1639164, codice corretto – Antonio

+1

Questo potrebbe funzionare. Ma quando si incapsula il dataSource in una classe diversa, come si deve (non inserire il DS nel controller), è necessario trovare un modo diverso per connettere celle e controller. Una cosa che potresti fare è usare il metodo dei delegati tableview willDisplayCell per assegnare il tableview come delegato alla cella. È quindi necessario scollegarli in prepareForReuse e dealloc o deinit a seconda della lingua che si sta utilizzando. Anche le notifiche non sono la soluzione ideale se ci sono più controller attivi che ascoltano la stessa notifica. –

7

Non penso che dovresti farlo e probabilmente stai facendo qualcosa di sbagliato ma se ne hai davvero bisogno allora hai solo una proprietà nella tua classe CustomCell.

var viewController : UIViewController 

poi, quando si crea la cella in cellForRowAtIndexPath impostare la proprietà

cell.viewController = self 

dopo che si può facilmente accedere al controller della vista dall'interno della cella codice:

self.viewController.doSomething() 

Ma ancora una volta, a mio parere, dovresti riprogettare il tuo codice. La cella non dovrebbe preoccuparsi del controller. Si dovrebbe preoccupare solo di visualizzare se stesso e nient'altro

+0

> "La cella non deve preoccuparsi del controller. Dovrebbe preoccupano solo la visualizzazione di se stesso e nient'altro" Vuol dire che è anche cattiva pratica di aggiungere i pulsanti in una cella personalizzato se l'azione del pulsante sarebbe accedere o modificare alcune proprietà del modello? Perché in quel caso il modello può accedere solo dal controller poiché è la fonte della vista tabella ... –

+3

non lo è ovviamente. una cattiva pratica sarebbe avere un codice che elabora un sacco di cose del modello nell'azione del pulsante. una buona pratica in questo caso è di avere solo una riga di codice nell'azione del pulsante. la linea dovrebbe pubblicare una notifica o chiamare un metodo delegato. e quindi il controller dovrebbe reagire a questa chiamata o questa notifica ed eseguire tutto il codice necessario. controller, non la cella. Spero tu capisca di cosa sto parlando di –

+2

nella maggior parte dei framework UI è molto comune accedere al contenitore dell'oggetto, ad esempio in ActionScript puoi chiamare il genitore usando this.parent, e dalla mia esperienza in linguaggio Apple sembra Apple Non ho esperienza sufficiente con il linguaggio di programmazione visuale, quindi credo che questa soluzione sia molto accettabile e intelligente e la darò +1 –

0

Leggi gli altri commenti circa davvero che vogliono utilizzare un approccio alternativo prima di provare questo, ma usando questa estensione vi permetterà di raggiungere la dataSource e delegate entrambi i quali dovrebbe essere il 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 
    } 
} 

All'interno della cella

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

Volevo eseguire un seguito da una raccolta di immagini raccolte all'interno di uitableviewcell e questo ha funzionato perfettamente! . Grazie. – webjunkie

+0

Lavorato nel modello di progetto Dettagli principali. Grazie. –

+1

in Swift 4, '.nextResponder()' è cambiato in '.next' – troligtvis

1

Il modo migliore è implementare la delega. Il delegato informerà il controller della vista sul clic del pulsante. E, a sua volta, il tuo controller di visualizzazione (che sta conformando il protocollo per sopra delegato) gestirà l'attività che si desidera eseguire sull'evento click. (Le esercitazioni sui modelli di delega sono disponibili online. Puoi consultarle se vuoi sapere come fare la delega).

Problemi correlati