Passing Data antara View Controllers

1372

Saya baru untuk iOS dan Objective-C dan seluruh paradigma MVC dan saya terjebak dengan yang berikut:

Saya memiliki pandangan yang bertindak sebagai formulir entri data dan saya ingin memberikan opsi kepada pengguna untuk memilih beberapa produk. Produk terdaftar pada tampilan lain dengan a UITableViewControllerdan saya telah mengaktifkan banyak pilihan.

Pertanyaan saya adalah, bagaimana cara mentransfer data dari satu tampilan ke tampilan lainnya? Saya akan menyimpan pilihan pada UITableViewdalam array, tetapi bagaimana saya kemudian meneruskannya kembali ke tampilan formulir entri data sebelumnya sehingga dapat disimpan bersama dengan data lain ke Data Inti pada saat pengajuan formulir?

Saya telah menjelajahi sekitar dan melihat beberapa orang mendeklarasikan array di delegasi aplikasi. Saya membaca sesuatu tentang Singletons tetapi tidak mengerti apa ini dan saya membaca sesuatu tentang membuat model data.

Apa cara yang benar untuk melakukan ini dan bagaimana saya melakukannya?

Matt Price
sumber

Jawaban:

1684

Pertanyaan ini tampaknya sangat populer di sini di stackoverflow, jadi saya pikir saya akan mencoba dan memberikan jawaban yang lebih baik untuk membantu orang-orang yang memulai di dunia iOS seperti saya.

Saya harap jawaban ini cukup jelas untuk dipahami orang dan saya tidak melewatkan apa pun.

Melewati Data Maju

Mengirimkan data ke pengontrol tampilan dari pengontrol tampilan lain. Anda akan menggunakan metode ini jika Anda ingin meneruskan objek / nilai dari satu pengontrol tampilan ke pengontrol tampilan lain yang mungkin Anda dorong ke tumpukan navigasi.

Untuk contoh ini, kita akan memiliki ViewControllerAdanViewControllerB

Untuk meneruskan BOOLnilai dari ViewControllerAke ViewControllerBkami akan melakukan hal berikut.

  1. di ViewControllerB.hbuat properti untukBOOL

    @property (nonatomic, assign) BOOL isSomethingEnabled;
  2. di ViewControllerAAnda perlu menceritakannya tentang ViewControllerBjadi gunakan

    #import "ViewControllerB.h"

    Lalu di mana Anda ingin memuat tampilan misalnya. didSelectRowAtIndexatau IBActionAnda perlu mengatur properti ViewControllerBsebelum Anda mendorongnya ke nav stack.

    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.isSomethingEnabled = YES;
    [self pushViewController:viewControllerB animated:YES];

    Ini akan mengatur isSomethingEnableddalam ViewControllerBuntuk BOOLnilai YES.

Melewati Data Maju menggunakan Segues

Jika Anda menggunakan Storyboard, kemungkinan besar Anda menggunakan segue dan akan membutuhkan prosedur ini untuk meneruskan data. Ini mirip dengan di atas tetapi alih-alih meneruskan data sebelum Anda mendorong pengontrol tampilan, Anda menggunakan metode yang disebut

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

Jadi untuk lulus BOOLdari ViewControllerAkeViewControllerB kita akan melakukan hal berikut:

  1. di ViewControllerB.hbuat properti untukBOOL

    @property (nonatomic, assign) BOOL isSomethingEnabled;
  2. di ViewControllerAAnda perlu menceritakannya tentang ViewControllerBjadi gunakan

    #import "ViewControllerB.h"
  3. Buat segmen dari ViewControllerAhinggaViewControllerB di papan cerita dan beri pengenal, dalam contoh ini kita akan menyebutnya"showDetailSegue"

  4. Selanjutnya, kita perlu menambahkan metode ViewControllerAyang dipanggil ketika setiap segmen dilakukan, karena ini kita perlu mendeteksi segmen mana yang dipanggil dan kemudian melakukan sesuatu. Dalam contoh kami, kami akan memeriksa "showDetailSegue"dan jika itu dilakukan kami akan memberikan BOOLnilai kamiViewControllerB

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

    Jika pandangan Anda tertanam di pengontrol navigasi, Anda perlu mengubah metode di atas sedikit menjadi yang berikut

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
        if([segue.identifier isEqualToString:@"showDetailSegue"]){
            UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
            ViewControllerB *controller = (ViewControllerB *)navController.topViewController;
            controller.isSomethingEnabled = YES;
        }
    }

    Ini akan mengatur isSomethingEnableddalam ViewControllerBuntuk BOOLnilai YES.

Melewati Data Kembali

Untuk meneruskan data kembali dari ViewControllerBke ViewControllerAAnda perlu menggunakan Protokol dan Delegasi atau Blok , yang terakhir dapat digunakan sebagai mekanisme yang digabungkan secara longgar untuk panggilan balik.

Untuk melakukan ini kami akan membuat ViewControllerAdelegasi dari ViewControllerB. Ini memungkinkanViewControllerB untuk mengirim pesan kembali agar ViewControllerAkami dapat mengirim data kembali.

Untuk ViewControllerAmenjadi delegasi ViewControllerBharus sesuai dengan ViewControllerBprotokol yang harus kita tentukan. Ini memberitahu ViewControllerAmetode mana yang harus diimplementasikan.

  1. Di ViewControllerB.h, di bawah #import, tetapi di atas @interfaceAnda menentukan protokol.

    @class ViewControllerB;
    
    @protocol ViewControllerBDelegate <NSObject>
    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
    @end
  2. selanjutnya masih dalam ViewControllerB.hAnda perlu mengatur delegateproperti dan mensintesis dalamViewControllerB.m

    @property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
  3. Dalam ViewControllerBkita memanggil pesan pada delegatesaat kita pop controller tampilan.

    NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
    [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
  4. Itu untuk ViewControllerB. Sekarang ViewControllerA.h, beri tahu ViewControllerAuntuk mengimpor ViewControllerBdan mematuhi protokolnya.

    #import "ViewControllerB.h"
    
    @interface ViewControllerA : UIViewController <ViewControllerBDelegate>
  5. Dalam ViewControllerA.mmengimplementasikan metode berikut dari protokol kami

    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
    {
        NSLog(@"This was returned from ViewControllerB %@",item);
    }
  6. Sebelum mendorong viewControllerBke tumpukan navigasi kita perlu mengatakan ViewControllerBbahwa itu ViewControllerAadalah delegasinya, kalau tidak kita akan mendapatkan kesalahan.

    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.delegate = self
    [[self navigationController] pushViewController:viewControllerB animated:YES];

Referensi

  1. Menggunakan Delegasi untuk Berkomunikasi Dengan View Controllers Lain di Panduan Pemrograman View Controller
  2. Delegasikan Pola

NSNotification center Ini cara lain untuk meneruskan data.

// add observer in controller(s) where you want to receive data
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDeepLinking:) name:@"handleDeepLinking" object:nil];

-(void) handleDeepLinking:(NSNotification *) notification {
    id someObject = notification.object // some custom object that was passed with notification fire.
}

// post notification
id someObject;
[NSNotificationCenter.defaultCenter postNotificationName:@"handleDeepLinking" object:someObject];

Melewati Data kembali dari satu kelas ke kelas lain (Sebuah kelas dapat berupa pengontrol apa saja, manajer jaringan / sesi, subkelas UIView atau kelas lainnya)

Blok adalah fungsi anonim.

Contoh ini meneruskan data dari Kontroler B ke Kontroler A

tentukan blok

@property void(^selectedVoucherBlock)(NSString *); // in ContollerA.h

tambahkan block handler (listener) di mana Anda memerlukan suatu nilai (misalnya Anda memerlukan respons API Anda di ControllerA atau Anda memerlukan data ContorllerB pada A)

// in ContollerA.m

- (void)viewDidLoad {
    [super viewDidLoad];
    __unsafe_unretained typeof(self) weakSelf = self;
    self.selectedVoucherBlock = ^(NSString *voucher) {
        weakSelf->someLabel.text = voucher;
    };
}

Pergi ke Pengendali B

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
ControllerB *vc = [storyboard instantiateViewControllerWithIdentifier:@"ControllerB"];
vc.sourceVC = self;
    [self.navigationController pushViewController:vc animated:NO];

blok api

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: 
(NSIndexPath *)indexPath {
    NSString *voucher = vouchersArray[indexPath.row];
    if (sourceVC.selectVoucherBlock) {
        sourceVC.selectVoucherBlock(voucher);
    }
    [self.navigationController popToViewController:sourceVC animated:YES];
}

Contoh Kerja Lain untuk Blok

