dismissModalViewController VE verileri geri iletme


84

FirstViewController ve secondViewController olmak üzere iki görünüm denetleyicim var . Bu kodu secondViewController'ıma geçmek için kullanıyorum (ayrıca ona bir dize geçiriyorum):

secondViewController *second = [[secondViewController alloc] initWithNibName:nil bundle:nil];

second.myString = @"This text is passed from firstViewController!";

second.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;

[self presentModalViewController:second animated:YES];

[second release];

Daha sonra bu kodu secondViewController'da firstViewController'a geri dönmek için kullanıyorum:

[self dismissModalViewControllerAnimated:YES];

Bütün bunlar iyi çalışıyor. Sorum şu, verileri firstViewController'a nasıl iletirim? SecondViewController'den firstViewController'a farklı bir string geçmek istiyorum.

Yanıtlar:


142

Temsilci protokollerini kullanmanız gerekiyor ... İşte bunu nasıl yapacağınız:

SecondViewController'ın başlık dosyasında bir protokol bildirin. Şöyle görünmeli:

#import <UIKit/UIKit.h>

@protocol SecondDelegate <NSObject>
-(void)secondViewControllerDismissed:(NSString *)stringForFirst
@end


@interface SecondViewController : UIViewController
{
    id myDelegate;  
}

@property (nonatomic, assign) id<SecondDelegate>    myDelegate;

MyDelegate'i uygulamanızdaki (SecondViewController.m) dosyasında sentezlemeyi unutmayın:

@synthesize myDelegate;

FirstViewController'ın başlık dosyasında, şunu yaparak SecondDelegate protokolüne abone olun:

#import "SecondViewController.h"

@interface FirstViewController:UIViewController <SecondDelegate>

Şimdi FirstViewController'da SecondViewController'ı başlattığınızda aşağıdakileri yapmanız gerekir:

// If you're using a view controller built with Interface Builder.
SecondViewController *second = [[SecondViewController alloc] initWithNibName:"SecondViewController" bundle:[NSBundle mainBundle]];
// If you're using a view controller built programmatically.
SecondViewController *second = [SecondViewController new]; // Convenience initializer that uses alloc] init]
second.myString = @"This text is passed from firstViewController!";
second.myDelegate = self;
second.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:second animated:YES];
[second release];

Son olarak, ilk görünüm denetleyicinizin (FirstViewController.m) uygulama dosyasında SecondDelegate yöntemini secondViewControllerDismissed için uygulayın:

- (void)secondViewControllerDismissed:(NSString *)stringForFirst
{
    NSString *thisIsTheDesiredString = stringForFirst; //And there you have it.....
}

Şimdi, ikinci görünüm denetleyicisini kapatmak üzereyken, ilk görünüm denetleyicisinde uygulanan yöntemi çağırmak istersiniz. Bu kısım basit. Tek yapmanız gereken, ikinci görünüm denetleyicinizde, kapatma kodundan önce bazı kodlar eklemektir:

if([self.myDelegate respondsToSelector:@selector(secondViewControllerDismissed:)])
{
    [self.myDelegate secondViewControllerDismissed:@"THIS IS THE STRING TO SEND!!!"];
}
[self dismissModalViewControllerAnimated:YES];

Delege protokolleri SON DERECE, SON DERECE, SON DERECE kullanışlıdır. Onları tanımanız size iyi gelir :)

NSNotifications bunu yapmanın başka bir yoludur, ancak en iyi uygulama olarak, birden çok viewController veya nesne arasında iletişim kurmak istediğimde bunu kullanmayı tercih ederim. NSNotifications'ı kullanmayı merak ediyorsanız, daha önce gönderdiğim bir cevap: Appdelegate'teki bir ileti dizisinden birden çok görüntü denetleyicisine yönelik olayları tetikleme

DÜZENLE:

Birden fazla argüman iletmek istiyorsanız, kapatmadan önceki kod şu şekilde görünür:

if([self.myDelegate respondsToSelector:@selector(secondViewControllerDismissed:argument2:argument3:)])
{
    [self.myDelegate secondViewControllerDismissed:@"THIS IS THE STRING TO SEND!!!" argument2:someObject argument3:anotherObject];
}
[self dismissModalViewControllerAnimated:YES];

Bu, firstViewController'ınızın içindeki SecondDelegate yöntemi uygulamanızın artık şöyle görüneceği anlamına gelir:

- (void) secondViewControllerDismissed:(NSString*)stringForFirst argument2:(NSObject*)inObject1 argument3:(NSObject*)inObject2
{
    NSString thisIsTheDesiredString = stringForFirst;
    NSObject desiredObject1 = inObject1;
    //....and so on
}

Apple'ın iOS için View Controller Programlama Kılavuzuna göre , secondViewController sunulan kontrolörde değil, sunum görünüm kontrolcüsünde atılmalıdır.
Michael

UITableView'ın temsilcisini ayarlamamışsınız gibi görünüyor. Bunu sahip olduğunuz kodla bir soru olarak gönderebilir ve geri dönebilir misiniz? Sana yardım edebilirim.
Sid

1
@Michael Dokümantasyon, kendi başına kapat çağrısının çağrıyı sunan görünüm denetleyicisine ilettiğini söylüyor. Ayrıca, hedeflediğiniz iOS sürümüne (5 veya öncesi) bağlı olarak sunmaViewController ve parentViewController arasında geçiş yapma konusunda endişelenmenize gerek olmadığından self'i çağırmak daha temizdir.
Sid

1
@Resty Katılıyorum; bloklar inanılmaz derecede kullanışlıdır. Bir noktada blokları desteklemek için bu yanıtı değiştirmeyi düşünüyordum. Ancak bu durumda, delege yanıtını şimdilik görünür bıraktım çünkü bu bize modale geçirilebilecek nesneleri manipüle etmek için biraz daha fazla özgürlük veriyor. Sadece tembelim ve yakında blokları kullanmak için bu yanıtı güncelleyeceğim :)
Sid

1
@sid teşekkürler kardeşim benim için çalışıyor ama biraz değişiklik yapman gerekiyor. birçok şey değişti. lütfen düzenleyin
ChenSmile

40

Burada yerimden çok uzakta olabilirim, ancak blok sözdizimini çok ayrıntılı delege / protokol yaklaşımına tercih etmeye başladım. Vc1'den vc2 yaparsanız, vc2'de vc1'den ayarlayabileceğiniz bir blok olan bir özelliğe sahip olun!

@property (nonatomic, copy) void (^somethingHappenedInVC2)(NSString *response);

Ardından, vc2'de vc1'e anlatmak istediğiniz bir şey olduğunda, sadece vc1'de tanımladığınız bloğu çalıştırın!

self.somethingHappenedInVC2(@"Hello!");

Bu, verileri vc2'den vc1'e geri göndermenizi sağlar. Tıpkı sihir gibi. IMO, bu protokollerden çok daha kolay / temiz. Bloklar harika ve mümkün olduğunca benimsenmesi gerekiyor.

DÜZENLEME - Geliştirilmiş örnek

Diyelim ki, bir kullanıcıdan bir miktar girdi almak için geçici olarak üstüne bir modalVC sunmak istediğimiz bir mainVC'ye sahibiz. Bu modalVC'yi mainVC'den sunmak için, onu mainVC'nin içine yerleştirmemiz / başlatmamız gerekir. Oldukça basit şeyler. Bu modalVC nesnesini yaptığımızda, üzerinde her iki vc nesnesi arasında kolayca iletişim kurmamızı sağlayan bir blok özelliği de ayarlayabiliriz. Öyleyse yukarıdaki örneği ele alalım ve follwing özelliğini modalVC'nin .h dosyasına koyalım:

 @property (nonatomic, copy) void (^somethingHappenedInModalVC)(NSString *response);  

Ardından, mainVC'mizde, yeni bir modalVC nesnesi tahsis ettikten / başlattıktan sonra, modalVC'nin blok özelliğini şu şekilde ayarlarsınız:

ModalVC *modalVC = [[ModalVC alloc] init];
modalVC.somethingHappenedInModalVC = ^(NSString *response) {
     NSLog(@"Something was selected in the modalVC, and this is what it was:%@", response);
}

Yani biz sadece blok özelliğini ayarlıyoruz ve bu blok yürütüldüğünde ne olacağını tanımlıyoruz.

Son olarak, modalVC'mizde, bir dataSource dizge dizisi tarafından desteklenen bir tableViewController olabilir. Bir satır seçimi yapıldıktan sonra, şöyle bir şey yapabiliriz:

 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
      NSString *selectedString = self.dataSource[indexPath.row];
      self.somethingHappenedInModalVC(selectedString);
 }

Ve tabii ki modalVC'de bir satır seçtiğimiz her seferde, NSLog hattımızdan mainVC'de bir konsol çıktısı alacağız. Umarım yardımcı olur!


1
Film şeridi kullanırken bu yine de çalışmalı mı? Şu anda benim için çalışmıyor. Sadece bir lldb hatasıyla çıkıyor. Ana fark. Görüyorum ki vc'nin tahsisi artık somutlaştırılmış bir storyboard akışı. DÜZENLE Ve bloğu oluşturmadan önce sunum yapıyordum. Sabit.
malaki1974

2
Size katılıyorum :) Cevabımı epey bir süre önce göndermiştim. Artık kullanıma bağlı olarak bloklar / protokoller arasında geçiş yapıyorum. Bu ileti dizisinin bugün hala oldukça aktif olduğunu görünce, bir noktada, yanıtımı blokları içerecek şekilde düzenlemeliyim.
Sid

1
En sezgisel çözümü getirdiği için bu cevabın kabul edilmesi gerekir.
Sukitha Udugamasooriya

2
İki uygun cevaptan en iyisi bu!
kygcoleman

1
Bu benim tercih ettiğim yöntem. Hızlı bir şekilde bu daha sonra kapatmalarla gerçekleştirilir. Temsilcilerden ve bildirimlerden çok daha iyi çünkü protokolleri veya bu "çirkin" bildirim sabitlerini belirtmenize gerek yok. Sunulan vc'deki kapanışı güzel tutan değişkenin adını yaparsanız, çok sezgisel bir kod olabilir, örn. Vc.didCancel, vc.didFinish ... Bunları, onu sunan vc'nin (eğer segmentler kullanıyorsanız) hazırlamada ayarlayabilirsiniz.
HixField

4

hmm, bildirim merkezini arayın ve bir bildirimde bilgileri geri verin. işte elmalar bunu üstleniyor - kimsenin başka önerisi yoksa bu yaklaşımı kişisel olarak alıyorum


Bağlantı aslında onu aşırı karmaşık hale getiriyor, ihtiyacınız olan tek şey bir gözlemci (ilk Görüntü Kontrolörü) ve ikinciden notif gönder. Seçicileri bir bildirime atayabilir ve ayrıca bildirim yoluyla geri gönderilen bilgileri alabilirsiniz.
theiOSDude

2

İkinci görünüm denetleyicisinde bir temsilci protokolü tanımlayın ve ilkini ikincinin temsilcisi yapın.

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.