Cara melewati prepForSegue: sebuah objek

358

Saya memiliki banyak anotasi dalam tampilan peta (dengan rightCalloutAccessorytombol). Tombol akan melakukan segue dari ini mapviewke a tableview. Saya ingin meneruskan tableviewobjek yang berbeda (yang menyimpan data) tergantung pada tombol info yang diklik.

Misalnya: (benar-benar dibuat-buat)

  • annotation1 (Austin) -> pass data obj 1 (relevan dengan Austin)
  • annotation2 (Dallas) -> pass data obj 2 (relevan dengan Dallas)
  • annotation3 (Houston) -> pass data obj 3 dan seterusnya ... (Anda mendapatkan ide)

Saya dapat mendeteksi tombol info yang diklik.

Saya menggunakan prepareForSegue: untuk meneruskan data obj ke tujuan ViewController. Karena saya tidak dapat membuat panggilan ini mengambil argumen tambahan untuk objek data yang saya butuhkan, apa saja cara elegan untuk mencapai efek yang sama (objek data dinamis)?

Tip apa pun akan dihargai.

berdecak
sumber

Jawaban:

674

Cukup ambil referensi ke pengontrol tampilan target dalam prepareForSegue:metode dan berikan benda yang Anda butuhkan ke sana. Ini sebuah contoh ...

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Make sure your segue name in storyboard is the same as this line
    if ([[segue identifier] isEqualToString:@"YOUR_SEGUE_NAME_HERE"])
    {
        // Get reference to the destination view controller
        YourViewController *vc = [segue destinationViewController];

        // Pass any objects to the view controller here, like...
        [vc setMyObjectHere:object];
    }
}

REVISI: Anda juga dapat menggunakan performSegueWithIdentifier:sender:metode untuk mengaktifkan transisi ke tampilan baru berdasarkan pilihan atau tekan tombol.

Sebagai contoh, pertimbangkan saya memiliki dua pengendali tampilan. Yang pertama berisi tiga tombol dan yang kedua perlu tahu tombol mana yang telah ditekan sebelum transisi. Anda dapat menyambungkan tombol ke IBActiondalam kode Anda yang menggunakan performSegueWithIdentifier:metode, seperti ini ...

// When any of my buttons are pressed, push the next view
- (IBAction)buttonPressed:(id)sender
{
    [self performSegueWithIdentifier:@"MySegue" sender:sender];
}

// This will get called too before the view appears
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"MySegue"]) {

        // Get destination view
        SecondView *vc = [segue destinationViewController];

        // Get button tag number (or do whatever you need to do here, based on your object
        NSInteger tagIndex = [(UIButton *)sender tag];

        // Pass the information to your destination view
        [vc setSelectedButton:tagIndex];
    }
}

EDIT: Aplikasi demo yang semula saya lampirkan sekarang berumur enam tahun, jadi saya telah menghapusnya untuk menghindari kebingungan.

Simon
sumber
Terima kasih, tetapi saya ingin mengatur [vc setMyObjectHere:object];ini secara dinamis. yaitu obj1 untuk button1, obj2 untuk button2 Masalahnya adalah saya tidak bisa menyampaikan argumen. Apakah ada cara untuk mengatasi ini?
berdecak
2
Saya telah memperbarui posting saya dengan contoh yang dapat diunduh tentang apa yang saya bicarakan.
Simon
itu berhasil! Terima kasih banyak. Sebagai catatan persiapan, persiapanForSegue: memiliki argumen UIControl yang merupakan kelas induk dari UIButton (dengan demikian bisa mendapatkan tag): D
chizzle
Apakah prepForSegue dipanggil bahkan ketika Anda hanya mendorong ke pengontrol navigasi tanpa papan storyboard?
zakdances
Ini adalah salah satu jawaban paling menyeluruh yang pernah saya lihat. Contoh kode yang baik, menyelesaikan masalah, menawarkan sampel yang dapat diunduh ... wow. Saya terkesan!
lewiguez
82

Kadang-kadang membantu untuk menghindari membuat ketergantungan waktu kompilasi antara dua pengontrol tampilan. Inilah cara Anda dapat melakukannya tanpa peduli dengan jenis pengontrol tampilan tujuan:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.destinationViewController respondsToSelector:@selector(setMyData:)]) {
        [segue.destinationViewController performSelector:@selector(setMyData:) 
                                              withObject:myData];
    } 
}

Jadi selama pengendali tampilan tujuan Anda menyatakan milik umum, mis:

@property (nonatomic, strong) MyData *myData;

Anda dapat mengatur properti ini di pengontrol tampilan sebelumnya seperti yang saya jelaskan di atas.

Macondo2Seattle
sumber
12
Ini benar-benar masalah pendapat. Saya belum (belum) memiliki situasi di mana saya tidak ingin mengontrol pengontrol tampilan 'ketat', meskipun saya sangat menghargai apa yang Anda katakan dan mungkin penting dalam keadaan yang tepat.
Simon
2
@Simon: yeah, Anda tinggal memilih pendekatan yang terbaik untuk Anda. Dalam aplikasi yang sedang saya kerjakan sekarang, misalnya, pendekatan saya sangat masuk akal karena saya terus menambahkan pengontrol tampilan yang memerlukan objek data yang sama. Mampu menghubungkan mereka hanya dengan segue dan mengetahui bahwa mereka akan mendapatkan data yang tepat sangat nyaman.
Macondo2Seattle
10
Ini bukan masalah pendapat, itu hanya salah :) Frasa "Jawaban yang diterima bukan cara terbaik untuk melakukan ini" adalah salah. Seharusnya berbunyi "Dalam kasus tertentu, Anda perlu melakukan ini ..."
Fattie
2
Saya lebih suka metode Simon. Karena akan memberi tahu saya kesalahan pada waktu kompilasi. Misalnya, jika saya melewatkan deklarasi myData di pengontrol tampilan tujuan, saya akan segera tahu. Tetapi untuk skenario Anda, pendekatan Anda tampaknya bagus!
Abdurrahman Mubeen Ali
14
Pendekatan ini benar-benar membuat ketergantungan, karena Anda memerlukan pengontrol tampilan tujuan untuk memiliki setMyData:. Itu ketergantungan. Fakta bahwa Anda menggunakan pemilih untuk menghindari kesalahan kompilasi harus diperlakukan sebagai kelemahan dari pendekatan Anda, bukan manfaat. Ini mengejutkan bagi saya berapa banyak pengembang telah kehilangan konsep bahwa kompilasi kesalahan waktu harus lebih disukai daripada kesalahan run-time.
Nate
21

Dalam Swift 4.2 saya akan melakukan sesuatu seperti itu:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let yourVC = segue.destination as? YourViewController {
        yourVC.yourData = self.someData
    }
}
Remy Cilia
sumber
Apakah Anda perlu menelepon: `super.prepare (untuk: segue, pengirim: pengirim)`?
Andrew K
16

Saya memiliki kelas pengirim , seperti ini

@class MyEntry;

@interface MySenderEntry : NSObject
@property (strong, nonatomic) MyEntry *entry;
@end

@implementation MySenderEntry
@end

Saya menggunakan kelas pengirim ini untuk meneruskan objek keprepareForSeque:sender:

-(void)didSelectItemAtIndexPath:(NSIndexPath*)indexPath
{
    MySenderEntry *sender = [MySenderEntry new];
    sender.entry = [_entries objectAtIndex:indexPath.row];
    [self performSegueWithIdentifier:SEGUE_IDENTIFIER_SHOW_ENTRY sender:sender];
}

-(void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:SEGUE_IDENTIFIER_SHOW_ENTRY]) {
        NSAssert([sender isKindOfClass:[MySenderEntry class]], @"MySenderEntry");
        MySenderEntry *senderEntry = (MySenderEntry*)sender;
        MyEntry *entry = senderEntry.entry;
        NSParameterAssert(entry);

        [segue destinationViewController].delegate = self;
        [segue destinationViewController].entry = entry;
        return;
    }

    if ([[segue identifier] isEqualToString:SEGUE_IDENTIFIER_HISTORY]) {
        // ...
        return;
    }

    if ([[segue identifier] isEqualToString:SEGUE_IDENTIFIER_FAVORITE]) {
        // ...
        return;
    }
}
neoneye
sumber
apakah kita menggunakan prepareForSegue atau menerapkannya dan anggapannya adalah prepForSegue dipanggil sendiri yaitu kita tidak perlu melakukan sesuatu seperti[self prepareForSegue]
Honey
15

Saya menemukan pertanyaan ini ketika saya mencoba mempelajari cara meneruskan data dari satu Pengontrol Tampilan ke yang lain. Saya membutuhkan sesuatu yang visual untuk membantu saya belajar, jadi jawaban ini adalah pelengkap bagi yang lain yang sudah ada di sini. Ini sedikit lebih umum daripada pertanyaan asli tetapi dapat disesuaikan untuk bekerja.

