Görünüm Denetleyicileri Arasında Veri Aktarma


1372

İOS ve Objective-C ve tüm MVC paradigmasında yeniyim ve aşağıdakilere takılı kaldım:

Bir veri giriş formu gibi davranan bir görünüm var ve kullanıcıya birden fazla ürün seçme seçeneği vermek istiyorum. Ürünler a ile başka bir görünümde listelenir UITableViewControllerve birden fazla seçimi etkinleştirdim.

Sorum şu: Verileri bir görünümden diğerine nasıl aktarabilirim? Seçimleri UITableViewbir dizide tutuyor olacak , ama daha sonra nasıl bir önceki veri giriş formu görünümüne geri iletmek böylece diğer verilerin yanı sıra formun sunulması Core Data için kaydedilebilir?

Etrafta dolaştım ve bazı kişilerin uygulama temsilcisinde bir dizi bildirdiklerini gördüm. Singletons hakkında bir şeyler okudum ama bunların ne olduğunu anlamadım ve veri modeli oluşturma hakkında bir şeyler okudum.

Bunu yapmanın doğru yolu ne olurdu ve nasıl devam edeceğim?

Yanıtlar:


1683

Bu soru burada stackoverflow üzerinde çok popüler gibi görünüyor, bu yüzden benim gibi iOS dünyasında başlayan insanlara yardımcı olmak için daha iyi bir cevap vereceğimi düşündüm.

Umarım bu cevap insanların anlaması için yeterince açıktır ve hiçbir şeyi kaçırmadım.

Verileri İletme

Verileri başka bir görünüm denetleyicisinden bir görünüm denetleyicisine iletme. Bir nesneyi / değeri bir görünüm denetleyicisinden başka bir görünüm denetleyicisine bir gezinme yığınına ilettiğinizde geçirmek isterseniz bu yöntemi kullanırsınız.

Bu örnek için, biz sahip olacak ViewControllerAveViewControllerB

Bir geçmek için BOOLdeğeri ViewControllerAiçin ViewControllerBbiz aşağıdakileri yapardı.

  1. içinde ViewControllerB.hiçin bir özellik oluşturunBOOL

    @property (nonatomic, assign) BOOL isSomethingEnabled;
  2. içinde ViewControllerAbunu söylememe gerek yaklaşık ViewControllerBböylece kullanmak

    #import "ViewControllerB.h"

    Sonra görünümü yüklemek istediğiniz yere örn. didSelectRowAtIndexveya bazılarını nav yığınına itmeden önce IBActionayarlamanız gerekir ViewControllerB.

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

    Bu ayarlar isSomethingEnablediçinde ViewControllerBhiç BOOLdeğer YES.

Segues Kullanarak Veri İletme

Storyboard'lar kullanıyorsanız, büyük olasılıkla segues kullanıyorsunuz ve verileri iletmek için bu prosedüre ihtiyacınız olacak. Bu yukarıdakine benzer, ancak görünüm denetleyicisini itmeden önce verileri iletmek yerine,

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

Yani bir geçmesine BOOLgelen ViewControllerAetmek ViewControllerBaşağıdakileri yapacağını biz:

  1. içinde ViewControllerB.hiçin bir özellik oluşturunBOOL

    @property (nonatomic, assign) BOOL isSomethingEnabled;
  2. içinde ViewControllerAbunu söylememe gerek yaklaşık ViewControllerBböylece kullanmak

    #import "ViewControllerB.h"
  3. Bir segue oluşturma ViewControllerAiçin ViewControllerBfilm şeridinde ve ona bir tanımlayıcı vermek, bu örnekte biz arayalım"showDetailSegue"

  4. Daha sonra, ViewControllerAherhangi bir segue gerçekleştirildiğinde çağrılan yöntemi eklememiz gerekir , bu nedenle hangi segue'in çağrıldığını tespit etmeli ve sonra bir şeyler yapmalıyız. Örneğimizde kontrol edeceğiz "showDetailSegue"ve eğer yapılırsa BOOLdeğerimiziViewControllerB

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

    Görüşlerinizi bir gezinti denetleyicisine yerleştirdiyseniz, yukarıdaki yöntemi hafifçe aşağıdakilere değiştirmeniz gerekir

    -(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;
        }
    }
    

    Bu ayarlar isSomethingEnablediçinde ViewControllerBhiç BOOLdeğer YES.

Verilerin Geri Verilmesi

Verileri geri aktarmak ViewControllerBiçin Protokoller ve Delegeler veya Bloklar'ıViewControllerA kullanmanız gerekir , ikincisi geri aramalar için gevşek bağlı bir mekanizma olarak kullanılabilir.

Bunu yapmak için ViewControllerAbir temsilci yapacağız ViewControllerB. Bu, verileri geri göndermemizi sağlayan ViewControllerBbir mesaj göndermemizi sağlar ViewControllerA.

