Xebia Blog

Unul dintre dezavantajele utilizării secvențelor în storyboard-uri este că, adesea, trebuie să scrieți cod pentru a transmite date de la controlerul de vizualizare sursă la controlerul de vizualizare destinație. Metoda prepareForSegue(_:sender:) este locul potrivit pentru a face acest lucru. Uneori trebuie să declanșați manual un segue prin apelarea performSegueWithIdentifier(_:sender:), iar acolo știți de obicei ce date trebuie să transmiteți. Cum putem evita să adăugăm variabile de stare suplimentare în controlerul nostru de vizualizare sursă doar pentru a transmite date? Un truc simplu este să folosim parametrul sender pe care îl au ambele metode.

Update:
Rețineți că acest lucru este considerat un anti-pattern, așa cum au comentat unii cititori de mai jos, această postare este menită să exploreze posibilitățile de segues, ceea ce nu înseamnă că ar trebui să o folosiți întotdeauna. Folosiți-l numai atunci când este adecvat sau atunci când nu este disponibilă nicio altă opțiune.

Parametrul expeditor este utilizat în mod normal de storyboard-uri pentru a indica elementul UI care a declanșat segue, de exemplu un UIButton atunci când este apăsat sau un UITableViewCell care declanșează segue prin selectarea acestuia. Acest lucru vă permite să determinați ceea ce a declanșat continuarea în prepareForSegue:sender: și, pe baza acestui lucru (și, desigur, a identificatorului de continuare), să întreprindeți anumite acțiuni și să configurați controlerul de vizualizare de destinație sau chiar să determinați că acesta nu ar trebui să efectueze deloc continuarea, returnând false în shouldPerformSegueWithIdentifier(_:sender:).

Când nu este posibil să declanșați trecerea de la un element UI din Storyboard, trebuie să utilizați în schimb performSegueWithIdentifier(_:sender:) pentru a o declanșa manual. Acest lucru se poate întâmpla atunci când nicio interacțiune directă a utilizatorului nu trebuie să declanșeze acțiunea unui control care a fost creat în cod. Poate că doriți să executați o logică suplimentară la apăsarea unui buton și, după aceea, să efectuați segue. Oricare ar fi situația, puteți utiliza argumentul sender în avantajul dumneavoastră. Puteți trece orice aveți nevoie în prepareForSegue(_:sender:) sau shouldPerformSegueWithIdentifier(_:sender:).

Să ne uităm la câteva exemple.

Screen Shot 2015-05-08 at 23.25.37

Aici avem doi controlori de vizualizare foarte simpli. Primul are trei butoane pentru diferite culori. La apăsarea pe oricare dintre butoane, numele culorii selectate va fi pus pe o etichetă și va împinge al doilea controler de vizualizare. Controlerul de vizualizare împins își va seta culoarea de fundal la culoarea reprezentată de butonul apăsat. Pentru a face acest lucru, trebuie să transmitem un obiect UIColor către controlerul de vizualizare țintă.

Chiar dacă acest lucru ar putea fi gestionat prin crearea a 3 secvențe distincte de la butoane direct către controlerul de vizualizare de destinație, am ales să gestionăm noi înșine atingerea butonului și să declanșăm secvența manual.

Puteți veni cu ceva de genul următorului cod pentru a realiza acest lucru:

class ViewController: UIViewController {

@IBOutlet weak var label: UILabel!

var tappedColor: UIColor?

@IBAction func tappedRed(sender: AnyObject) {
label.text = „Tapped Red”
tappedColor = UIColor.redColor()
performSegueWithIdentifier(„ShowColor”, sender: sender)
}

@IBAction func tappedGreen(sender: AnyObject) {
label.text = „Tapped Green”
tappedColor = UIColor.greenColor()
performSegueWithIdentifier(„ShowColor”, sender: sender)
}

@IBAction func tappedBlue(sender: AnyObject) {
label.text = „Tapped Blue”
tappedColor = UIColor.blueColor()
performSegueWithIdentifier(„ShowColor”, sender: sender)
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == „ShowColor” {
if let colorViewController = segue.destinationViewController as? ColorViewController {
colorViewController.color = tappedColor
}
}
}
}

}

class ColorViewController: UIViewController {

var color: UIColor?

override func viewDidLoad() {
super.viewDidLoad()

view.backgroundColor = color
}

}

Am creat o variabilă de stare numită tappedColor pentru a ține evidența culorii care trebuie să fie transmisă. Aceasta este setată în fiecare dintre metodele de acțiune înainte de a apela performSegueWithIdentifier(„ShowColor”, sender: sender) și apoi citită din nou în prepareForSegue(_:sender:), astfel încât să o putem transmite controlerului de vizualizare de destinație.

Metodele de acțiune vor avea ca argument expeditor UIButtons tactat și, din moment ce acesta este elementul real care a inițiat acțiunea, este logic să fie setat ca expeditor atunci când se efectuează segue. Deci, asta este ceea ce facem în codul de mai sus. Dar, din moment ce nu folosim de fapt expeditorul atunci când pregătim tranziția, am putea la fel de bine să transmitem direct culoarea. Iată o nouă versiune a ViewController care face exact acest lucru:

class ViewController: UIViewController {

@IBOutlet weak var label: UILabel!

@IBAction func tappedRed(sender: AnyObject) {
label.text = „Tapped Red”
performSegueWithIdentifier(„ShowColor”, sender: UIColor.redColor())}

@IBAction func tappedGreen(sender: AnyObject) {
label.text = „Tapped Green”
performSegueWithIdentifier(„ShowColor”, sender: UIColor.greenColor())}

@IBAction func tappedBlue(sender: AnyObject) {
label.text = „Tapped Blue”
performSegueWithIdentifier(„ShowColor”, sender: UIColor.blueColor())}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == „ShowColor” {
if let colorViewController = segue.destinationViewController as? ColorViewController {
colorViewController.color = sender as? UIColor
}
}
}
}

}

Acest lucru ne permite să scăpăm de variabila noastră suplimentară tappedColor.

S-ar putea părea (și poate că așa este) că se abuzează totuși de parametrul expeditor, așa că folosiți-l cu grijă și numai acolo unde este cazul. Fiți conștienți de consecințe; dacă un alt cod sau un element dintr-un Storyboard declanșează același segue (adică cu același identificator), atunci expeditorul ar putea fi doar un element UI în loc de obiectul la care vă așteptați, ceea ce va duce la rezultate neașteptate și poate chiar la blocări atunci când forțați transformarea expeditorului în ceva ce nu este.

Puteți găsi codul de exemplu sub forma unui proiect Xcode pe https://github.com/lammertw/SegueColorSample.

Doriți să aflați mai multe despre acest subiect?
Consultați serviciile noastre de consultanță, ofertele de formare și carierele de mai jos sau contactați-ne la [email protected]

.

Lasă un răspuns

Adresa ta de email nu va fi publicată.