Ricerca…


Utilizzo di Segues (passaggio dei dati in avanti)

Per passare i dati dal controller della vista corrente al nuovo controller della vista successivo (non un precedente controller della vista) usando segues, prima creare un seguito con un identificatore nello storyboard pertinente. Sostituisci il metodo prepareForSegue del tuo attuale controller di prepareForSegue . All'interno del metodo controlla il seguito appena creato dal suo identificatore. Trasmetti il ​​controller di visualizzazione di destinazione e passa i dati ad esso impostando le proprietà sul controller di visualizzazione downcast.

Impostazione di un identificatore per un seguito:

Ispettore degli attributi per un seguito

Le sequenze possono essere eseguite in modo programmatico o utilizzando l'evento dell'azione del pulsante impostato nello storyboard da ctrl + trascinamento al controller della vista di destinazione. È possibile chiamare un passaggio in modo programmatico, quando necessario, utilizzando l'identificatore dei passaggi nel controllore della vista:

Objective-C

- (void)showDetail {
    [self performSegueWithIdentifier:@"showDetailingSegue" sender:self];        
}

veloce

func showDetail() {
    self.performSegue(withIdentifier: "showDetailingSegue", sender: self)
}

È possibile configurare il payload dei passaggi nella versione sovrascritta del metodo prepareForSegue . È possibile impostare le proprietà richieste prima che il controller della vista di destinazione sia caricato.

Objective-C

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if([segue.identifier isEqualToString:@"showDetailingSegue"]){
        DetailViewController *controller = (DetailViewController *)segue.destinationViewController;
        controller.isDetailingEnabled = YES;
    }
}

veloce

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "showDetailingSegue" {
        let controller = segue.destinationViewController as! DetailViewController
        controller.isDetailingEnabled = true
    }    
}

DetailViewController è il nome del secondo controller di visualizzazione e isDetailingEnabled è una variabile pubblica in tale controller di visualizzazione.

Per espandere questo modello, puoi trattare un metodo pubblico su DetailViewController come pseudo inizializzatore, per aiutare a inizializzare le variabili richieste. Questo documenterà automaticamente le variabili che devono essere impostate su DetailViewController senza dover leggere il suo codice sorgente. È anche un posto comodo per mettere le impostazioni predefinite.

Objective-C

- (void)initVC:(BOOL *)isDetailingEnabled {
    self.isDetailingEnabled = isDetailingEnabled
}

veloce

func initVC(isDetailingEnabled: Bool) {
    self.isDetailingEnabled = isDetailingEnabled
}

Uso del pattern Delegate (passaggio di dati indietro)

Per trasferire i dati dal controller di visualizzazione corrente al controller di visualizzazione precedente, è possibile utilizzare il modello delegato.

inserisci la descrizione dell'immagine qui

In questo esempio si presuppone che sia stato eseguito un seguito in Interface Builder e che si sia impostato l'identificatore di showSecondViewController per showSecondViewController . Le uscite e le azioni devono anche essere collegate ai nomi nel seguente codice.

First View Controller

Il codice per il controller First View è

veloce

class FirstViewController: UIViewController, DataEnteredDelegate {

    @IBOutlet weak var label: UILabel!
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showSecondViewController", let secondViewController = segue.destinationViewController as? SecondViewController  {
            secondViewController.delegate = self
        }
    }

    // required method of our custom DataEnteredDelegate protocol
    func userDidEnterInformation(info: String) {
        label.text = info
        navigationController?.popViewControllerAnimated(true)
    }
}

Objective-C

@interface FirstViewController : UIViewController <DataEnteredDelegate>
@property (weak, nonatomic) IBOutlet UILabel *label;
@end

@implementation FirstViewController
- (void)viewDidLoad {
    [super viewDidLoad];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    SecondViewController *secondViewController = segue.destinationViewController;
    secondViewController.delegate = self;

}
-(void)userDidEnterInformation:(NSString *)info {
    _label.text = info
    [self.navigationController popViewControllerAnimated:YES];
}
@end

Nota l'uso del nostro protocollo personalizzato DataEnteredDelegate .

Secondo View Controller and Protocol