For ViewControllerAolmak bir temsilci ViewControllerBbuna uygun olmalıdır ViewControllerBbiz belirtmek zorunda bireyin protokolü. Bu, ViewControllerAhangi yöntemleri uygulaması gerektiğini söyler .

  1. Bölümünde ViewControllerB.h, #importancak altında @interface, protokolü belirtirsiniz.

    @class ViewControllerB;
    
    @protocol ViewControllerBDelegate <NSObject>
    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
    @end
    
  2. daha sonra hala ViewControllerB.hbir delegatemülk kurmanız veViewControllerB.m

    @property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
  3. Burada görünüm denetleyicisini ne zaman açtığımız hakkında ViewControllerBbir mesaj çağırıyoruz delegate.

    NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
    [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
    
  4. Bunun için ViewControllerB. Şimdi de ViewControllerA.h, anlatmak ViewControllerAithalat ViewControllerBve protokole uygundur.

    #import "ViewControllerB.h"
    
    @interface ViewControllerA : UIViewController <ViewControllerBDelegate>
    
  5. In ViewControllerA.mour protokolden aşağıdaki yöntemi uygulamak

    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
    {
        NSLog(@"This was returned from ViewControllerB %@",item);
    }
    
  6. viewControllerBNavigasyon yığınına geçmeden önce bunun temsilci ViewControllerBolduğunu söylemeliyiz ViewControllerA, aksi takdirde bir hata alırız.

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

Referanslar

  1. Yetki özelliğini kullanarak diğer Görünüm Kontrolörleri ile iletişim kurmak için de View Controller Kılavuzu Programlama
  2. Temsilci Deseni

NS Bildirim merkezi Veri aktarmanın başka bir yolu.

// 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];

Verileri bir sınıftan diğerine geri verme (Sınıf herhangi bir denetleyici, Ağ / oturum yöneticisi, UIView alt sınıfı veya başka bir sınıf olabilir)

Bloklar anonim işlevlerdir.

Bu örnek, veri geçer Kontrol B için Kontrol A

bir blok tanımla

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

bir değere ihtiyacınız olduğunda blok işleyici (dinleyici) ekleyin (örneğin ControllerA'da API yanıtınıza veya A'da ContorllerB verilerine ihtiyacınız vardır)

// in ContollerA.m

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

Denetleyici B'ye gidin

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

yangın bloğu

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

Bloklar için Başka Bir Çalışma Örneği


24
Ayrıca @class ViewControllerB;@protocol tanımının üstüne koymamız gerekiyor mu? Onsuz satırda ViewControllerB bir "Beklenen tip" hatası alıyorum: bildirimi - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item; içinde@protocol
alan-p

4
Harika çalışıyor. Alan-p'nin dediği gibi @class ViewControllerB yazmayı unutmayın; aksi takdirde "Beklenen bir tür" hatası alırsınız.
Andrew Davis

6
geri dönmek için delegelere ihtiyacınız yok, sadece gevşeyin.
malhal

4
"ViewControllerB.delegate = self;" ViewControllerB bir hata alıyorum. 'ViewControllerB * const __strong' ile uyumlu olmayan türden 'id <ViewControllerBDelegate>' öğesine atadığımda, ne yaptığımı bilmiyorum. Biri yardım edebilir mi? Artı değiştirmek zorunda kaldım: initWithNib -> initWithNibName.
2014

4
Eğer kullanıyorsanız NavigationControllerkullanmak zorunda [self.navigationController pushViewController:viewController animated:YES];yerine[self pushViewController:viewControllerB animated:YES];
Nazir

192

hızlı

StackOverflow'un burada ve çevresinde tonlarca ton açıklama var, ancak yeni başlayan bir iş için temel bir şey elde etmeye çalışıyorsanız, bu YouTube eğiticisini izlemeyi deneyin (Nihayet nasıl yapılacağını anlamama yardımcı olan şey budur).

Verileri bir sonraki Görünüm Denetleyicisine iletme

Aşağıdaki videoyu temel alan bir örnektir. Fikir, First View Controller'daki metin alanından Second View Controller'daki etikete bir dize geçirmektir.

resim açıklamasını buraya girin

Arayüz Oluşturucu'da film şeridi düzenini oluşturun. Segue yapmak için, sadece Controldüğmeye tıklayın ve İkinci Görünüm Denetleyicisine sürükleyin.

İlk Görüş Kontrolörü

İlk Görünüm Denetleyicisinin kodu:

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!
    }

}

İkinci Görünüm Kontrol Cihazı

Ve İkinci Görünüm Kontrolörünün kodu

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
    }

}

Unutma

  • İçin çıkışları bağlayın UITextFieldve UILabel.
  • Birinci ve ikinci Görünüm Denetleyicilerini IB'deki uygun Swift dosyalarına ayarlayın.

Verileri önceki View Controller'a geri aktarma

Verileri ikinci görünüm denetleyicisinden ilk görünüm denetleyicisine aktarmak için bir protokol ve bir temsilci kullanırsınız . Bu video, bu işlemle birlikte çok net bir yürüyüş:

Aşağıdaki videoyu temel alan bir örnektir (birkaç değişiklikle).

resim açıklamasını buraya girin

Arayüz Oluşturucu'da film şeridi düzenini oluşturun. Yine, segue yapmak için Controldüğmeden İkinci Görünüm Denetleyicisine sürükleyin. Segue tanımlayıcısını olarak ayarlayın showSecondViewController. Ayrıca, çıkışları ve eylemleri aşağıdaki koddaki adları kullanarak bağlamayı unutmayın.

İlk Görüş Kontrolörü

İlk Görünüm Denetleyicisinin kodu:

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
    }
}

Özel DataEnteredDelegateprotokolümüzün kullanımına dikkat edin .

İkinci Görünüm Kontrolörü ve Protokolü

İkinci görünüm denetleyicisinin kodu:

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)
    }
}

protocolGörünüm Denetleyicisi sınıfının dışında olduğunu unutmayın .

Bu kadar. Uygulamayı şimdi çalıştırdığınızda, verileri ikinci görünüm denetleyicisinden ilkine geri gönderebilmeniz gerekir.


En son Swift güncellemelerinden bazıları göz önüne alındığında, bu hala uygulanması yaygın bir kalıp mı?
piofusco

4
Gördüğüm Swift güncellemelerinin çoğu, görünüm denetleyicileri arasında verilerin aktarılma biçimindeki değişiklikler değil, nispeten küçük sözdizimsel değişiklikler oldu. Böyle büyük değişiklikler öğrenirsem cevabımı güncelleyeceğim.
Suresi

2
offtopic - iOS'un parametreleri yeni görünüm denetleyicilerine iletmenin çok çirkin bir yolu var, inanılmaz - parametreleri arama yaparken bir yerde değil, başka bir yerde ayarlamanız gerekiyor. Android bu konuda daha iyi bir yaklaşıma sahiptir - bir Etkinliğe başladığınızda, herhangi bir veriyi (neredeyse, başlangıç ​​Niyeti) iletebilirsiniz. Kolay. Dökmeye gerek yok falan. Dönüş değerlerini arayana geri vermek de önemli bir şeydir, temsilci seçmeye gerek yoktur. Tabii ki de çirkin yaklaşımlar kullanmak mümkün, sorun yok))
Mixaz

1
@Himanshu, önce ikinci görünüm denetleyicisine bir referans alın. Ardından içerdiği genel değişkeni güncelleyin.
Suresi

8
@Bal. "Delege" kelimesinin kafa karıştırıcı olduğunu düşünüyorum. "İşçi" kelimesini kullanayım. "İşçi" (ilk görünüm denetleyicisi), "patron" (ikinci görünüm denetleyicisi) yapmasını istediği her şeyi yapar. "Patron", "işçisinin" kim olacağını bilmiyor; herhangi biri olabilir. Yani ilk görünüm denetleyicisinde ("işçi" sınıfı), "sizin işçi" olacağım diyor. Bana etikete ne yazacağımı söyle ve ben senin için yapacağım. Böylece secondViewController.delegate = self"Patronun işçisi olmayı kabul ediyorum" anlamına gelir. Başka bir örnek ve daha fazla açıklama için bu cevaba bakınız .
Suragch

136

MVC'deki M "Model" içindir ve MVC paradigmasında model sınıflarının rolü bir programın verilerini yönetmektir. Model, görünümün tersidir - görünüm, verilerin nasıl görüntüleneceğini bilir, ancak verilerle ne yapılacağı hakkında hiçbir şey bilmezken, model, verilerle nasıl çalışılacağı hakkında her şeyi bilir, ancak verilerin nasıl görüntüleneceği hakkında hiçbir şey bilmez. Modeller karmaşık olabilir, ancak olmaları gerekmez - uygulamanızın modeli bir dizi veya sözlük dizisi kadar basit olabilir.