Matt Price
sumber
24
Apakah kita juga harus meletakkan @class ViewControllerB;definisi @protocol di atas? Tanpa itu saya mendapatkan kesalahan "Diharapkan jenis" pada ViewControllerB di baris: - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item; dalam @protocoldeklarasi
alan-p
4
Ini sangat bagus. Seperti yang dikatakan alan-p, jangan lupa untuk menulis @class ViewControllerB; di atas protokol jika tidak Anda akan menerima kesalahan "Diharapkan tipe".
Andrew Davis
6
Anda tidak perlu delegasi untuk lewat kembali, cukup gunakan bersantai.
Malhal
4
Ketika saya meletakkan "viewControllerB.delegate = self;" di ViewControllerB saya mendapatkan kesalahan. Menetapkan ke 'id <ViewControllerBDelegate>' dari jenis yang tidak kompatibel 'ViewControllerB * const __strong', saya tidak yakin apa yang saya lakukan salah. Adakah yang bisa membantu? Plus saya harus mengubah: initWithNib -> initWithNibName.
uplearnedu.com
4
jika Anda menggunakan NavigationControllerAnda harus menggunakan [self.navigationController pushViewController:viewController animated:YES];sebagai gantinya[self pushViewController:viewControllerB animated:YES];
Nazir
192

Cepat

Ada berton-ton penjelasan di sini dan di sekitar StackOverflow, tetapi jika Anda seorang pemula hanya mencoba untuk mendapatkan sesuatu yang mendasar untuk bekerja, cobalah menonton tutorial YouTube ini (Ini yang membantu saya akhirnya mengerti bagaimana melakukannya).

Melewati data ke depan ke View Controller berikutnya

Berikut ini adalah contoh berdasarkan video. Idenya adalah untuk meneruskan string dari bidang teks di Pengendali Tampilan Pertama ke label di Pengendali Tampilan Kedua.

masukkan deskripsi gambar di sini

Buat tata letak storyboard di Interface Builder. Untuk membuat segue, Anda cukup Controlklik tombol dan seret ke Pengendali Tampilan Kedua.

Pengontrol Tampilan Pertama

Kode untuk Pengendali Tampilan Pertama adalah

import UIKit

class FirstViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!

    // This function is called before the segue
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

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

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

}

Pengendali Tampilan Kedua

Dan kode untuk Pengendali Tampilan Kedua adalah

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
    }

}

Jangan lupa

  • Hubungkan outlet untuk UITextFielddanUILabel .
  • Atur View Controllers pertama dan kedua ke file Swift yang sesuai di IB.

Melewati data kembali ke View Controller sebelumnya

Untuk meneruskan data dari pengontrol tampilan kedua ke pengontrol tampilan pertama, Anda menggunakan protokol dan delegasi . Video ini berjalan sangat jelas melalui proses itu:

Berikut ini adalah contoh berdasarkan video (dengan beberapa modifikasi).

masukkan deskripsi gambar di sini

Buat tata letak storyboard di Interface Builder. Sekali lagi, untuk membuat segue, Anda cukup Controlmenyeret dari tombol ke Pengendali Tampilan Kedua. Setel pengidentifikasi segue keshowSecondViewController . Juga, jangan lupa menghubungkan outlet dan tindakan menggunakan nama-nama dalam kode berikut.

Pengontrol Tampilan Pertama

Kode untuk Pengendali Tampilan Pertama adalah

import UIKit

class FirstViewController: UIViewController, DataEnteredDelegate {

    @IBOutlet weak var label: UILabel!

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showSecondViewController" {
            let secondViewController = segue.destination as! SecondViewController
            secondViewController.delegate = self
        }
    }

    func userDidEnterInformation(info: String) {
        label.text = info
    }
}

Perhatikan penggunaan DataEnteredDelegateprotokol khusus kami .

Pengendali dan Protokol Tampilan Kedua

Kode untuk pengontrol tampilan kedua adalah

import UIKit

// protocol used for sending data back
protocol DataEnteredDelegate: AnyObject {
    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? = nil

    @IBOutlet weak var textField: UITextField!

    @IBAction func sendTextBackButton(sender: AnyObject) {

        // call this method on whichever class implements our delegate protocol
        delegate?.userDidEnterInformation(info: textField.text!)

        // go back to the previous view controller
        _ = self.navigationController?.popViewController(animated: true)
    }
}

Perhatikan bahwa di protocolluar kelas View Controller.

Itu dia. Menjalankan aplikasi sekarang Anda harus dapat mengirim data kembali dari pengontrol tampilan kedua ke yang pertama.

Suragch
sumber
Mengingat beberapa pembaruan Swift terbaru, apakah ini masih merupakan pola umum untuk diterapkan?
piofusco
4
Sebagian besar semua pembaruan Swift yang saya lihat merupakan perubahan sintaksis yang relatif kecil, bukan perubahan dalam cara data dilewatkan di antara pengontrol tampilan. Jika saya mengetahui adanya perubahan besar seperti itu, saya akan memperbarui jawaban saya.
Suragch
2
offtopic - iOS memiliki cara jelek untuk mengirimkan parameter ke pengontrol tampilan baru, sulit dipercaya - Anda harus mengatur parameter tidak di tempat saat Anda melakukan panggilan, tetapi di beberapa tempat lain. Android memiliki pendekatan yang lebih baik dalam hal ini - ketika Anda memulai suatu Aktivitas, Anda dapat meneruskan data apa pun (yah, hampir) melalui Intentnya. Mudah. Tidak perlu dilemparkan atau sesuatu. Melewati nilai kembali ke pemanggil adalah hal yang penting juga, tidak perlu didelegasikan. Tentu saja mungkin untuk menggunakan pendekatan yang jelek juga, tidak ada masalah di sana))
Mixaz
1
@ Himanshu, pertama dapatkan referensi ke controller tampilan kedua. Kemudian perbarui variabel publik yang dikandungnya.
Suragch
8
@Madu. Saya pikir kata "delegasi" membingungkan. Biarkan saya menggunakan kata "pekerja". "Pekerja" (pengontrol tampilan pertama) melakukan apa pun yang "diperintahkan" oleh bos (pengontrol tampilan kedua). "Bos" tidak tahu siapa "pekerja" nya; bisa siapa saja. Jadi di controller tampilan pertama ("pekerja" kelas), ia mengatakan, saya akan menjadi "pekerja" Anda. Anda memberi tahu saya apa yang harus ditulis dalam label dan saya akan melakukannya untuk Anda. Dengan demikian, secondViewController.delegate = selfberarti "Saya setuju untuk menjadi pekerja bos." Lihat jawaban ini untuk contoh lain dan penjelasan lebih lanjut.
Suragch
136

M dalam MVC adalah untuk "Model" dan dalam paradigma MVC peran kelas model adalah untuk mengelola data program. Model adalah kebalikan dari tampilan - tampilan tahu cara menampilkan data, tetapi tidak tahu apa yang harus dilakukan dengan data, sedangkan model tahu segalanya tentang cara bekerja dengan data, tetapi tidak ada tentang cara menampilkannya. Model bisa rumit, tetapi tidak harus seperti itu - model untuk aplikasi Anda mungkin sesederhana serangkaian string atau kamus.

Peran pengontrol adalah memediasi antara tampilan dan model. Oleh karena itu, mereka memerlukan referensi ke satu atau lebih objek tampilan dan satu atau lebih objek model. Katakanlah model Anda adalah array kamus, dengan setiap kamus mewakili satu baris di tabel Anda. Tampilan root untuk aplikasi Anda menampilkan tabel itu, dan mungkin bertanggung jawab untuk memuat array dari file. Ketika pengguna memutuskan untuk menambahkan baris baru ke tabel, mereka mengetuk beberapa tombol dan controller Anda membuat kamus baru (bisa berubah) dan menambahkannya ke array. Untuk mengisi baris, controller membuat controller tampilan detail dan memberikan kamus baru. Pengontrol tampilan detail mengisi kamus dan kembali. Kamus sudah menjadi bagian dari model, jadi tidak ada lagi yang perlu terjadi.

Caleb
sumber
95

Ada berbagai cara dimana data dapat diterima ke kelas yang berbeda di iOS. Sebagai contoh -

  1. Inisialisasi langsung setelah alokasi kelas lain.
  2. Delegasi - untuk meneruskan data kembali
  3. Notifikasi - untuk menyiarkan data ke beberapa kelas sekaligus
  4. Menyimpan masuk NSUserDefaults - untuk mengaksesnya nanti
  5. Kelas singleton
  6. Basis data dan mekanisme penyimpanan lain seperti plist, dll.

Tetapi untuk skenario sederhana menyampaikan nilai ke kelas yang berbeda yang alokasi dilakukan di kelas saat ini, metode yang paling umum dan disukai adalah pengaturan langsung nilai setelah alokasi. Ini dilakukan sebagai berikut: -

Kita dapat memahaminya menggunakan dua pengontrol - Controller1 dan Controller2

Misalkan di kelas Controller1 Anda ingin membuat objek Controller2 dan dorong dengan nilai String yang diteruskan. Ini dapat dilakukan karena ini: -

- (void)pushToController2 {

    Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
    [obj passValue:@"String"];
    [self pushViewController:obj animated:YES];
}

Dalam implementasi kelas Controller2 akan ada fungsi ini sebagai-

@interface Controller2  : NSObject