Contoh dasar ini berfungsi seperti ini:

masukkan deskripsi gambar di sini

Idenya adalah untuk meneruskan string dari bidang teks di Pengendali Tampilan Pertama ke label di Pengendali Tampilan Kedua.

Pengontrol Tampilan Pertama

import UIKit

class FirstViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!

    // This function is called before the segue
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

        // get a reference to the second view controller
        let secondViewController = segue.destinationViewController as! SecondViewController

        // set a variable in the second view controller with the String to pass
        secondViewController.receivedString = textField.text!
    }

}

Pengendali Tampilan Kedua

import UIKit

class SecondViewController: UIViewController {

    @IBOutlet weak var label: UILabel!

    // This variable will hold the data being passed from the First View Controller
    var receivedString = ""

    override func viewDidLoad() {
        super.viewDidLoad()

        // Used the text from the First View Controller to set the label
        label.text = receivedString
    }

}

Ingat untuk

  • Buat segue dengan controlmengeklik tombol dan menggerakkannya ke Pengendali Tampilan Kedua.
  • Hubungkan outlet untuk UITextFielddan UILabel.
  • Atur View Controllers pertama dan kedua ke file Swift yang sesuai di IB.

Sumber

Cara mengirim data melalui segue (cepat) (tutorial YouTube)

Lihat juga

Lihat Pengontrol: Melewati data maju dan meneruskan data kembali (jawaban yang lebih lengkap)

Suragch
sumber
5

Untuk Swift gunakan ini,

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    var segueID = segue.identifier

    if(segueID! == "yourSegueName"){

        var yourVC:YourViewController = segue.destinationViewController as YourViewController

        yourVC.objectOnYourVC = setObjectValueHere!

    }
}
Mohammad Zaid Pathan
sumber
4

Saya telah mengimplementasikan perpustakaan dengan kategori di UIViewController yang menyederhanakan operasi ini. Pada dasarnya, Anda mengatur parameter yang ingin Anda lewati di NSDictionary yang terkait dengan item UI yang melakukan segue. Ia bekerja dengan segues manual juga.

Misalnya, Anda bisa melakukannya

[self performSegueWithIdentifier:@"yourIdentifier" parameters:@{@"customParam1":customValue1, @"customValue2":customValue2}];

untuk segue manual atau buat tombol dengan segue dan gunakan

[button setSegueParameters:@{@"customParam1":customValue1, @"customValue2":customValue2}];

Jika pengontrol tampilan tujuan tidak sesuai dengan kode nilai kunci untuk kunci, tidak ada yang terjadi. Ini bekerja dengan nilai kunci juga (berguna untuk segmen segues). Lihat di sini https://github.com/stefanomondino/SMQuickSegue

Stefano Mondino
sumber
2

Solusi saya serupa.

// In destination class: 
var AddressString:String = String()

// In segue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
   if (segue.identifier == "seguetobiddetailpagefromleadbidder")
    {
        let secondViewController = segue.destinationViewController as! BidDetailPage
        secondViewController.AddressString = pr.address as String
    }
}
AG
sumber
1

Cukup gunakan fungsi ini.

 override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let index = CategorytableView.indexPathForSelectedRow
    let indexNumber = index?.row
    let VC = segue.destination as! DestinationViewController
   VC.value = self.data

}
Parth Barot
sumber
0

Saya menggunakan solusi ini sehingga saya bisa menyimpan permohonan segue dan komunikasi data dalam fungsi yang sama:

private var segueCompletion : ((UIStoryboardSegue, Any?) -> Void)?

func performSegue(withIdentifier identifier: String, sender: Any?, completion: @escaping (UIStoryboardSegue, Any?) -> Void) {
    self.segueCompletion = completion;
    self.performSegue(withIdentifier: identifier, sender: sender);
    self.segueCompletion = nil
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    self.segueCompletion?(segue, sender)
}

Kasus penggunaan akan menjadi seperti:

func showData(id : Int){
    someService.loadSomeData(id: id) {
        data in
        self.performSegue(withIdentifier: "showData", sender: self) {
            storyboard, sender in
            let dataView = storyboard.destination as! DataView
            dataView.data = data
        }
    }
}

Ini sepertinya bekerja untuk saya, bagaimanapun, saya tidak 100% yakin bahwa fungsi perform dan persiapan selalu dieksekusi pada utas yang sama.

dannrob
sumber