Bir denetleyicinin rolü, görünüm ve model arasında aracılık etmektir. Bu nedenle, bir veya daha fazla görünüm nesnesine ve bir veya daha fazla model nesnesine başvurmaları gerekir. Diyelim ki modeliniz bir sözlük dizisidir ve her sözlük tablonuzda bir satırı temsil eder. Uygulamanızın kök görünümü bu tabloyu görüntüler ve dizinin bir dosyadan yüklenmesinden sorumlu olabilir. Kullanıcı tabloya yeni bir satır eklemeye karar verdiğinde, bazı düğmelere dokunun ve denetleyiciniz yeni (değiştirilebilir) bir sözlük oluşturur ve diziye ekler. Satırı doldurmak için, denetleyici bir ayrıntı görünümü denetleyicisi oluşturur ve ona yeni sözlük verir. Ayrıntı görünümü denetleyicisi sözlüğü doldurur ve geri döner. Sözlük zaten modelin bir parçası, bu yüzden başka bir şey olmaya gerek yok.


95

İOS'ta farklı bir sınıfa veri alınmasının çeşitli yolları vardır. Örneğin -

  1. Başka bir sınıfın tahsisinden sonra doğrudan başlatma.
  2. Temsilci seçme - verilerin geri aktarılması için
  3. Bildirim - tek seferde birden fazla sınıfa veri yayınlamak için
  4. Kaydetme NSUserDefaults- daha sonra erişmek için
  5. Singleton sınıfları
  6. Veritabanları ve plist gibi diğer depolama mekanizmaları

Ancak, mevcut sınıfta tahsisi yapılan farklı bir sınıfa bir değer aktarmanın basit senaryosu için, en yaygın ve tercih edilen yöntem, tahsis sonrasında değerlerin doğrudan ayarlanması olacaktır. Bu şu şekilde yapılır: -

İki denetleyici kullanarak anlayabiliriz - Denetleyici1 ve Denetleyici2

Controller1 sınıfında Controller2 nesnesini oluşturmak istediğinizi varsayalım ve bunu bir String değeri iletilerek itin. Bu şu şekilde yapılabilir: -

- (void)pushToController2 {

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

Controller2 sınıfının uygulanmasında şu işlev olacaktır:

@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

Ayrıca Controller2 sınıfının özelliklerini doğrudan aşağıdaki gibi ayarlayabilirsiniz:

- (void)pushToController2 {

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

Birden çok değer iletmek için aşağıdaki gibi birden fazla parametre kullanabilirsiniz: -

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

Veya ortak bir özellikle ilişkili 3'ten fazla parametre geçirmeniz gerekiyorsa, değerleri bir Model sınıfına depolayabilir ve bu modelObject öğesini bir sonraki sınıfa aktarabilirsiniz

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];

Yani kısaca -

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.

Bu yardımcı olur umarım


84

Daha fazla araştırmadan sonra, Protokoller ve Delegelerin bunu yapmanın doğru / Apple'ın tercih ettiği yol olduğu görülüyordu.

Sonunda bu örneği kullandım

Görünüm denetleyicileri ve diğer nesneler arasında veri paylaşımı @ iPhone Dev SDK

İyi çalıştı ve benim görünümler arasında ileri ve geri bir dize ve bir dizi geçmek için izin verdi.

Yardımların için teşekkür ederim


3
protokolleri ve delegeleri kullanmayın, sadece çözmeyi kullanın.
malhal

1
@malhal Ya hikaye tahtaları kullanmazsanız ??
Evan R

Yararsız protokollerden ve delegelerden de nefret ediyorum. @malhal
DawnSong

@EvanR Kodda sekmeler oluşturabilir ve gerçekleştirebilirsiniz. Hepsi aynı.
DawnSong

1
Esasen bu sayfadaki tüm KG "kapsayıcı görünümlerinden önceki günlerden" dir. Milyonlarca yıl içinde hiçbir zaman protokoller veya delegelerle uğraşmazsınız. Herhangi bir ekranda yaptığınız her küçük şey yine de bir kapsayıcı görünümüdür, bu yüzden soru gerçekten mevcut değildir - tüm kapsayıcı görünümlerinden "yukarı ve aşağı" tüm referanslara zaten sahipsiniz.
Fattie

66

Geçen bloklarla en basit ve en zarif versiyonu buluyorum. Geri dönen verileri "A" ve geri dönen görünüm denetleyicisini "B" olarak bekleyen görünüm denetleyicisini adlandıralım. Bu örnekte 2 değer elde etmek istiyoruz: ilk olarak Type1 ve ikinci olarak Type2.

Storyboard kullandığımızı varsayarsak, ilk kontrolör örneğin segue hazırlığı sırasında geri arama bloğunu ayarlar:

- (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);
        };

    }
}

ve "B" görünüm denetleyicisi BViewController.h geri arama özelliğini bildirmelidir:

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

Geri arama geri dönmek için değerleri istedikten sonra BViewController.m uygulama dosyasında daha denir:

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

Hatırlanması gereken bir şey, blok kullanımının sıklıkla burada açıklandığı gibi güçlü ve __ zayıf referansları yönetmesi gerektiğidir.


Değer neden ayrı bir özellik olmaktan ziyade geri arama bloğuna bir parametre olmasın?
Timuçin

56

Verilen cevapların çoğunda bazı iyi bilgiler var, ancak hiçbiri soruyu tam olarak ele almıyor.

Soru, görünüm denetleyicileri arasında bilgi aktarılması hakkında soru soruyor. Verilen belirli örnek, görünümler arasında bilgi aktarılmasıyla ilgili soruluyor, ancak iOS'a kendi kendine ifade edilen yeniliği göz önüne alındığında, orijinal poster muhtemelen görünümler arasında değil (ViewControllers'ın katılımı olmadan) viewControllers arasında anlamına geliyordu. Tüm cevaplar iki görünüm denetleyicisine odaklanıyor gibi görünüyor, ancak uygulama bilgi değişimine ikiden fazla görünüm denetleyicisini dahil etmek için gelişirse ne olur?

Orijinal poster ayrıca Singletons ve AppDelegate'in kullanımını sordu . Bu soruların cevaplanması gerekiyor.

Bu soruya bakan, tam cevap isteyen herkese yardımcı olmak için, bunu sağlamaya çalışacağım.

Uygulama Senaryoları

Oldukça varsayımsal, soyut bir tartışma yapmak yerine, somut uygulamaların akılda tutulmasına yardımcı olur. İki görünümlü denetleyici durumu ve iki görünümden fazla denetleyici durumu tanımlamaya yardımcı olmak için iki somut uygulama senaryosu tanımlayacağım.

Birinci senaryo: Maksimum iki görünüm denetleyicisinin bilgi paylaşması gerekir. Bkz. Şekil 1.

orijinal problem şeması

Uygulamada iki görünüm denetleyicisi vardır. Bir ViewControllerA (Veri Giriş Formu) ve Görünüm Denetleyicisi B (Ürün Listesi) vardır. Ürün listesinde seçilen öğeler, veri giriş formundaki metin kutusunda görüntülenen öğelerle eşleşmelidir. Bu senaryoda, ViewControllerA ve ViewControllerB birbirleriyle doğrudan iletişim kurmalı ve başka bir görünüm denetleyicisi olmamalıdır.

İkinci senaryo : İkiden fazla görünüm denetleyicisinin aynı bilgileri paylaşması gerekir. İkinci diyagrama bakınız.

ev envanter uygulama şeması

Uygulamada dört görünüm denetleyicisi vardır. Ev envanterini yönetmek için sekme tabanlı bir uygulamadır. Üç görünüm denetleyicisi aynı verilerin farklı filtrelenmiş görünümlerini sunar:

  • ViewControllerA - Lüks Ürünler
  • ViewControllerB - Sigortalanmamış Ürünler
  • ViewControllerC - Tüm Ev Envanteri
  • ViewControllerD - Yeni Öğe Formu Ekle

Tek bir öğe oluşturulduğunda veya düzenlendiğinde, diğer görünüm denetleyicileriyle de senkronize edilmesi gerekir. Örneğin, ViewControllerD'ye bir tekne eklersek, ancak henüz sigortalı değilse, tekne kullanıcı ViewControllerA'ya (Lüks Öğeler) ve ayrıca ViewControllerC'ye (Tüm Ev Envanteri) gittiğinde görünmelidir, ancak kullanıcı ViewControllerB (Sigortalanmamış Ürünler). Yalnızca yeni öğeler eklemekle kalmayıp, aynı zamanda (dört görünüm denetleyicisinin herhangi birinden izin verilebilir) öğeleri silmeyle veya mevcut öğeleri ("Yeni Öğe Formu Ekle" den izin verilebilir) düzenleyerek, düzenleme için).

Tüm görünüm denetleyicilerinin aynı verileri paylaşması gerektiğinden, dört görünüm denetleyicisinin de eşitlemede kalması gerekir ve bu nedenle, herhangi bir tek görünüm denetleyicisinin temel verileri değiştirdiğinde, diğer tüm görünüm denetleyicileriyle bir tür iletişim olması gerekir. Her bir görüntü denetleyicisinin bu senaryoda birbiriyle doğrudan görünüm denetleyicisi ile iletişim kurmasını istemediğimiz açıktır. Açık değilse, 20 farklı görüntü denetleyicimiz olup olmadığını düşünün (4 yerine). Bir görünüm denetleyicisi herhangi bir değişiklik yaptığında diğer 19 görüntü denetleyicisini her birine bildirmek ne kadar zor ve hataya açık olur?

Çözümler: Delegeler ve Gözlemci Düzeni ve Tek Tonlar

Birinci senaryoda, diğer cevapların verdiği gibi birkaç uygulanabilir çözümümüz var

  • Segues
  • delegeler
  • özellikleri doğrudan görünüm denetleyicilerinde ayarlama
  • NSUserDefaults (aslında kötü bir seçim)

İkinci senaryoda, başka uygulanabilir çözümlerimiz var:

  • Gözlemci Düzeni
  • singletons

Bir tekil örneği ömrü içinde mevcut Yalnızca örnek olarak bu, bir sınıfın bir örneğidir. Bir singleton adını tek örnek olduğu gerçeğinden alır. Normalde singleton kullanan geliştiricilerin bunlara erişmek için özel sınıf yöntemleri vardır.

+ (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;
}

Şimdi bir singletonun ne olduğunu anladığımıza göre, singletonun gözlemci modeline nasıl uyduğunu tartışalım. Gözlemci deseni, bir nesnenin başka bir nesnenin değişikliklerine yanıt vermesi için kullanılır. İkinci senaryoda, temel verilerdeki değişiklikler hakkında bilmek isteyen dört farklı görünüm denetleyicimiz var. "Temel veriler" tek bir örneğe, tek bir örneğe ait olmalıdır. "Değişiklikleri bilmek", singletonda yapılan değişiklikleri gözlemleyerek gerçekleştirilir.

Ev envanter uygulamasında, envanter öğelerinin listesini yönetmek için tasarlanmış tek bir sınıf örneği bulunur. Yönetici, ev eşyaları koleksiyonunu yönetecektir. Veri yöneticisi için bir sınıf tanımı aşağıdadır:

#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

Ev envanter öğelerinin koleksiyonu değiştiğinde, görünüm denetleyicilerinin bu değişiklikten haberdar edilmesi gerekir. Yukarıdaki sınıf tanımı bunun nasıl olacağını netleştirmez. Gözlemci modelini takip etmeliyiz. Görünüm denetleyicileri sharedManager'ı resmi olarak gözlemlemelidir. Başka bir nesneyi gözlemlemenin iki yolu vardır:

  • Anahtar / Değer İzleme (KVO)
  • NSNotificationCenter.

İkinci senaryoda, HouseholdInventoryManager'ın KVO kullanılarak gözlemlenebilecek tek bir özelliğimiz yoktur. Kolayca gözlemlenebilir tek bir özelliğimiz olmadığından, gözlemci modeli, bu durumda NSNotificationCenter kullanılarak uygulanmalıdır. Dört görünüm denetleyicisinin her biri bildirimlere abone olur ve sharedManager uygun olduğunda bildirim merkezine bildirim gönderir. Envanter yöneticisinin, görünüm denetleyicileri veya envanter öğelerinin toplanmasının ne zaman değiştiğini bilmekle ilgilenebilecek diğer sınıfların örnekleri hakkında hiçbir şey bilmesine gerek yoktur; NSNotificationCenter bu uygulama ayrıntılarıyla ilgilenir. Görünüm Denetleyicileri bildirimlere abone olur ve veri yöneticisi bildirimleri gönderir.

Birçok yeni başlayan programcı , uygulamanın ömrü boyunca her zaman tam olarak bir Uygulama Temsilcisi bulunmasından yararlanır ve bu da küresel olarak erişilebilirdir. Başlangıçtaki programcılar, uygulamadaki başka herhangi bir yerden erişim için bir kolaylık olarak nesneleri ve işlevleri appDelegate'e doldurmak için bu gerçeği kullanır. AppDelegate'in bir singleton olması, diğer tüm singletonların yerini alması gerektiği anlamına gelmez. İyi bir nesne yönelimli uygulamaları kırarak, bir sınıfa çok fazla yük bindirdiği için bu kötü bir uygulamadır. Her sınıfın, genellikle sadece sınıfın adıyla açıklanabilecek açık bir rolü olmalıdır.

Uygulama Temsilciniz şişirilmeye başladığında, işlevselliği tek tektonlara kaldırmaya başlayın. Örneğin, Çekirdek Veri Yığını AppDelegate içinde bırakılmamalı, bunun yerine kendi sınıfına, bir coreDataManager sınıfına konulmalıdır.

Referanslar


41

OP, görünüm denetleyicilerinden bahsetmedi, ancak cevapların çoğu, LLVM'nin yeni özelliklerinden bazılarının, bir görünüm denetleyicisinden diğerine veri aktarmak istediğinde bunu kolaylaştırmasına izin vermek istedim. bazı sonuçları geri almak.

Storyboard segues, ARC ve LLVM blokları bunu benim için her zamankinden daha kolay hale getiriyor. Yukarıda bahsedilen hikaye tahtalarından ve selamlardan bazı cevaplar zaten delegasyona dayanıyordu. Delegelerin tanımlanması kesinlikle işe yarıyor, ancak bazı insanlar işaretçileri veya kod bloklarını geçmeyi daha kolay bulabilir.

UINavigators ve segues ile, bilgiyi bağımlı denetleyiciye aktarmanın ve bilgileri geri almanın kolay yolları vardır. ARC, NSObjects'ten türetilen şeylere geçiş işaretçileri kolaylaştırır; bu nedenle, alt denetleyicinin sizin için bazı veriler eklemesini / değiştirmesini / değiştirmesini istiyorsanız, değiştirilebilir bir örneğe bir işaretçi iletin. Bloklar geçiş eylemlerini kolaylaştırır, böylece alt denetleyicinin daha yüksek düzey denetleyicinizde bir eylem başlatmasını istiyorsanız, bunu bir blok geçirin. Bloğu, sizin için anlamlı olan herhangi bir sayıda argümanı kabul edecek şekilde tanımlarsınız. API'yı, işinize daha uygunsa birden çok blok kullanacak şekilde de tasarlayabilirsiniz.

İşte segue tutkalının iki önemsiz örneği. Birincisi, giriş için bir parametreyi, ikincisi ise çıkış için geçirileni gösteren basittir.

// 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];
}

Bu ikinci örnek, ikinci argüman için bir geri arama bloğunun iletilmesini gösterir. Blokları kullanmayı seviyorum çünkü ilgili ayrıntıları kaynakta birbirine yakın tutar - üst düzey kaynak.

// 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];
    }];
}

41

Verileri ViewController 2'den (hedef) viewController 1'e (Kaynak) geri aktarmak daha ilginç bir şeydir. StoryBoard'ı kullandığınızı varsayarsak, bunların hepsini öğrendim:

  • Temsilci
  • Bildirim
  • Kullanıcı varsayılanları
  • Singleton

Bunlar zaten burada tartışıldı.

Daha fazla yol olduğunu gördüm:

-Blok geri çağrılarını kullanma:

prepareForSegueVC1'deki yöntemde kullanın

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

- Görsel senaryo taslaklarını kullanma Gevşeyin (Çıkış)

VC 1'de UIStoryboardSegue bağımsız değişkeniyle aşağıdaki gibi bir yöntem uygulayın:

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

StoryBoard'da "return" düğmesini vc'nin yeşil Exit (Açma) düğmesine asın. Şimdi u bir segue var, böylece u VC2 preparForSegue içinde destinationViewController özelliğini kullanmak ve geri gitmeden önce herhangi bir VC1 özelliğini değiştirmek.

  • Film şeridi Undwind (Exit) kullanmanın başka bir seçeneği - VC1'de yazdığınız yöntemi kullanabilirsiniz

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

    Ve VC1'in preparForSegue uygulamasında paylaşmak istediğiniz herhangi bir özelliği değiştirebilirsiniz.

Her iki çözme seçeneğinde düğmenin tag özelliğini ayarlayabilir ve preparForSegue'de kontrol edebilirsiniz.

Umarım tartışmaya bir şey ekledim.

:) Şerefe.


40

Veri paylaşmak için birden çok yöntem vardır.

  1. Kullanarak her zaman veri paylaşabilirsiniz NSUserDefaults. Paylaşmak istediğiniz değeri seçtiğiniz bir tuşa göre ayarlayın ve bir NSUserDefaultsonraki görünüm denetleyicisinde o tuşla ilişkilendirilen değeri alın .

    [[NSUserDefaults standardUserDefaults] setValue:value forKey:key]
    [[NSUserDefaults standardUserDefaults] objectForKey:key]
  2. İçinde sadece bir özellik oluşturabilirsiniz viewcontrollerA. Bir nesne oluşturun viewcontrollerAiçinde viewcontrollerBve o mülke istenen değer atayın.

  3. Bunun için özel delegeler de oluşturabilirsiniz.


30
NSUserDefaults'un tipik amacı, uygulama yürütmeleri arasında kalan kullanıcı tercihlerini depolamaktır, bu nedenle burada saklanan her şey açıkça kaldırılmadığı sürece burada kalacaktır. Bir uygulamadaki görünüm denetleyicileri (veya diğer nesneler) arasında bilgi aktarmak için bunu kullanmak gerçekten kötü bir fikirdir.
José González

30

Bir denetleyiciden diğerine veri aktarmak istiyorsanız bu kodu deneyin

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];
 }

29

Bu çok eski bir cevap ve bu anti-desen, lütfen delegeler kullanın. Bu Yaklaşımı kullanmayın !!

1. İkinci View Controller'da ilk View Controller örneğini oluşturun ve özelliğini yapın @property (nonatomic,assign).

2.SecondviewController Bu görünüm denetleyicisinin örneğini atayın .

2. Seçim işlemini tamamladığınızda diziyi ilk Görünüm Denetleyicisine kopyalayın, SecondView u kaldırdığınızda, FirstView Dizi Verilerini tutacaktır.

Bu yardımcı olur umarım.


2
Görünüm denetleyicileri arasında çok düzensiz bir bağlantı oluşturduğundan, bunun doğru yol olduğuna inanmıyorum. Gerçekten MVC'ye bağlı değil.
Matt Price

1
Eğer sıkı MVC takip etmek istiyorsanız, kullanmak NSNotificationCenter kontrol yöntemidir ViewControllerB için ViewControllerA çağrılabilir bu o u yardımcı olabilir
kaar3k

28

Uzun zamandır bu çözümü araştırıyordum, Atlast buldum. Her şeyden önce SecondViewController.h dosyanızdaki tüm nesneleri

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

Şimdi uygulama dosyanızda bu gibi nesneler için bellek ayırın

- (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;
}

Şimdi Arrayve nesnesi için bellek ayırdınız. şimdi itmeden önce o hafızayı doldurabilirsinizViewController

SecondViewController.h'nize gidin ve iki yöntem yazın

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

uygulama dosyasında işlevi uygulayabilirsiniz

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

CustomObjectbununla birlikte bir ayarlayıcı işlevinin olması gerektiğini umarak .

şimdi temel işiniz bitti. itmek istediğiniz yere gidin SecondViewControllerve aşağıdaki şeyleri yapın

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

Yazım hatalarına dikkat edin.


24

Bunu yapmanın yolu değil, delegeleri kullanmalısınız, ViewController1 ve ViewController2 adlı iki görünüm denetleyicimiz olduğunu varsayalım. bunu doğru şekilde başarmak için aşağıdakileri yapmanız gerekir:

Projenize yeni bir dosya ekleyin (Objective-C Protokolü) Dosya -> Yeni, şimdi ViewController1Delegate veya istediğiniz herhangi bir ad verin ve bunları @interface ve @end yönergeleri arasında yazın

@optional

- (void)checkStateDidChange:(BOOL)checked;

Şimdi ViewController2.h dosyasına gidin ve ekleyin

#import "ViewController1Delegate.h"

ardından tanımını

@interface ViewController2: UIViewController<ViewController1Delegate>

Şimdi ViewController2.m'ye gidin ve uygulamanın içine ekleyin:

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

Şimdi ViewController1.h dosyasına gidin ve aşağıdaki özelliği ekleyin:

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

Şimdi bir olaydan sonra ViewController2 içinde ViewController1 oluşturuyorsanız, NIB dosyalarını kullanarak bu şekilde yapmanız gerekir:

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

Artık hazırsınız, ViewController1'de kontrol olayının değiştiğini algıladığınızda, tek yapmanız gereken aşağıdaki

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

Lütfen sorunuzu doğru anlamadığımda net olmayan bir şey olup olmadığını söyleyin.


23

Birinden başka bir viewController'a veri göndermek istiyorsanız, işte size bir yol:

ViewControllers'ımız olduğunu varsayalım: viewControllerA ve viewControllerB

Şimdi viewControllerB.h

@interface viewControllerB : UIViewController {

  NSString *string;
  NSArray *array;

}

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

ViewControllerB.m içinde

#import "viewControllerB.h"

@implementation viewControllerB

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

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

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

}

In 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];

}

Böylece, herhangi bir delege ayarlamadan viewControllerA'dan viewControllerB'ye veri aktarabilirsiniz. ;)


1
Projemde ur kodu kullanarak denedim, ancak viewcontrollerB değerleri alamadım. Sorun ne olabilir bana söyleyebilir misin?
X-Kodlayıcı

1
@Ajitthala Kodunuzu yeni bir soruya yapıştırabilir misiniz? Sorununuzu çözmeye çalışacağım. :)
Aniruddh Joshi

1
init yöntemlerini kullanmamak ve sadece viewcontroller A'dan vcB.string = @ "asdf" gibi bir şey yapmak yanlış mı?
khanh.tran.vinh

1
@ khanh.tran.vinh ARC kullanıp kullanmadığınıza bağlıdır.
Aniruddh Joshi

21

Bu dövülmüş bir konu olduğunu biliyorum ama bu soruyu bir SWIFT eğik ile cevaplamak ve çıplak kemikler örneği isteyenler için, burada bir segue almak için veri kullanmak için go-to yöntemi.

Yukarıdakine benzer, ancak düğmeler, etiketler vb. Sadece bir görünümden diğerine veri aktarmak yeterlidir.

Storyboard'u Kur

Üç bölüm var.

  1. Gönderen
  2. Segue
  3. Alıcı

Bu, aralarında bir segue olan çok basit bir görünüm düzenidir.


Çok basit görünüm düzeni.  Not: Gezinme denetleyicisi yok


İşte gönderenin kurulumu


Gönderen


İşte alıcı için kurulum.


Alıcı


Son olarak, segue için kurulum.


Segue Identifier


Görünüm Denetleyicileri

Bunu basit tutuyoruz, böylece eylemler değil, düğmeler yok, uygulama yüklendiğinde verileri gönderenden alıcıya taşıyoruz ve sonra iletilen değeri konsola çıkarıyoruz.

Bu sayfa başlangıçta yüklenen değeri alır ve iletir.

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

    }

}

Bu sayfa yüklendiğinde sadece değişkenin değerini konsola gönderir. Bu noktada, en sevdiğimiz film bu değişkente olmalı.

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)")

    }   
}

Bir segue kullanmak istiyorsanız ve sayfalarınızı bir gezinme denetleyicisi altında yoksa, bu şekilde başa çıkabilirsiniz.

Çalıştırıldığında otomatik olarak alıcı görünümüne geçmeli ve değeri konsoldan göstererek göndericiden alıcıya geçirmelidir.

Ghost Busters klasik bir millet.


19

Benim durumumda, uygulamanın hemen hemen her yerinden verilere erişime izin veren küresel bir nesne olarak çalışabilen tekli bir sınıf kullandım. İlk şey bir singleton sınıfı oluşturmaktır. , Sayfasına bakınız " Ne gerektiği gibi bakmak? Tekil benim Objective-C " Ve ne ben sadece bunu ithal edilmiş nesne küresel erişilebilir hale getirmek yaptılar appName_Prefix.pchher sınıflarında import ifadesini uygulamak için hangi. Bu nesneye erişmek ve kullanmak için, kendi değişkenlerini içeren paylaşılan örneği döndürmek için sınıf yöntemi uyguladım


Bu doğru cevap. Sadece "model" olarak bir singleton kullanın. Caleb'in dediği gibi "uygulamanızın modelinin bir dizi dizisi kadar basit olabileceğini" unutmayın . Swift'te bir singleton yapmanın gerçekten önemsiz olduğunu belirtmek önemlidir . (Çok basit, burada bahsetmeye bile değmez - sadece google.) Yeni programcılar için, bir singleton yapmanın kıçta gerçek bir acı olduğunu anlamaya değer . Ancak, singletonlar kesinlikle iOS programlamasının merkezindedir - Apple'ın yaptığı her şey bir singleton'dur. Bu yüzden Apple nihayet tek tek tonları düzgün bir şekilde yapmayı (Swift'te) yaptı.
Fattie

1
Ancak, bu günlerde (2016+) "her şeyin iOS'ta kapsayıcı bir görünüm olduğunu" unutmayın. Ekranda yaptığınız her şey küçük bir konteyner görünümü yapar. Kapsayıcı görünümlerinin "yukarı ve aşağı" zincirlerini referans almak oldukça önemlidir (ancak Apple bunu gelecekte daha kolay hale getirecektir) ve bunu hemen hemen her kapsayıcı görünümü için yaparsınız. Yani, yine de yaptıysanız - cevabınız var; bir singletona gerek yok. Konteyner görünüm
girişi

19

Hızlı 5

Peki Matt Price'ın Cevabı veri geçmek için gayet iyi ama en son Swift sürümünde yeniden yazacağım çünkü yeni programcıların yeni sözdizimi ve yöntemler / çerçeveler nedeniyle zorlu çıktığını düşünüyoruz, çünkü orijinal yazı Objective-C'de.

Görünüm Denetleyicileri Arasında Veri Aktarmak için birden fazla seçenek vardır.

  1. Gezinti Denetleyicisini Kullanma
  2. Segue Kullanımı
  3. Temsilci Kullanma
  4. Bildirim Gözlemcisini Kullanma
  5. Bloğu Kullanma

Swift'teki mantığını en son iOS Framework ile yeniden yazacağım


Verileri Gezinti Denetleyicisinden Aktarma Push : ViewControllerA'dan ViewControllerB'ye

Adım 1. ViewControllerB'de değişken bildirme

var isSomethingEnabled = false

Adım 2. ViewControllerB 'ViewDidLoad yönteminde Değişkeni Yazdır

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

Adım 3. ViewControllerA'da Verileri Gezinti Kontrol Cihazına aktarırken aktarın

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)
        }
    }

İşte tam kod:

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)
    }
}

Segue ile Veri Aktarma : ViewControllerA'dan ViewControllerB'ye

Adım 1. ViewControllerA'dan ViewControllerB'ye Segue oluşturun ve Storyboard'da aşağıda gösterildiği gibi Identifier = showDetailSegue verin

resim açıklamasını buraya girin

2. Adım. ViewControllerB'de isSomethingEnabled adlı geçerli bir değer bildirin ve değerini yazdırın.

Adım 3. ViewControllerA'da Segue iletilirken isSomethingEnabled'ın değeri

İşte tam kod:

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)
    }
}

Delege ile Veri Aktarma : ViewControllerB'den ViewControllerA'ya

Adım 1. ViewControllerB dosyasında ancak sınıf dışında Protokol ViewControllerBDelegate bildir

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?)
}

Adım 2. ViewControllerB'de değişken örneği temsilci olarak bildirin

var delegate: ViewControllerBDelegate?

Adım 3. ViewControllerB viewDidLoad yöntemi içinde temsilci için veri gönderme

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

Adım 4. ViewControllerA'da ViewControllerBDelegate'i onaylayın

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

Adım 5. ViewControllerA'da temsilci uygulayacağınızı onaylayın

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)
            }
        }

Adım 6. ViewControllerA'da veri almak için temsilci yöntemi uygulayın

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

İşte tam kod:

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")
    }
}

Verileri Bildirim Gözlemcisinden Aktarma : ViewControllerB'den ViewControllerA'ya

Adım 1. ViewControllerB'de Bildirim gözlemcisindeki verileri ayarlayın ve kaydedin

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

Adım 2. ViewControllerA'da Bildirim Gözlemcisi ekleyin

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

Adım 3. ViewControllerA'da Bildirim veri değerini alma

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

İşte tam kod:

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)
    }
}

Bloktan Veri Aktarma : ViewControllerB'den ViewControllerA'ya

Adım 1. ViewControllerB'de bloğu bildirin

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

Adım 2. ViewControllerB'de blok halinde veri ayarlama

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

Adım 3. ViewControllerA'da blok verilerini alma

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

İşte tam kod:

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)
        }
    }
}

GitHub'ımda tam bir örnek uygulama bulabilirsiniz . Bu konuda herhangi bir sorunuz olursa lütfen bize bildirin.


18

FirstViewController arasında SecondViewController'a veri aktarımı aşağıdaki gibi

Örneğin:

FirstViewController Dize değeri olarak

StrFirstValue = @"first";

yani bu değeri aşağıdaki adımla ikinci sınıfta geçirebiliriz

1> SecondViewController.h dosyasında dize nesnesini sandık gerekiyor

NSString *strValue;

2> .h dosyasındaki aşağıdaki beyanı aşağıda belirtmek gerekir

@property (strong, nonatomic)  NSString *strSecondValue;

3> Bu değeri başlık bildiriminin altındaki FirstViewController.m dosyasında sentezlemeniz gerekiyor

@synthesize strValue;

ve FirstViewController.h dosyasında:

@property (strong, nonatomic)  NSString *strValue;

4> FirstViewController'da, ikinci görünüme gittiğimiz yöntemden lütfen bu yöntemde aşağıdaki kodu yazın.

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

[secondView setStrSecondValue:StrFirstValue];

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

SecondViewController'a girdikten sonra, verileri FirstViewController'a nasıl aktarırsınız?
bruno

18

Şu anda burada bulunan MCViewFactory adlı bir proje aracılığıyla bu soruna açık kaynak çözümüne katkıda bulunuyorum:

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

Fikir, baktığınız görünümü yönetmek için küresel bir fabrika kullanarak Android'in niyet paradigmasını taklit etmek ve görünümler arasında veri değiştirmek ve geçiş yapmak için "niyetler" kullanmaktır. Tüm belgeler github sayfasındadır, ancak bazı önemli noktalar şunlardır:

Fabrika ayarlarınızı başlatırken, tüm görünümlerinizi .XIB dosyalarına ayarlar ve uygulama temsilcisine kaydedersiniz.

// Register activities

MCViewFactory *factory = [MCViewFactory sharedFactory];

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

Şimdi, VC'nizde, yeni bir VC'ye geçmek ve veri aktarmak istediğinizde, yeni bir niyet oluşturursunuz ve sözlüğüne veri kaydedersiniz (savedInstanceState). Ardından, fabrikanın mevcut amacını ayarlayın:

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

Buna uyan tüm görünümlerinizin MCViewController alt sınıfları olması ve yeni onResume: yöntemini geçersiz kılmanıza ve geçtiğiniz verilere erişmenize izin vermesi gerekir.

-(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];
}

Umarım bazılarınız bu çözümü faydalı / ilginç bulmaktadır.


Sonra tüm denetleyici nesneleri kayıtlı tüm sözlükleri herhangi bir kapsamda alabilir / ayarlayabilir mi? Bunu küçümseyin.
Itachi

15

Sonraki özelliği oluşturun view controller .hve alıcı ve ayarlayıcıyı tanımlayın.

Bunu propertynextVC'de NextVC.h dosyasına ekleyin

@property (strong, nonatomic) NSString *indexNumber;

Ekle

@synthesize indexNumber; NextVC.m'de

Ve son olarak

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

vc.indexNumber=@"123";

[self.navigationController vc animated:YES];

11

Bunu yapmanın tonlarca yolu var ve doğru olanı seçmek önemlidir. Muhtemelen en büyük mimari kararlardan biri, model kodunun uygulama boyunca nasıl paylaşılacağı veya bunlara nasıl erişileceğiyle ilgilidir.

Bir süre önce bununla ilgili bir blog yazısı yazdım: Model Kodunu Paylaşma . İşte kısa bir özet:

Paylaşılan veriler

Bir yaklaşım, görünüm denetleyicileri arasında model nesnelerine işaretçiler paylaşmaktır.

  • Verileri ayarlamak için görünüm denetleyicilerinde (Gezinme veya Sekme Çubuğu Denetleyicisi'nde) kaba kuvvet yinelemesi
  • ReadyForSegue'de (film şeritleri varsa) veya init'te (programlıysa) veri ayarlama

Segue için hazırlanın en yaygın olanı burada bir örnektir:

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

Bağımsız erişim

Başka bir yaklaşım, bir seferde veri dolu bir ekranı işlemek ve görünüm denetleyicilerini birbirleriyle eşleştirmek yerine her bir görünüm denetleyicisini bağımsız olarak elde edebilecekleri tek veri kaynağına birleştirmektir.

Bunu yapmanın en yaygın yolu singleton örneğidir. Eğer tekli nesneniz olsaydı DataAccessUIViewController'ın viewDidLoad yönteminde aşağıdakileri yapabilirsiniz:

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

Verilerin aktarılmasına yardımcı olan ek araçlar da vardır:

  • Anahtar / Değer İzleme
  • NSNotification
  • Temel veri
  • NSFetchedResultsController
  • Veri kaynağı

Temel veri

Temel Veriler ile ilgili güzel olan şey, ters ilişkilere sahip olmasıdır. Notlar nesnesine yalnızca NotesViewController vermek istiyorsanız, not defteri nesnesi ile ters bir ilişkiye sahip olacağınızdan yapabilirsiniz. NotesViewController'daki not defterinde verilere ihtiyacınız varsa, aşağıdakileri yaparak nesne grafiğini geri çekebilirsiniz:

let notebookName = note.notebook.name

Bununla ilgili daha fazla bilgiyi blog yayınımda bulabilirsiniz: Model Kodunu Paylaşma


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;

10

Yetkilendirme .xib dosyalarını kullanırken bu tür işlemleri gerçekleştiren tek çözümdür, ancak yukarıda açıklanan tüm yanıtlar storyboardtemsilci seçmeniz gereken .xibs dosyaları içindir. yapabileceğiniz tek çözüm bu.

Başka bir çözüm, singleton sınıf modelini bir kez başlatmak ve tüm uygulamanızda kullanmaktır.


10

ViewControlerOne'dan ViewControllerTwo'ya veri aktarmak istiyorsanız bunları deneyin ..

bunları ViewControlerOne.h içinde yapın

 @property (nonatomic, strong) NSString *str1;

bunları ViewControllerTwo.h içinde yapın

 @property (nonatomic, strong) NSString *str2;

ViewControllerTwo.m içinde str2'yi sentezleme

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

bunları ViewControlerOne.m'de yapın

 - (void)viewDidLoad
 {
   [super viewDidLoad];

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

 }

düğmeler tıklayın olay bunu yapın ..

-(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];
}

bunları ViewControllerTwo.m'de yapın

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

10

Uygulamanızdaki görünüm denetleyicilerine erişmek için verileri Uygulama temsilcisine kaydedebilirsiniz. Tek yapmanız gereken, uygulama temsilcisinin paylaşılan bir örneğini oluşturmaktır

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

Örneğin

bir beyan NSArray object *arrayXYZederseniz, herhangi bir görünüm denetleyicisindenappDelegate.arrayXYZ


Hackathon için tercih edilen yöntem
Hai Feng Kao

9

Birinden başka bir viewController'a veri göndermek istiyorsanız, işte size bir yol:

Diyelim ki viewControllers: ViewController ve NewViewController.

ViewController.h içinde

#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

ViewController.m içinde

#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];

}

NewViewController.h içinde

#import <UIKit/UIKit.h>

@interface NewViewController : UITableViewController
{
    NSArray *arrayList;

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

}

@property(nonatomic, retain)NSArray *arrayList;

@end

NewViewController.m içinde

#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

Bu şekilde verileri bir viewcontroller'dan başka bir view controller'a aktarabiliriz ...


8

NSProxy tabanlı Model nesneleri ve Mock nesneleri fikrini, kullanıcının seçtiği şey iptal edilebilirse veriyi işlemek veya atmak fikrinden hoşlanıyorum.

Tek bir nesne veya birkaç nesne olduğu için verileri iletmek kolaydır ve eğer UINavigationController denetleyicisi diyelim, referansı içeride tutabilirsiniz ve tüm itilen görünüm denetleyicileri doğrudan navigasyon denetleyicisinden erişebilir.


8

didSelectRowAtPathMetodu kullanarak bunu karmaşık hale getiren bir çok insan gördüm . Örneğimde Temel Verileri kullanıyorum.

- (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];

}

Yöntemin içinde 4 satır kod ve bitirdiniz.


6

Bu sorulara, gerçekten işe yarayacak görünüm denetleyicisi iletişimini gerçekleştirmek için birçok farklı yol sunan birçok cevap var, ancak hangisinin gerçekten hangisinin en iyi hangisinin kullanılacağından bahsettiğim hiçbir yerde göremiyorum.

Uygulamada, bence sadece birkaç çözüm önerilmektedir:

  • Verileri iletmek için:
    • film şeridi ve segues kullanırken prepare(for:sender:)yöntemini geçersiz UIViewControllerkıl
    • görünümü bir denetleyiciden veya görünüm denetleyicisi geçişlerini kodla gerçekleştirirken özelliklerden geçirme
  • Verileri geriye doğru aktarmak için
    • uygulama paylaşılan durumunu güncelleme (yukarıdaki yöntemlerden biriyle görünüm denetleyicileri arasında iletebilirsiniz)
    • yetkiyi kullan
    • gevşemek

Kullanmamanızı tavsiye ettiğim çözümler:

  • Temsilci kullanmak yerine önceki denetleyiciye doğrudan başvurma
  • Tek birtondan veri paylaşma
  • Uygulama temsilcisi aracılığıyla veri aktarma
  • Kullanıcı varsayılanları üzerinden veri paylaşımı
  • Bildirimlerden veri aktarımı

Bu çözümler, kısa vadede çalışmasına rağmen, uygulamanın mimarisini bozacak ve daha sonra daha fazla sorun yaratacak çok fazla bağımlılık getiriyor.

İlgilenenler için, bu noktaları daha derinlemesine ele alan ve çeşitli dezavantajları vurgulayan bazı makaleler yazdım:

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.