@property (nonatomic , strong) NSString* stringPassed;

@end

@implementation Controller2

@synthesize stringPassed = _stringPassed;

- (void) passValue:(NSString *)value {

    _stringPassed = value; //or self.stringPassed = value
}

@end

Anda juga bisa langsung mengatur properti dari kelas Controller2 dengan cara yang sama seperti ini:

- (void)pushToController2 {

    Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
    [obj setStringPassed:@"String"];  
    [self pushViewController:obj animated:YES];
}

Untuk melewati beberapa nilai, Anda dapat menggunakan beberapa parameter seperti: -

Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
[obj passValue:@“String1 andValues:objArray withDate:date]; 

Atau jika Anda harus melewati lebih dari 3 parameter yang terkait dengan fitur umum, Anda dapat menyimpan nilai-nilai ke kelas Model dan meneruskan modelObject ke kelas berikutnya

ModelClass *modelObject = [[ModelClass alloc] init]; 
modelObject.property1 = _property1;
modelObject.property2 = _property2;
modelObject.property3 = _property3;

Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
[obj passmodel: modelObject];

Jadi singkatnya jika Anda ingin -

1) set the private variables of the second class initialise the values by calling a custom function and passing the values.
2) setProperties do it by directlyInitialising it using the setter method.
3) pass more that 3-4 values related to each other in some manner , then create a model class and set values to its object and pass the object using any of the above process.

Semoga ini membantu

Borncrazy
sumber
84

Setelah penelitian lebih lanjut tampak bahwa Protokol dan Delegasi adalah cara yang benar / Apple lebih suka melakukan ini.

Saya akhirnya menggunakan contoh ini

Berbagi data antara pengontrol tampilan dan objek lainnya @ iPhone Dev SDK

Bekerja dengan baik dan memungkinkan saya untuk melewatkan sebuah string dan array maju dan mundur di antara pandangan saya.

Terima kasih atas seluruh bantuan Anda

Matt Price
sumber
3
jangan gunakan protokol dan delegasi, cukup gunakan bersantai.
Malhal
1
@malhal Bagaimana jika Anda tidak menggunakan storyboard ??
Evan R
Saya benci protokol dan delegasi yang tidak berguna juga. @malhal
DawnSong
@ EvanR Anda dapat membuat dan melakukan segues dalam kode. Semuanya sama.
DawnSong
1
Intinya seluruh QA pada halaman ini adalah "dari masa lalu sebelum tampilan kontainer". Anda tidak akan pernah dalam sejuta tahun peduli dengan protokol atau delegasi sekarang. Setiap hal kecil yang Anda lakukan pada layar apa pun adalah tampilan wadah, jadi, pertanyaannya benar-benar tidak ada lagi - Anda sudah memiliki semua referensi "naik dan turun" dari semua tampilan wadah.
Fattie
66

Saya menemukan versi paling sederhana dan paling elegan dengan blok yang lewat. Mari kita beri nama view controller yang menunggu data yang dikembalikan sebagai "A" dan kembali view controller sebagai "B". Dalam contoh ini kita ingin mendapatkan 2 nilai: pertama dari Type1 dan yang kedua dari Type2.

Dengan asumsi kita menggunakan Storyboard, controller pertama menetapkan blok callback, misalnya selama persiapan segue:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.destinationViewController isKindOfClass:[BViewController class]])
    {
        BViewController *viewController = segue.destinationViewController;

        viewController.callback = ^(Type1 *value1, Type2 *value2) {
            // optionally, close B
            //[self.navigationController popViewControllerAnimated:YES];

            // let's do some action after with returned values
            action1(value1);
            action2(value2);
        };

    }
}

dan "B" view controller harus mendeklarasikan properti callback, BViewController.h:

// it is important to use "copy"
@property (copy) void(^callback)(Type1 *value1, Type2 *value2);

Daripada di file implementasi BViewController.m setelah kita menginginkan nilai untuk mengembalikan panggilan balik kita harus dipanggil:

if (self.callback)
    self.callback(value1, value2);

Satu hal yang perlu diingat adalah bahwa menggunakan blok seringkali perlu mengelola referensi yang kuat dan __weak seperti dijelaskan di sini

Leszek Zarna
sumber
Mengapa nilai tidak menjadi parameter untuk blok panggilan balik alih-alih menjadi properti yang terpisah?
Timuçin
56

Ada beberapa informasi yang baik di banyak jawaban yang diberikan, tetapi tidak ada yang menjawab pertanyaan sepenuhnya.

Pertanyaannya adalah tentang meneruskan informasi antara pengontrol tampilan. Contoh spesifik yang diberikan menanyakan tentang meneruskan informasi antar tampilan, tetapi mengingat kebaruan yang dinyatakan sendiri untuk iOS, poster asli kemungkinan dimaksudkan antara viewControllers, bukan antara view (tanpa keterlibatan dari ViewControllers). Tampaknya semua jawaban fokus pada dua pengendali tampilan, tetapi bagaimana jika aplikasi berevolusi perlu melibatkan lebih dari dua pengendali tampilan dalam pertukaran informasi?

Poster asli juga bertanya tentang Singletons dan penggunaan AppDelegate . Pertanyaan-pertanyaan ini perlu dijawab.

Untuk membantu orang lain melihat pertanyaan ini, yang menginginkan jawaban penuh, saya akan berusaha memberikannya.

Skenario Aplikasi

Alih-alih mengadakan diskusi abstrak yang sangat hipotetis, lebih baik memikirkan aplikasi konkret. Untuk membantu menentukan situasi dua-view-controller dan situasi lebih-dari-dua-view-controller, saya akan mendefinisikan dua skenario aplikasi konkret.

Skenario satu: maksimum dua pengendali tampilan yang perlu berbagi informasi. Lihat diagram satu.

diagram masalah asli

Ada dua pengendali tampilan dalam aplikasi. Ada ViewControllerA (Formulir Entri Data), dan View Controller B (Daftar Produk). Item yang dipilih dalam daftar produk harus cocok dengan item yang ditampilkan di kotak teks dalam formulir entri data. Dalam skenario ini, ViewControllerA dan ViewControllerB harus berkomunikasi langsung satu sama lain dan tidak ada pengontrol tampilan lainnya.

Skenario dua : lebih dari dua pengendali tampilan perlu berbagi informasi yang sama. Lihat diagram dua.

diagram aplikasi inventaris rumah

Ada empat pengendali tampilan dalam aplikasi. Ini adalah aplikasi berbasis tab untuk mengelola inventaris rumah. Tiga pengendali tampilan menyajikan tampilan yang disaring berbeda dari data yang sama:

  • ViewControllerA - Item Mewah
  • ViewControllerB - Item yang tidak diasuransikan
  • ViewControllerC - Seluruh Inventaris Rumah
  • ViewControllerD - Tambahkan Formulir Item Baru

Setiap kali suatu item dibuat atau diedit, item tersebut juga harus disinkronkan dengan pengontrol tampilan lainnya. Misalnya, jika kita menambahkan perahu di ViewControllerD, tetapi belum diasuransikan, maka perahu tersebut harus muncul ketika pengguna masuk ke ViewControllerA (Barang Mewah), dan juga ViewControllerC (Seluruh Perlengkapan Rumah), tetapi tidak ketika pengguna pergi ke ViewControllerB (Item Non-Tertanggung). Kita perlu khawatir tidak hanya dengan menambahkan item baru, tetapi juga menghapus item (yang mungkin diizinkan dari salah satu dari empat pengontrol tampilan), atau mengedit item yang ada (yang mungkin diizinkan dari "Tambahkan Formulir Item Baru", menggunakan kembali yang sama untuk mengedit).

Karena semua pengontrol tampilan harus berbagi data yang sama, keempat pengontrol tampilan harus tetap dalam sinkronisasi, dan oleh karena itu perlu ada semacam komunikasi dengan semua pengontrol tampilan lainnya, setiap kali pengontrol tampilan tunggal mengubah data yang mendasarinya. Seharusnya cukup jelas bahwa kita tidak ingin masing-masing pengontrol tampilan berkomunikasi secara langsung dengan masing-masing pengontrol tampilan lain dalam skenario ini. Jika tidak jelas, pertimbangkan jika kami memiliki 20 pengontrol tampilan yang berbeda (bukan hanya 4). Seberapa sulit dan rawan kesalahan untuk memberi tahu masing-masing dari 19 pengontrol tampilan lainnya setiap kali satu pengontrol tampilan melakukan perubahan?

Solusi: Delegasi dan Pola Pengamat, dan Lajang

Dalam skenario satu, kami memiliki beberapa solusi yang layak, seperti jawaban lain yang diberikan

  • segues
  • delegasi
  • mengatur properti pada pengontrol tampilan secara langsung
  • NSUserDefaults (sebenarnya pilihan yang buruk)

Dalam skenario dua, kami memiliki solusi lain yang layak:

  • Pola Pengamat
  • Lajang

Sebuah tunggal adalah turunan dari kelas, bahwa contoh menjadi satu-satunya contoh yang ada selama masa pakai baterai. Singleton mendapatkan namanya dari fakta bahwa itu adalah contoh tunggal. Biasanya pengembang yang menggunakan lajang memiliki metode kelas khusus untuk mengaksesnya.

+ (HouseholdInventoryManager*) sharedManager; {
    static dispatch_once_t onceQueue;
    static HouseholdInventoryManager* _sharedInstance;

    // dispatch_once is guaranteed to only be executed once in the
    // lifetime of the application
    dispatch_once(&onceQueue, ^{
        _sharedInstance = [[self alloc] init];
    });
    return _sharedInstance;
}

Sekarang kita mengerti apa itu singleton, mari kita bahas bagaimana singleton cocok dengan pola pengamat. Pola pengamat digunakan untuk satu objek untuk merespons perubahan oleh objek lain. Dalam skenario kedua, kami memiliki empat pengontrol tampilan yang berbeda, yang semuanya ingin tahu tentang perubahan pada data yang mendasarinya. "Data dasar" harus dimiliki oleh satu instance, singleton. "Tahu tentang perubahan" dicapai dengan mengamati perubahan yang dilakukan pada singleton.

Aplikasi inventaris rumah akan memiliki satu instance kelas yang dirancang untuk mengelola daftar item inventaris. Manajer akan mengelola koleksi barang-barang rumah tangga. Berikut ini adalah definisi kelas untuk pengelola data:

#import <Foundation/Foundation.h>

@class JGCHouseholdInventoryItem;

@interface HouseholdInventoryManager : NSObject
/*!
 The global singleton for accessing application data
 */
+ (HouseholdInventoryManager*) sharedManager;


- (NSArray *) entireHouseholdInventory;
- (NSArray *) luxuryItems;
- (NSArray *) nonInsuredItems;

- (void) addHouseholdItemToHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) editHouseholdItemInHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) deleteHoueholdItemFromHomeInventory:(JGCHouseholdInventoryItem*)item;
@end

Ketika koleksi item inventaris rumah berubah, pengontrol tampilan harus dibuat sadar akan perubahan ini. Definisi kelas di atas tidak menjelaskan bagaimana ini akan terjadi. Kita harus mengikuti pola pengamat. Pengontrol tampilan harus secara formal mengamati Manajer bersama. Ada dua cara untuk mengamati objek lain:

  • Key-Value-Observing (KVO)
  • NSNotificationCenter.

Dalam skenario dua, kami tidak memiliki properti tunggal dari HouseholdInventoryManager yang dapat diamati menggunakan KVO. Karena kami tidak memiliki satu properti yang mudah diamati, pola pengamat, dalam hal ini, harus diimplementasikan menggunakan NSNotificationCenter. Masing-masing dari empat pengontrol tampilan akan berlangganan pemberitahuan, dan Manajer bersama akan mengirim pemberitahuan ke pusat pemberitahuan bila perlu. Manajer inventaris tidak perlu mengetahui apa pun tentang pengontrol tampilan atau instance dari kelas lain yang mungkin tertarik mengetahui kapan koleksi item inventaris berubah; NSNotificationCenter menangani detail implementasi ini. View Controllers hanya berlangganan notifikasi, dan pengelola data hanya memposting notifikasi.

Banyak programmer pemula mengambil keuntungan dari kenyataan bahwa selalu ada persis satu Aplikasi Delegate di dalam masa aplikasi, yang dapat diakses secara global. Pemrogram pemula menggunakan fakta ini untuk memasukkan benda dan fungsi ke dalam appDelegate sebagai kenyamanan untuk akses dari mana saja dalam aplikasi. Hanya karena AppDelegate adalah singleton, tidak berarti harus mengganti semua lajang lainnya. Ini adalah praktik yang buruk karena menempatkan terlalu banyak beban pada satu kelas, melanggar praktik berorientasi objek yang baik. Setiap kelas harus memiliki peran yang jelas yang mudah dijelaskan, seringkali hanya dengan nama kelas.

Setiap kali Delegasi Aplikasi Anda mulai membengkak, mulailah untuk menghapus fungsionalitas menjadi lajang. Misalnya, Core Data Stack tidak boleh ditinggalkan di AppDelegate, tetapi sebaliknya harus diletakkan di kelasnya sendiri, kelas coreDataManager.

Referensi

Jason Cross
sumber
41

OP tidak menyebutkan view controller tetapi begitu banyak jawabannya, bahwa saya ingin membaur dengan apa yang beberapa fitur baru dari LLVM memungkinkan untuk membuat ini lebih mudah ketika ingin meneruskan data dari satu pengontrol tampilan ke yang lain dan kemudian mendapatkan beberapa hasil kembali.

Segues storyboard, blok ARC dan LLVM membuat ini lebih mudah bagi saya. Beberapa jawaban yang disebutkan di atas storyboard dan segues sudah tetapi masih mengandalkan delegasi. Mendefinisikan delegasi tentu berhasil tetapi beberapa orang mungkin merasa lebih mudah untuk melewatkan pointer atau blok kode.

Dengan UINavigator dan segue, ada cara mudah untuk menyampaikan informasi ke pengontrol yang tunduk dan mendapatkan kembali informasi tersebut. ARC membuat passing pointer ke hal-hal yang berasal dari NSObjects sederhana jadi jika Anda ingin pengontrol yang tunduk menambahkan / mengubah / memodifikasi beberapa data untuk Anda, berikan pointer ke instance yang dapat diubah. Blok memudahkan aksi passing, jadi jika Anda ingin pengendali bawahan memanggil aksi pada kontroler level yang lebih tinggi, berikan blok. Anda menentukan blok untuk menerima sejumlah argumen yang masuk akal bagi Anda. Anda juga dapat mendesain API untuk menggunakan banyak blok jika hal itu lebih cocok.

Berikut adalah dua contoh sepele dari lem segue. Yang pertama adalah langsung menunjukkan satu parameter dilewati untuk input, yang kedua untuk output.

// Prepare the destination view controller by passing it the input we want it to work on
// and the results we will look at when the user has navigated back to this controller's view.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    [[segue destinationViewController]

     // This parameter gives the next controller the data it works on.
     segueHandoffWithInput:self.dataForNextController

     // This parameter allows the next controller to pass back results
     // by virtue of both controllers having a pointer to the same object.
     andResults:self.resultsFromNextController];
}

Contoh kedua ini menunjukkan melewati blok panggilan balik untuk argumen kedua. Saya suka menggunakan blok karena menjaga detail yang relevan berdekatan di sumber - sumber tingkat yang lebih tinggi.

// Prepare the destination view controller by passing it the input we want it to work on
// and the callback when it has done its work.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    [[segue destinationViewController]

     // This parameter gives the next controller the data it works on.
     segueHandoffWithInput:self.dataForNextController

     // This parameter allows the next controller to pass back results.
     resultsBlock:^(id results) {
         // This callback could be as involved as you like.
         // It can use Grand Central Dispatch to have work done on another thread for example.
        [self setResultsFromNextController:results];
    }];
}
WeakPointer
sumber
41

Melewati data kembali dari ViewController 2 (tujuan) ke viewController 1 (Sumber) adalah hal yang lebih menarik. Dengan asumsi Anda menggunakan storyBoard, itulah yang saya temukan:

  • Melimpahkan
  • Pemberitahuan
  • Default pengguna
  • Singleton

Itu sudah dibahas di sini.

Saya menemukan ada lebih banyak cara:

-Menggunakan Blok panggilan balik:

gunakan dalam prepareForSeguemetode di VC1

NextViewController *destinationVC = (NextViewController *) segue.destinationViewController;
[destinationVC setDidFinishUsingBlockCallback:^(NextViewController *destinationVC)
{
    self.blockLabel.text = destination.blockTextField.text;
}];

-Menggunakan storyboard Unwind (Exit)

Menerapkan metode dengan argumen UIStoryboardSegue di VC 1, seperti ini:

-(IBAction)UnWindDone:(UIStoryboardSegue *)segue { }

Dalam storyBoard kait tombol "kembali" ke tombol Keluar hijau (Unwind) dari vc. Sekarang Anda memiliki segue yang "kembali" sehingga Anda dapat menggunakan properti destinationViewController di prepForSegue VC2 dan mengubah properti VC1 sebelum kembali.

  • Opsi lain untuk menggunakan storyboard Undwind (Exit) - Anda dapat menggunakan metode yang Anda tulis di VC1

    -(IBAction)UnWindDone:(UIStoryboardSegue *)segue {
        NextViewController *nextViewController = segue.sourceViewController;
        self.unwindLabel.text = nextViewController.unwindPropertyPass;
    } 

    Dan di prepForSegue of VC1 Anda dapat mengubah properti apa pun yang ingin Anda bagikan.

Dalam kedua opsi pelepasan, Anda dapat mengatur properti tag tombol dan memeriksanya di prepForSegue.

Semoga saya menambahkan sesuatu ke diskusi.

:) Bersulang.

Yevgeni
sumber
40

Ada beberapa metode untuk berbagi data.

  1. Anda selalu dapat berbagi data menggunakan NSUserDefaults. Tetapkan nilai yang ingin Anda bagikan sehubungan dengan kunci pilihan Anda dan dapatkan nilai dari yang NSUserDefaultterkait dengan kunci itu di pengontrol tampilan berikutnya.

    [[NSUserDefaults standardUserDefaults] setValue:value forKey:key]
    [[NSUserDefaults standardUserDefaults] objectForKey:key]
  2. Anda cukup membuat properti di viewcontrollerA. Buat objek viewcontrollerAdalam viewcontrollerBdan berikan nilai yang diinginkan ke properti itu.

  3. Anda juga dapat membuat delegasi khusus untuk ini.

Anubrata Santra
sumber
30
Tujuan khas NSUserDefaults adalah untuk menyimpan preferensi pengguna yang tetap ada di antara eksekusi aplikasi, jadi apa pun yang disimpan di sini akan tetap di sini kecuali dihapus secara eksplisit. Merupakan ide yang sangat buruk untuk menggunakan ini untuk meneruskan informasi antara pengontrol tampilan (atau objek lain) dalam suatu aplikasi.
José González
30

Jika Anda ingin meneruskan data dari satu pengontrol ke yang lain, coba kode ini

FirstViewController.h

@property (nonatomic, retain) NSString *str;

SecondViewController.h

@property (nonatomic, retain) NSString *str1;

FirstViewController.m

- (void)viewDidLoad
   {
     // message for the second SecondViewController
     self.str = @"text message";

     [super viewDidLoad];
   }

-(IBAction)ButtonClicked
 {
   SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil];
   secondViewController.str1 = str;
  [self.navigationController pushViewController:secondViewController animated:YES];
 }
pengguna2998756
sumber
29

Ini adalah jawaban yang sangat lama dan ini anti pola, silakan gunakan delegasi. Jangan gunakan Pendekatan ini !!

1. Buat instance View Controller pertama di View Controller kedua dan buat propertinya @property (nonatomic,assign).

2. Tetapkan SecondviewControllerinstance dari view controller ini.

2. Ketika Anda menyelesaikan operasi pemilihan salin array ke View Controller pertama, Ketika Anda menurunkan SecondView, FirstView akan memegang Array Data.

Semoga ini membantu.

kaar3k
sumber
2
Saya tidak percaya ini adalah cara yang benar untuk pergi karena ia menciptakan tautan yang sangat berliku antara pengontrol tampilan. Tidak terlalu melekat pada MVC.
Harga Matt
1
Jika Anda ingin secara ketat mengikuti MVC, gunakan metode NSNotificationCenter yang dapat dipanggil dari ViewControllerA ke ViewControllerB, periksa ini mungkin membantu u
kaar3k
28

Saya mencari solusi ini untuk waktu yang lama, Atlast saya menemukannya. Pertama-tama deklarasikan semua objek dalam file SecondViewController.h Anda

@interface SecondViewController: UIviewController 
{
    NSMutableArray *myAray;
    CustomObject *object;
}

Sekarang dalam file implementasi Anda mengalokasikan memori untuk objek-objek seperti ini

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
     self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
     if (self) 
     {
         // Custom initialization
         myAray=[[NSMutableArray alloc] init];
         object=[[CustomObject alloc] init];
     }
     return self;
}

Sekarang Anda telah mengalokasikan memori untuk Arraydan objek. sekarang Anda dapat mengisi memori itu sebelum mendorong iniViewController

Pergi ke SecondViewController.h Anda dan tulis dua metode

-(void)setMyArray:(NSArray *)_myArray;
-(void)setMyObject:(CustomObject *)_myObject;

dalam file implementasi Anda dapat mengimplementasikan fungsi

-(void)setMyArray:(NSArray *)_myArray
{
     [myArra addObjectsFromArray:_myArray];
}
-(void)setMyObject:(CustomObject *)_myObject
{
     [object setCustomObject:_myObject];
}

berharap bahwa Anda CustomObjectharus memiliki fungsi setter dengannya.

sekarang pekerjaan dasar Anda selesai. pergi ke tempat di mana Anda ingin mendorong SecondViewControllerdan melakukan hal-hal berikut

SecondViewController *secondView= [[SecondViewController alloc] initWithNibName:@"SecondViewController " bundle:[NSBundle MainBundle]] ;
[secondView setMyArray:ArrayToPass];
[secondView setMyObject:objectToPass];
[self.navigationController pushViewController:secondView animated:YES ];

Jaga kesalahan pengejaan.

AsifHabib
sumber
24

Ini bukan cara untuk melakukannya, Anda harus menggunakan delegasi, saya akan menganggap kami memiliki dua pengontrol tampilan ViewController1 dan ViewController2 dan hal pemeriksaan ini adalah yang pertama dan ketika keadaannya berubah, Anda ingin melakukan sesuatu di ViewController2, untuk capai itu dengan cara yang tepat, Anda harus melakukan hal berikut:

Tambahkan file baru ke file proyek Anda (Objective-C Protocol) -> Baru, sekarang beri nama ViewController1Delegate atau apa pun yang Anda inginkan dan tulis ini di antara arahan @interface dan @end.

@optional

- (void)checkStateDidChange:(BOOL)checked;

Sekarang buka ViewController2.h dan tambahkan

#import "ViewController1Delegate.h"

kemudian ubah definisi menjadi

@interface ViewController2: UIViewController<ViewController1Delegate>

Sekarang pergi ke ViewController2.m dan di dalam implementasinya tambahkan:

- (void)checkStateDidChange:(BOOL)checked {
     if (checked) {
           // Do whatever you want here
           NSLog(@"Checked");
     }
     else {
           // Also do whatever you want here
           NSLog(@"Not checked");
     }
}

Sekarang buka ViewController1.h dan tambahkan properti berikut:

@property (weak, nonatomic) id<ViewController1Delegate> delegate; 

Sekarang jika Anda membuat ViewController1 di dalam ViewController2 setelah beberapa kejadian, maka Anda harus melakukannya dengan menggunakan file NIB:

ViewController1* controller = [[NSBundle mainBundle] loadNibNamed:@"ViewController1" owner:self options:nil][0];
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];

Sekarang Anda sudah siap, setiap kali Anda mendeteksi acara cek diubah di ViewController1, yang harus Anda lakukan adalah di bawah ini

[delegate checkStateDidChange:checked]; // You pass here YES or NO based on the check state of your control

Tolong beri tahu saya jika ada sesuatu yang tidak jelas jika saya tidak memahami pertanyaan Anda dengan benar.

Boda Taljo
sumber
23

Jika Anda ingin mengirim data dari satu ke viewController lain, berikut ini caranya:

Katakanlah kita memiliki viewControllers: viewControllerA dan viewControllerB

Sekarang di viewControllerB.h

@interface viewControllerB : UIViewController {

  NSString *string;
  NSArray *array;

}

- (id)initWithArray:(NSArray)a andString:(NSString)s;

Di viewControllerB.m

#import "viewControllerB.h"

@implementation viewControllerB

- (id)initWithArray:(NSArray)a andString:(NSString)s {

   array = [[NSArray alloc] init];
   array = a;

   string = [[NSString alloc] init];
   string = s;

}

Di viewControllerA.m

#import "viewControllerA.h"
#import "viewControllerB.h"

@implementation viewControllerA

- (void)someMethod {

  someArray = [NSArray arrayWithObjects:@"One", @"Two", @"Three", nil];
  someString = [NSString stringWithFormat:@"Hahahahaha"];

  viewControllerB *vc = [[viewControllerB alloc] initWithArray:someArray andString:someString];

  [self.navigationController pushViewController:vc animated:YES];
  [vc release];

}

Jadi ini adalah bagaimana Anda dapat melewatkan data dari viewControllerA ke viewControllerB tanpa mengatur delegasi. ;)

Aniruddh Joshi
sumber
1
Saya mencoba menggunakan kode ur dalam proyek saya, tetapi saya tidak bisa mendapatkan nilai di viewcontrollerB. Bisakah Anda memberi tahu saya apa masalahnya?
X-Coder
1
@ Astitala Bisakah Anda menempelkan kode Anda dalam pertanyaan baru? Saya akan mencoba menyelesaikan masalah Anda. :)
Aniruddh Joshi
1
apakah salah menggunakan metode init, dan hanya melakukan sesuatu seperti vcB.string = @ "asdf" dari viewcontroller A?
khanh.tran.vinh
1
@ khanh.tran.vinh Bergantung pada apakah Anda menggunakan ARC atau tidak.
Aniruddh Joshi
21

Saya tahu ini adalah subjek yang dikalahkan, tetapi bagi mereka yang mencari untuk menjawab pertanyaan ini dengan miring SWIFT dan ingin contoh sederhana, di sini metode masuk-ke ​​saya untuk meneruskan data jika Anda menggunakan segue untuk berkeliling.

Ini mirip dengan di atas tetapi tanpa tombol, label dan semacamnya. Cukup dengan mengirimkan data dari satu tampilan ke tampilan berikutnya.

Siapkan Papan Cerita

Ada tiga bagian.

  1. Pengirim
  2. Segue
  3. Penerima

Ini adalah tata letak tampilan yang sangat sederhana dengan segue di antaranya.


Tata letak tampilan yang sangat sederhana.  Catatan: Tidak ada pengontrol navigasi


Ini adalah pengaturan untuk pengirim


Pengirim


Ini adalah pengaturan untuk penerima.


Penerima


Terakhir, pengaturan untuk segue.


Pengidentifikasi Segue


Lihat Pengontrol

Kami menjaga ini tetap sederhana sehingga tidak ada tombol, bukan tindakan, kami hanya memindahkan data dari pengirim ke penerima ketika aplikasi dimuat dan kemudian mengeluarkan nilai yang dikirimkan ke konsol.

Halaman ini mengambil nilai yang awalnya dimuat dan meneruskannya.

import UIKit


class ViewControllerSender: UIViewController {

    // THE STUFF - put some info into a variable
    let favoriteMovie = "Ghost Busters"

    override func viewDidAppear(animated: Bool) {
        // PASS IDENTIFIER - go to the recieving view controller.
        self.performSegueWithIdentifier("goToReciever", sender: self)
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

        //GET REFERENCE - ...to the receiver view.
        var viewControllerReceiver = segue.destinationViewController as? ViewControllerReceiver

        //PASS STUFF - pass the variable along to the target.
        viewControllerReceiver!.yourFavMovie = self.favoriteMovie

    }

}

Halaman ini hanya mengirimkan nilai variabel ke konsol saat dimuat. Pada titik ini, film favorit kami harus dalam variabel itu.

import UIKit

class ViewControllerReceiver: UIViewController {

    //Basic empty variable waiting for you to pass in your fantastic favorite movie.
    var yourFavMovie = ""

    override func viewDidLoad() {
        super.viewDidLoad()

        //And now we can view it in the console.
        println("The Movie is \(self.yourFavMovie)")

    }   
}

Itulah cara Anda dapat mengatasinya jika Anda ingin menggunakan segue dan Anda tidak memiliki halaman Anda di bawah pengontrol navigasi.

Setelah dijalankan, ia harus beralih ke tampilan penerima secara otomatis dan meneruskan nilai dari pengirim ke penerima, menampilkan nilai di konsol.

Ghost Busters adalah orang-orang klasik.

Christopher Wade Cantley
sumber
19

Dalam kasus saya, saya menggunakan kelas tunggal yang dapat berfungsi sebagai objek global yang memungkinkan akses ke data dari hampir semua bagian aplikasi. Hal pertama adalah membangun kelas singleton. Silakan merujuk ke halaman, “ Seperti apa bentuk singleton Objective-C saya? ” Dan apa yang saya lakukan untuk membuat objek dapat diakses secara global adalah hanya mengimpornya appName_Prefix.pchuntuk menerapkan pernyataan impor di setiap kelas. Untuk mengakses objek ini dan menggunakannya, saya cukup menerapkan metode kelas untuk mengembalikan instance bersama, yang berisi variabel sendiri

petershine
sumber
Ini jawaban yang benar. Cukup gunakan singleton sebagai "model". Perhatikan bahwa seperti kata Caleb "model untuk aplikasi Anda mungkin sesederhana array string" . Penting untuk dicatat bahwa melakukan singleton di Swift, benar-benar sepele . (Sangat sederhana bahkan tidak layak disebutkan di sini - hanya google.) Untuk programmer baru, perlu dipahami bahwa membuat singleton dulu benar-benar menyebalkan . Namun, lajang sangat penting untuk pemrograman iOS - semua yang dilakukan Apple adalah singleton. Itu sebabnya Apple akhirnya membuatnya trtvial (di Swift) untuk membuat lajang dengan benar.
Fattie
1
Perhatikan, bagaimanapun, bahwa hari ini (2016+) "semuanya adalah tampilan wadah di iOS". Setiap hal yang Anda lakukan di layar membuat tampilan wadah kecil. Cukup sepele untuk mendapatkan referensi "naik turun" rantai pandangan kontainer (meskipun Apple akan membuat itu lebih mudah di masa depan), dan Anda tetap melakukannya untuk hampir setiap tampilan wadah. Jadi, jika Anda tetap melakukannya - Anda punya jawabannya; tidak perlu untuk seorang lajang. Intro view container ... stackoverflow.com/a/23403979/294884
Fattie
19

Cepat 5

Yah Matt Price's Answer baik-baik saja untuk meneruskan data tetapi saya akan menulis ulang, dalam versi Swift Terbaru karena saya percaya programmer baru menemukan itu berhenti menantang karena Sintaks dan metode / kerangka kerja baru, seperti posting asli di Objective-C.

Ada beberapa opsi untuk Passing Data antara View Controllers.

  1. Menggunakan Push Pengontrol Navigasi
  2. Menggunakan Segue
  3. Menggunakan Delegasi
  4. Menggunakan Pengamat Notifikasi
  5. Menggunakan Blok

Saya akan menulis ulang logikanya dalam Swift dengan Kerangka iOS terbaru


Melewati Data melalui Push Pengontrol Navigasi : Dari ViewControllerA ke ViewControllerB

Langkah 1. Deklarasikan variabel di ViewControllerB

var isSomethingEnabled = false

Langkah 2. Cetak Variabel dalam metode ViewDidLoad ViewControllerB

override func viewDidLoad() {
        super.viewDidLoad()
        //Print value received through segue, navigation push
        print("Value of 'isSomethingEnabled' from ViewControllerA : ", isSomethingEnabled)
    }

Langkah 3. Di ViewControllerA Lulus Data sambil mendorong melalui Pengontrol Navigasi

if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
        viewControllerB.isSomethingEnabled = true
        if let navigator = navigationController {
            navigator.pushViewController(viewControllerB, animated: true)
        }
    }

Jadi di sini adalah kode lengkap untuk:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //MARK:Passing Data through Navigation PushViewController
    @IBAction func goToViewControllerB(_ sender: Any) {

        if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
            viewControllerB.isSomethingEnabled = true
            if let navigator = navigationController {
                navigator.pushViewController(viewControllerB, animated: true)
            }
        }
    }
}

ViewControllerB

import UIKit

class ViewControllerB: UIViewController {

    //MARK:  - Variable for Passing Data through Navigation push   
    var isSomethingEnabled = false

    override func viewDidLoad() {
        super.viewDidLoad()
        //Print value received through navigation push
        print("Value of 'isSomethingEnabled' from ViewControllerA : ", isSomethingEnabled)
    }
}

Melewati Data melalui Segue : Dari ViewControllerA ke ViewControllerB

Langkah 1. Buat Segue dari ViewControllerA ke ViewControllerB dan berikan Identifier = showDetailSegue di Storyboard seperti yang ditunjukkan di bawah ini

masukkan deskripsi gambar di sini

Langkah 2. Di ViewControllerB Deklarasikan yang layak bernama isSomethingEnabled dan cetak nilainya.

Langkah 3. Di PassControllerA pass adalah nilai sesuatuSomethingEnabled saat melewati Segue

Jadi di sini adalah kode lengkap untuk:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //MARK:  - - Passing Data through Segue  - - 
    @IBAction func goToViewControllerBUsingSegue(_ sender: Any) {
        performSegue(withIdentifier: "showDetailSegue", sender: nil)
    }

    //Segue Delegate Method
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (segue.identifier == "showDetailSegue") {
            let controller = segue.destination as? ViewControllerB
            controller?.isSomethingEnabled = true//passing data
        }
    }
}

ViewControllerB

import UIKit

class ViewControllerB: UIViewController {
    var isSomethingEnabled = false

    override func viewDidLoad() {
        super.viewDidLoad()
        //Print value received through segue
        print("Value of 'isSomethingEnabled' from ViewControllerA : ", isSomethingEnabled)
    }
}

Melewati Data melalui Delegasi : Dari ViewControllerB ke ViewControllerA

Langkah 1. Deklarasikan Protokol ViewControllerBDelegate dalam file ViewControllerB tetapi di luar kelas

protocol ViewControllerBDelegate: NSObjectProtocol {

    // Classes that adopt this protocol MUST define
    // this method -- and hopefully do something in
    // that definition.
    func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?)
}

Langkah 2. Mendeklarasikan instance variabel Delegasi di ViewControllerB

var delegate: ViewControllerBDelegate?

Langkah 3. Kirim data untuk didelegasikan di dalam metode viewDidLoad dari ViewControllerB

delegate?.addItemViewController(self, didFinishEnteringItem: "Data for ViewControllerA")

Langkah 4. Konfirmasikan ViewControllerBDelegate di ViewControllerA

class ViewControllerA: UIViewController, ViewControllerBDelegate  {
// to do
}

Langkah 5. Konfirmasikan bahwa Anda akan menerapkan delegasi di ViewControllerA

if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
            viewControllerB.delegate = self//confirming delegate
            if let navigator = navigationController {
                navigator.pushViewController(viewControllerB, animated: true)
            }
        }

Langkah 6. Terapkan metode delegasi untuk menerima data di ViewControllerA

func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?) {
        print("Value from ViewControllerB's Delegate", item!)
    }

Jadi di sini adalah kode lengkap untuk:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController, ViewControllerBDelegate  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //Delegate method
    func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?) {
        print("Value from ViewControllerB's Delegate", item!)
    }

    @IBAction func goToViewControllerForDelegate(_ sender: Any) {

        if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
            viewControllerB.delegate = self
            if let navigator = navigationController {
                navigator.pushViewController(viewControllerB, animated: true)
            }
        }
    }
}

ViewControllerB

import UIKit

//Protocol decleare
protocol ViewControllerBDelegate: NSObjectProtocol {
    // Classes that adopt this protocol MUST define
    // this method -- and hopefully do something in
    // that definition.
    func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?)
}

class ViewControllerB: UIViewController {
    var delegate: ViewControllerBDelegate?

    override func viewDidLoad() {
        super.viewDidLoad()
        //MARK:  - - - -  Set Data for Passing Data through Delegate  - - - - - -
        delegate?.addItemViewController(self, didFinishEnteringItem: "Data for ViewControllerA")
    }
}

Melewati Data melalui Pengamat Pemberitahuan : Dari ViewControllerB ke ViewControllerA

Langkah 1. Setel dan Posting data dalam Pengamat pemberitahuan di ViewControllerB

let objToBeSent = "Test Message from Notification"
        NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: objToBeSent)

Langkah 2. Tambahkan Pengamat Pemberitahuan di ViewControllerA

NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)

Langkah 3. Terima nilai data Notifikasi di ViewControllerA

@objc func methodOfReceivedNotification(notification: Notification) {
        print("Value of notification : ", notification.object ?? "")
    }

Jadi di sini adalah kode lengkap untuk:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController{

    override func viewDidLoad() {
        super.viewDidLoad()

        // add observer in controller(s) where you want to receive data
        NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)
    }

    //MARK: Method for receiving Data through Post Notification 
    @objc func methodOfReceivedNotification(notification: Notification) {
        print("Value of notification : ", notification.object ?? "")
    }
}

ViewControllerB

import UIKit

class ViewControllerB: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        //MARK:Set data for Passing Data through Post Notification
        let objToBeSent = "Test Message from Notification"
        NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: objToBeSent)
    }
}

Melewati Data melalui Blok : Dari ViewControllerB ke ViewControllerA

Langkah 1. Deklarasikan blok di ViewControllerB

var authorizationCompletionBlock: ((Bool) -> ())? = {_ in}

Langkah 2. Atur data dalam blok di ViewControllerB

if authorizationCompletionBlock != nil
        {
            authorizationCompletionBlock!(true)
        }

Langkah 3. Terima data blok di ViewControllerA

//Receiver Block
                controller!.authorizationCompletionBlock = { isGranted in
                    print("Data received from Block is :", isGranted)
                }

Jadi di sini adalah kode lengkap untuk:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //MARK:Method for receiving Data through Block
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if (segue.identifier == "showDetailSegue") {
                let controller = segue.destination as? ViewControllerB
                controller?.isSomethingEnabled = true

                //Receiver Block
                controller!.authorizationCompletionBlock = { isGranted in
                    print("Data received from Block is :", isGranted)
                }
            }
        }
}

ViewControllerB

import UIKit

class ViewControllerB: UIViewController {

    //MARK:Variable for Passing Data through Block
    var authorizationCompletionBlock:((Bool)->())? = {_ in}

    override func viewDidLoad() {
        super.viewDidLoad()

        //MARK:Set data for Passing Data through Block
        if authorizationCompletionBlock != nil
        {
            authorizationCompletionBlock!(true)
        }
    }
}

Anda dapat menemukan contoh aplikasi lengkap di GitHub saya. Mohon beri tahu saya jika ada pertanyaan tentang ini.

swiftBoy
sumber
18

Melewati Data antara FirstViewController ke SecondViewController seperti di bawah ini

Sebagai contoh:

Nilai FirstViewController String sebagai

StrFirstValue = @"first";

jadi kita bisa meneruskan nilai ini di kelas dua menggunakan langkah di bawah ini

1> Kita perlu membuat objek string dalam file SecondViewController.h

NSString *strValue;

2> Perlu mendeklarasikan properti seperti di bawah ini deklarasi dalam file .h

@property (strong, nonatomic)  NSString *strSecondValue;

3> Perlu mensintesis nilai tersebut dalam file FirstViewController.m di bawah deklarasi header

@synthesize strValue;

dan di FirstViewController.h:

@property (strong, nonatomic)  NSString *strValue;

4> Di FirstViewController, Dari metode mana kita menavigasi ke tampilan kedua, silakan tulis kode di bawah ini dalam metode itu.

SecondViewController *secondView= [[SecondViewController alloc]     
initWithNibName:@"SecondViewController " bundle:[NSBundle MainBundle]];

[secondView setStrSecondValue:StrFirstValue];

[self.navigationController pushViewController:secondView animated:YES ];
Chris Alan
sumber
Setelah berada di SecondViewController, bagaimana Anda meneruskan data kembali ke FirstViewController?
Bruno
18

Saat ini saya berkontribusi pada solusi open source untuk masalah ini melalui proyek bernama MCViewFactory, yang dapat ditemukan di sini:

https://github.com/YetiHQ/manticore-iosviewfactory

Idenya adalah meniru paradigma niat Android, menggunakan pabrik global untuk mengelola tampilan mana yang Anda lihat dan menggunakan "niat" untuk beralih dan meneruskan data di antara tampilan. Semua dokumentasi ada di halaman github, tetapi di sini ada beberapa highlight:

Anda mengatur semua tampilan Anda dalam file .XIB dan mendaftarkannya dalam delegasi aplikasi, sambil menginisialisasi pabrik.

// Register activities

MCViewFactory *factory = [MCViewFactory sharedFactory];

// the following two lines are optional. 
[factory registerView:@"YourSectionViewController"]; 

Sekarang, di VC Anda, kapan pun Anda ingin pindah ke VC baru dan meneruskan data, Anda membuat maksud baru dan menambahkan data ke kamusnya (saveInstanceState). Kemudian, cukup tetapkan maksud pabrik saat ini:

MCIntent* intent = [MCIntent intentWithSectionName:@"YourSectionViewController"];
[intent setAnimationStyle:UIViewAnimationOptionTransitionFlipFromLeft];
[[intent savedInstanceState] setObject:@"someValue" forKey:@"yourKey"];
[[intent savedInstanceState] setObject:@"anotherValue" forKey:@"anotherKey"];
// ...
[[MCViewModel sharedModel] setCurrentSection:intent];

Semua pandangan Anda yang sesuai dengan ini haruslah subclass dari MCViewController, yang memungkinkan Anda mengganti metode onResume: yang baru, yang memungkinkan Anda mengakses data yang telah Anda lewati.

-(void)onResume:(MCIntent *)intent {
    NSObject* someValue = [intent.savedInstanceState objectForKey:@"yourKey"];
    NSObject* anotherValue = [intent.savedInstanceState objectForKey:@"anotherKey"];

    // ...

    // ensure the following line is called, especially for MCSectionViewController
    [super onResume:intent];
}

Semoga sebagian dari Anda menemukan solusi ini bermanfaat / menarik.


sumber
Lalu semua objek pengontrol bisa mendapatkan / mengatur semua kamus terdaftar dalam lingkup apa pun? Catat ini.
Itachi
15

Buat properti selanjutnya view controller .hdan tentukan pengambil dan penyetel.

Tambahkan ini propertydi NextVC.h di nextVC

@property (strong, nonatomic) NSString *indexNumber;

Menambahkan

@synthesize indexNumber; dalam NextVC.m

Dan terakhir

NextVC *vc=[[NextVC alloc]init];

vc.indexNumber=@"123";

[self.navigationController vc animated:YES];
Vivek Yadav
sumber
11

Ada banyak cara untuk melakukan ini dan penting untuk memilih yang tepat. Mungkin salah satu keputusan arsitektur terbesar terletak pada bagaimana kode model akan dibagikan atau diakses di seluruh aplikasi.

Saya menulis posting blog tentang ini beberapa waktu lalu: Berbagi Model Kode . Berikut ringkasan singkatnya:

Data bersama

Salah satu pendekatan adalah untuk membagikan pointer ke objek model antara pengontrol tampilan.

  • Lakukan iterasi kasar pada pengontrol tampilan (di Navigasi atau Pengontrol Tab Bar) untuk mengatur data
  • Setel data dalam prepForSegue (jika storyboard) atau init (jika terprogram)

Karena bersiap untuk segue adalah yang paling umum di sini adalah contoh:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    var next = segue.destinationViewController as NextViewController
    next.dataSource = dataSource
}

Akses independen

Pendekatan lain adalah dengan menangani layar penuh data pada suatu waktu dan alih-alih menyambungkan pengontrol tampilan satu sama lain, masing-masing pasangan pengontrol tampilan ke sumber data tunggal yang dapat mereka peroleh secara mandiri.

Cara paling umum yang pernah saya lihat dilakukan adalah contoh tunggal . Jadi, jika objek singleton DataAccessAnda, Anda bisa melakukan hal berikut dalam metode viewDidLoad dari UIViewController:

func viewDidLoad() {
    super.viewDidLoad()
    var data = dataAccess.requestData()
}

Ada alat tambahan yang juga membantu meneruskan data:

  • Mengamati Nilai-Kunci
  • NSNotification
  • Data Inti
  • NSFetchedResultsController
  • Sumber data

Data Inti

Hal yang menyenangkan tentang Core Data adalah bahwa ia memiliki hubungan terbalik. Jadi, jika Anda hanya ingin memberikan NotesViewController objek catatan Anda bisa karena itu akan memiliki hubungan terbalik dengan sesuatu yang lain seperti notebook. Jika Anda membutuhkan data pada buku catatan di NotesViewController Anda dapat berjalan mundur grafik objek dengan melakukan hal berikut:

let notebookName = note.notebook.name

Baca lebih lanjut tentang ini di posting blog saya: Berbagi Model Kode

Korey Hinton
sumber
10

NewsViewController

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
  [tbl_View deselectRowAtIndexPath:indexPath animated:YES];
  News *newsObj = [newstitleArr objectAtIndex:indexPath.row];
  NewsDetailViewController *newsDetailView = [[NewsDetailViewController alloc] initWithNibName:@"NewsDetailViewController" bundle:nil];

  newsDetailView.newsHeadlineStr = newsObj.newsHeadline;

  [self.navigationController pushViewController:newsDetailView animated:YES];
}

NewsDetailViewController.h

@interface NewsDetailViewController : UIViewController
@property(nonatomic,retain) NSString *newsHeadlineStr;
@end

NewsDetailViewController.m

@synthesize newsHeadlineStr;
Mohsin Sabasara
sumber
10

Delegasi adalah satu-satunya solusi untuk melakukan operasi seperti itu ketika Anda menggunakan file .xib namun semua jawaban yang dijelaskan di atas adalah untuk storyboardfile .xib yang Anda butuhkan untuk menggunakan delegasi. itu hanya solusi yang Anda bisa.

Solusi lain adalah menggunakan pola kelas tunggal menginisialisasi sekali dan menggunakannya di seluruh aplikasi Anda.

pengguna2786888
sumber
10

jika Anda ingin meneruskan data dari ViewControlerOne ke ViewControllerTwo coba ini ..

lakukan ini di ViewControlerOne.h

 @property (nonatomic, strong) NSString *str1;

lakukan ini di ViewControllerTwo.h

 @property (nonatomic, strong) NSString *str2;

Mensintesis str2 di ViewControllerTwo.m

@interface ViewControllerTwo ()
@end
@implementation ViewControllerTwo
@synthesize str2;

lakukan ini di ViewControlerOne.m

 - (void)viewDidLoad
 {
   [super viewDidLoad];

  // Data or string you wants to pass in ViewControllerTwo..
  self.str1 = @"hello world";

 }

pada acara klik tombol lakukan ini ..

-(IBAction)ButtonClicked
{ //Navigation on buttons click event from ViewControlerOne to ViewControlerTwo with transferring data or string..
  ViewControllerTwo *objViewTwo=[self.storyboard instantiateViewControllerWithIdentifier:@"ViewControllerTwo"];
  obj.str2=str1;
  [self.navigationController pushViewController: objViewTwo animated:YES];
}

lakukan ini di ViewControllerTwo.m

- (void)viewDidLoad
{
 [super viewDidLoad];
  NSLog(@"%@",str2);
}
krushnsinh
sumber
10

Anda dapat menyimpan data dalam delegasi Aplikasi untuk mengaksesnya di seluruh pengontrol tampilan di aplikasi Anda. Yang harus Anda lakukan adalah membuat instance bersama delegasi aplikasi

AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;

Sebagai contoh

jika Anda mendeklarasikan a NSArray object *arrayXYZmaka Anda dapat mengaksesnya di sembarang pengontrol tampilan olehappDelegate.arrayXYZ

ak_tyagi
sumber
Ini adalah metode pilihan untuk hackathon
Hai Feng Kao
9

Jika Anda ingin mengirim data dari satu ke viewController lain, berikut ini caranya:

Katakanlah kita memiliki viewControllers: ViewController dan NewViewController.

di ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
{
    IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;
}

@property (nonatomic,retain) IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;

-(IBAction)goToNextScreen:(id)sender;

@end

di ViewController.m

#import "ViewController.h"

#import "NewViewController.h"

@implementation ViewController
@synthesize mytext1,mytext2,mytext3,mytext4;

-(IBAction)goToNextScreen:(id)sender
{
    NSArray *arr = [NSArray arrayWithObjects:mytext1.text,mytext2.text,mytext3.text,mytext4.text, nil];


    NewViewController *newVc = [[NewViewController alloc] initWithNibName:@"NewViewController" bundle:nil];

    newVc.arrayList = arr;

    [self.navigationController pushViewController:newVc animated:YES];

}

Di NewViewController.h

#import <UIKit/UIKit.h>

@interface NewViewController : UITableViewController
{
    NSArray *arrayList;

    NSString *name,*age,*dob,*mobile;

}

@property(nonatomic, retain)NSArray *arrayList;

@end

Di NewViewController.m

#import "NewViewController.h"

#import "ViewController.h"

@implementation NewViewController
@synthesize arrayList;

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

    // Return the number of sections.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

    // Return the number of rows in the section.
    return [arrayList count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil)
    {
         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];      
    }
    // Configure the cell...
    cell.textLabel.text = [arrayList objectAtIndex:indexPath.row];
    return cell;


}

@end

Jadi dengan cara ini kita dapat meneruskan data dari satu viewcontroller ke controller tampilan lain ...

Sabs
sumber
8

Saya suka gagasan objek Model dan objek tiruan berdasarkan NSProxy untuk melakukan atau membuang data jika apa yang dipilih pengguna dapat dibatalkan.

Sangat mudah untuk menyampaikan data karena ini adalah satu objek atau beberapa objek dan jika Anda memiliki katakanlah pengontrol UINavigationController, Anda dapat menyimpan referensi ke model di dalam dan semua pengontrol tampilan terdorong dapat mengaksesnya langsung dari pengontrol navigasi.

Ben Sinclair
sumber
8

Saya telah melihat banyak orang yang memperumit masalah ini menggunakan didSelectRowAtPathmetode ini. Saya menggunakan Data Inti dalam contoh saya.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

    //this solution is for using Core Data
    YourCDEntityName * value = (YourCDEntityName *)[[self fetchedResultsController] objectAtIndexPath: indexPath];

    YourSecondViewController * details = [self.storyboard instantiateViewControllerWithIdentifier:@"nameOfYourSecondVC"];//make sure in storyboards you give your second VC an identifier

    //Make sure you declare your value in the second view controller
    details.selectedValue = value;

    //Now that you have said to pass value all you need to do is change views
    [self.navigationController pushViewController: details animated:YES];

}

4 baris kode di dalam metode dan Anda selesai.

App Dev Guy
sumber
6

Ada banyak jawaban untuk pertanyaan ini yang menawarkan banyak cara berbeda untuk melakukan komunikasi pengontrol tampilan yang memang akan berhasil, tetapi saya tidak melihat di mana pun disebutkan mana yang sebenarnya terbaik untuk digunakan dan mana yang harus dihindari.

Dalam praktiknya, menurut saya hanya beberapa solusi yang disarankan:

  • Untuk meneruskan data:
    • timpa prepare(for:sender:)metode UIViewControllerketika menggunakan storyboard dan segues
    • meneruskan data melalui penginisialisasi atau melalui properti ketika melakukan transisi pengontrol tampilan melalui kode
  • Untuk meneruskan data ke belakang
    • perbarui status aplikasi bersama (yang dapat Anda sampaikan ke depan antara pengontrol tampilan dengan salah satu metode di atas)
    • gunakan delegasi
    • gunakan segue bersantai

Solusi Saya sarankan untuk TIDAK menggunakan:

  • Merujuk pengontrol sebelumnya secara langsung daripada menggunakan delegasi
  • Berbagi data melalui singleton
  • Melewati data melalui delegasi aplikasi
  • Berbagi data melalui default pengguna
  • Melewati data melalui pemberitahuan

Solusi ini, meskipun bekerja dalam jangka pendek, memperkenalkan terlalu banyak dependensi yang akan merusak arsitektur aplikasi dan membuat lebih banyak masalah nanti.

Bagi mereka yang tertarik, saya menulis beberapa artikel yang membahas poin-poin ini lebih dalam dan menyoroti berbagai kelemahan:

Matteo Manferdini
sumber