Il codice per il secondo controller di vista è

veloce

// protocol used for sending data back
protocol DataEnteredDelegate: class {
    func userDidEnterInformation(info: String)
}

class SecondViewController: UIViewController {

    // making this a weak variable so that it won't create a strong reference cycle
    weak var delegate: DataEnteredDelegate?
    
    @IBOutlet weak var textField: UITextField!

    @IBAction func sendTextBackButton(sender: AnyObject) {
        
        // call this method on whichever class implements our delegate protocol (the first view controller)
        delegate?.userDidEnterInformation(textField.text ?? "")
    }
}

Objective-C

@protocol DataEnteredDelegate <NSObject>
-(void)userDidEnterInformation:(NSString *)info;
@end

@interface SecondViewController : UIViewController 
@property (nonatomic) id <DataEnteredDelegate> delegate;
@property (weak, nonatomic) IBOutlet UITextField *textField;
@end

@implementation SecondViewController
- (void)viewDidLoad {
    [super viewDidLoad];
}

- (IBAction) sendTextBackButton:(id)sender{
    [_delegate userDidEnterInformation:textField.text];
}
@end

Si noti che il protocol è al di fuori della classe View Controller.

Passare i dati all'indietro usando lo svolgimento ai seguiti

A differenza di seguito che consente di passare i dati "in avanti" dal controller di visualizzazione corrente al controller di visualizzazione di destinazione:

(VC1) -> (VC2)

Usando "unwind" puoi fare il contrario, passare i dati dalla destinazione o dal controller della vista corrente al suo controller di visualizzazione presentando:

(VC1) <- (VC2)

NOTA : Prestare attenzione al fatto che l'utilizzo di unwind consente di passare prima i dati e successivamente il controller di visualizzazione corrente (VC2) verrà deallocato.

Ecco come farlo:

Innanzitutto, è necessario aggiungere la seguente dichiarazione al controller della vista di presentazione (VC1) che è il controller della vista che vogliamo trasmettere i dati a:

@IBAction func unwindToPresentingViewController(segue:UIStoryboardSegue)

L'importante è usare il prefisso unwind , questo "informa" Xcode che questo è un metodo di svolgimento che ti dà la possibilità di usarlo anche nello storyboard.

Successivamente dovrai implementare il metodo, sembra quasi lo stesso di un seguito reale:

@IBAction func unwindToPresentingViewController(segue:UIStoryboardSegue)
{
    if segue.identifier == "YourCustomIdentifer"
    {
        if let VC2 = segue.sourceViewController as? VC2
        {
            //    Your custom code in here to access VC2 class member
        }

Ora hai 2 opzioni per invocare le chiamate a piacimento:

  1. È possibile "hard code" richiamare: self.performSegueWithIdentifier("YourCustomIdentifier", sender: self) che eseguirà lo performSegueWithIdentifier per te ogni volta che performSegueWithIdentifier .
  2. Puoi collegare il metodo di svolgimento utilizzando lo storyboard all'oggetto "Esci": ctrl + trascina il pulsante che vuoi richiamare il metodo di svolgimento, sull'oggetto "Esci":

inserisci la descrizione dell'immagine qui

Rilascia e avrai la possibilità di scegliere il tuo metodo di svolgimento personalizzato:

inserisci la descrizione dell'immagine qui

Trasmissione dei dati tramite le chiusure (trasmissione dei dati indietro)

Invece di usare il pattern delegato , che ha diviso l'implementazione in varie parti della classe UIViewController , è possibile utilizzare anche le closures per passare i dati indietro e avanti. Supponendo che tu stia utilizzando UIStoryboardSegue , nel metodo prepareForSegue puoi facilmente configurare il nuovo controller in un solo passaggio

final class DestinationViewController: UIViewController {
    var onCompletion: ((success: Bool) -> ())?

    @IBAction func someButtonTapped(sender: AnyObject?) {
        onCompletion?(success: true)
    }
}

final class MyViewController: UIViewController {
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    
        guard let destinationController = segue.destinationViewController as? DestinationViewController else { return }
    
        destinationController.onCompletion = { success in
            // this will be executed when `someButtonTapped(_:)` will be called
            print(success)
        }
    }
}

Questo è un esempio di utilizzo ed è meglio usare su Swift, la sintassi del blocco Objective-C non è così facile da rendere il codice più leggibile

Usando la chiusura (blocco) di richiamata che restituisce i dati

questo argomento è un problema classico nello sviluppo di iOS e la sua soluzione è diversa come già mostrato in altri esempi. In questo esempio mostrerò un altro uso quotidiano comune: passare i dati usando la closure adattando l'esempio di delegate pattern su questa pagina alla closure callback!

una cosa che questo metodo è superiore a delegate pattern è invece di dividere il codice di settaggio in due posti diversi (guarda l'esempio di delegato in questa pagina, prepareForSegue , userDidEnterInformation ) piuttosto raccogliendoli insieme (solo in prepareForSegue , lo mostrerò)

Inizia da Second View Controller

dobbiamo capire come usare il callback, quindi possiamo scriverlo, questo è il motivo per cui partiamo dal secondo controller di vista poiché è dove usiamo il callback: quando abbiamo ottenuto il nuovo input di testo, chiamiamo il nostro callback, usando come parametro il parametro callback per passare i dati al primo ViewController, notare che ho detto usando il parametro callback, questo è molto importante, i novizi (come lo ero io) lo ignorano sempre e non sanno da dove iniziare a scrivere correttamente la callback

quindi in questo caso, sappiamo che il nostro callback accetta solo un parametro: il testo e il suo tipo è String , dichiariamolo e rendiamolo proprietà dal momento che abbiamo bisogno di compilare dal nostro primo controller di visualizzazione

Devo solo commentare tutta la parte del delegate e tenerla per il confronto

class SecondViewController: UIViewController {

    //weak var delegate: DataEnteredDelegate? = nil
    var callback: ((String?)->())?
    
    @IBOutlet weak var textField: UITextField!

    @IBAction func sendTextBackButton(sender: AnyObject) {
        
        //delegate?.userDidEnterInformation(textField.text!)
        callback?(input.text)
        
        self.navigationController?.popViewControllerAnimated(true)
    }
}

Termina il primo controller di visualizzazione

tutto quello che devi fare è passare la chiusura del callback, e abbiamo finito, la chiusura farà il lavoro futuro per noi dal momento che l'abbiamo già configurata in seconda visione

guarda come riduce il nostro codice rispetto al delegate pattern

//no more DataEnteredDelegate
class FirstViewController: UIViewController {

    @IBOutlet weak var label: UILabel!
    
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "showSecondViewController" {
            let secondViewController = segue.destinationViewController as! SecondViewController
            //secondViewController.delegate = self
            secondViewController.callback = { text in self.label.text = text }
        }
    }

    // required method of our custom DataEnteredDelegate protocol
    //func userDidEnterInformation(info: String) {
    //    label.text = info
    //}
}

e nell'ultimo, forse qualcuno di voi sarà confuso dal fatto che stiamo passando solo i dati (chiusura in questo caso) solo in un modo, dal primo controller di visualizzazione al secondo, non direttamente dal controller di seconda visione, come possiamo considerarlo come uno strumento di comunicazione? forse dovresti davvero eseguirlo e provarlo tu stesso, tutto quello che dirò è il parametro , il parametro di callback closure che restituisce i dati indietro!

Assegnando una proprietà (Passa dati in avanti)

È possibile passare i dati direttamente assegnando la proprietà del controller di visualizzazione successivo prima di inviarlo o inviarlo.

class FirstViewController: UIViewController {

    func openSecondViewController() {

        // Here we initialize SecondViewController and set the id property to 492
        let secondViewController = SecondViewController()
        secondViewController.id = 492

        // Once it was assign we now push or present the view controller
        present(secondViewController, animated: true, completion: nil)
    }

}

class SecondViewController: UIViewController {
    
    var id: Int?

    override func viewDidLoad() {
        super.viewDidLoad()

        // Here we unwrapped the id and will get the data from the previous view controller.
        if let id = id {
            print("Id was set: \(id)")
        }
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow