UnfollowModalViewController และส่งข้อมูลกลับ


84

ฉันมีสองตัวควบคุมมุมมองfirstViewControllerและsecondViewController ฉันใช้รหัสนี้เพื่อเปลี่ยนเป็น secondViewController ของฉัน (ฉันกำลังส่งสตริงไปด้วย):

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

จากนั้นฉันใช้รหัสนี้ใน secondViewController เพื่อเปลี่ยนกลับไปที่ firstViewController:

[self dismissModalViewControllerAnimated:YES];

ทั้งหมดนี้ใช้งานได้ดี คำถามของฉันคือฉันจะส่งข้อมูลไปยัง firstViewController ได้อย่างไร ฉันต้องการส่งสตริงอื่นไปยัง firstViewController จาก secondViewController

คำตอบ:


142

คุณต้องใช้โปรโตคอลผู้ร่วมประชุม ... นี่คือวิธีการ:

ประกาศโปรโตคอลในไฟล์ส่วนหัวของ secondViewController ควรมีลักษณะดังนี้:

#import <UIKit/UIKit.h>

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


@interface SecondViewController : UIViewController
{
    id myDelegate;  
}

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

อย่าลืมสังเคราะห์ myDelegate ในไฟล์การนำไปใช้งาน (SecondViewController.m) ของคุณ:

@synthesize myDelegate;

ในไฟล์ส่วนหัวของ FirstViewController สมัครใช้โปรโตคอล SecondDelegate โดยทำสิ่งนี้:

#import "SecondViewController.h"

@interface FirstViewController:UIViewController <SecondDelegate>

ตอนนี้เมื่อคุณสร้างอินสแตนซ์ SecondViewController ใน FirstViewController คุณควรทำสิ่งต่อไปนี้:

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

สุดท้ายในไฟล์การใช้งานสำหรับตัวควบคุมมุมมองแรกของคุณ (FirstViewController.m) ใช้เมธอด SecondDelegate สำหรับ secondViewControllerDismissed:

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

ตอนนี้เมื่อคุณกำลังจะปิดตัวควบคุมมุมมองที่สองคุณต้องการเรียกใช้วิธีการที่ใช้งานในตัวควบคุมมุมมองแรก ส่วนนี้เป็นเรื่องง่าย สิ่งที่คุณทำคือในตัวควบคุมมุมมองที่สองของคุณเพิ่มรหัสก่อนรหัสปิด:

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

โปรโตคอลของผู้ร่วมประชุมมีประโยชน์อย่างมากและมีประโยชน์มาก จะเป็นการดีที่จะทำความคุ้นเคยกับพวกเขา :)

NSNotifications เป็นอีกวิธีหนึ่งในการทำเช่นนี้ แต่ตามแนวทางปฏิบัติที่ดีที่สุดฉันชอบใช้เมื่อต้องการสื่อสารผ่าน viewControllers หรือวัตถุหลายตัว นี่คือคำตอบที่ฉันโพสต์ไว้ก่อนหน้านี้หากคุณสงสัยเกี่ยวกับการใช้ NSNotifications: การเริ่มต้นเหตุการณ์ที่เกิดขึ้นกับตัวควบคุมมุมมองหลายตัวจากเธรดในผู้ร่วมประชุม

แก้ไข:

หากคุณต้องการส่งผ่านหลายอาร์กิวเมนต์โค้ดก่อนปิดจะมีลักษณะดังนี้:

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

ซึ่งหมายความว่าการใช้งานเมธอด SecondDelegate ภายใน firstViewController ของคุณจะมีลักษณะดังนี้:

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

ตามคู่มือการเขียนโปรแกรม View Controllerของ Apple สำหรับ iOSควรปิด secondViewController ในตัวควบคุมมุมมองการนำเสนอไม่ใช่ในตัวควบคุมที่นำเสนอ
Michael

ดูเหมือนว่าคุณยังไม่ได้ตั้งค่า delegate ของ UITableView คุณช่วยโพสต์เป็นคำถามพร้อมรหัสที่คุณมีและวนกลับมาได้ไหม ฉันอาจจะช่วยคุณได้
Sid

1
@ ไมเคิลเอกสารระบุว่าการเลิกโทรด้วยตนเองจะส่งต่อการโทรไปยังตัวควบคุมมุมมองการนำเสนอ นอกจากนี้การโทรหาตัวเองยังสะอาดกว่าด้วยวิธีนี้คุณไม่ต้องกังวลกับการสลับระหว่างการนำเสนอViewControllerและ parentViewController ขึ้นอยู่กับเวอร์ชัน iOS ที่คุณกำหนดเป้าหมาย (5 หรือก่อนหน้า)
Sid

1
@Resty ฉันเห็นด้วย; บล็อกมีประโยชน์อย่างน่าอัศจรรย์ ฉันกำลังพิจารณาที่จะเปลี่ยนคำตอบนี้เพื่อรองรับการบล็อกในบางจุด อย่างไรก็ตามในกรณีนี้ฉันปล่อยให้คำตอบของผู้ร่วมประชุมมองเห็นได้ในตอนนี้เพราะทำให้เรามีอิสระมากขึ้นในการจัดการกับวัตถุที่สามารถส่งผ่านไปยังโมดอลได้ ฉันแค่ขี้เกียจและจะอัปเดตคำตอบนี้เพื่อใช้บล็อกเร็ว ๆ นี้ :)
Sid

1
@sid ขอบคุณครับมันใช้งานได้สำหรับฉัน แต่คุณต้องแก้ไขเล็กน้อย หลายสิ่งหลายอย่างเปลี่ยนแปลงไป โปรดแก้ไข
ChenSmile

40

ฉันอาจจะออกจากสถานที่ที่นี่ แต่ฉันเริ่มชอบไวยากรณ์บล็อกมากกว่าวิธีการมอบหมาย / โปรโตคอลแบบละเอียดมาก หากคุณสร้าง vc2 จาก vc1 ให้มีคุณสมบัติบน vc2 ที่คุณสามารถตั้งค่าจาก vc1 ที่เป็นบล็อก!

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

จากนั้นเมื่อมีบางอย่างเกิดขึ้นใน vc2 ที่คุณต้องการบอกเกี่ยวกับ vc1 ให้ดำเนินการบล็อกที่คุณกำหนดไว้ใน vc1!

self.somethingHappenedInVC2(@"Hello!");

สิ่งนี้ช่วยให้คุณส่งข้อมูลจาก vc2 กลับไปที่ vc1 เช่นเดียวกับเวทมนตร์ IMO นี่ง่ายกว่า / สะอาดกว่าโปรโตคอลมาก บล็อกนั้นยอดเยี่ยมและจำเป็นต้องได้รับการยอมรับให้มากที่สุด

แก้ไข - ปรับปรุงตัวอย่าง

สมมติว่าเรามี mainVC ที่เราต้องการนำเสนอ modalVC ที่ด้านบนของชั่วคราวเพื่อรับอินพุตจากผู้ใช้ ในการนำเสนอ modalVC นั้นจาก mainVC เราจำเป็นต้องจัดสรร / เริ่มต้นภายใน mainVC สิ่งพื้นฐานสวย ๆ เมื่อเราสร้างออบเจ็กต์ modalVC นี้เรายังสามารถตั้งค่าคุณสมบัติบล็อกที่ช่วยให้เราสื่อสารระหว่างวัตถุ vc ทั้งสองได้อย่างง่ายดาย ลองยกตัวอย่างจากด้านบนและใส่คุณสมบัติ follwing ในไฟล์. h ของ modalVC:

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

จากนั้นใน mainVC ของเราหลังจากที่เราจัดสรร / เริ่มต้นวัตถุ modalVC ใหม่แล้วคุณตั้งค่าคุณสมบัติบล็อกของ modalVC ดังนี้:

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

ดังนั้นเราจึงแค่ตั้งค่าคุณสมบัติบล็อกและกำหนดสิ่งที่จะเกิดขึ้นเมื่อบล็อกนั้นถูกเรียกใช้งาน

สุดท้ายใน modalVC ของเราเราสามารถมี tableViewController ที่ได้รับการสนับสนุนโดยอาร์เรย์ dataSource ของสตริง เมื่อทำการเลือกแถวแล้วเราสามารถทำสิ่งนี้ได้:

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

และแน่นอนทุกครั้งที่เราเลือกแถวใน modalVC เราจะได้เอาต์พุตคอนโซลจากบรรทัด NSLog ของเรากลับมาที่ mainVC หวังว่าจะช่วยได้!


1
สิ่งนี้ควรใช้งานได้หรือไม่เมื่อใช้สตอรีบอร์ด ตอนนี้มันใช้ไม่ได้สำหรับฉัน เพียงแค่ออกจากข้อผิดพลาด lldb ความแตกต่างหลัก ที่ฉันเห็นคือการจัดสรร vc ตอนนี้เป็นโฟลว์สตอรีบอร์ดที่สร้างอินสแตนซ์ แก้ไขและฉันกำลังนำเสนอก่อนสร้างบล็อก แก้ไขแล้ว.
malaki1974

2
ฉันเห็นด้วยกับคุณ :) ฉันโพสต์คำตอบไว้ค่อนข้างนานแล้ว ตอนนี้ฉันสลับไปมาระหว่างการใช้บล็อก / โปรโตคอลขึ้นอยู่กับการใช้งาน เมื่อเห็นว่าเธรดนี้ยังคงใช้งานได้ดีจนถึงทุกวันนี้ฉันควรแก้ไขคำตอบของฉันเพื่อรวมบล็อก
Sid

1
คำตอบนี้ต้องได้รับการยอมรับเนื่องจากสิ่งนี้นำมาซึ่งโซลูชันที่ใช้งานง่ายที่สุด
Sukitha Udugamasooriya

2
จากสองคำตอบที่เหมาะสมนี่คือคำตอบที่ดีที่สุด!
kygcoleman

1
นี่เป็นวิธีที่ฉันชอบที่สุด อย่างรวดเร็วสิ่งนี้จะสำเร็จได้ด้วยการปิด ดีกว่ามากจากนั้นผู้รับมอบสิทธิ์และการแจ้งเตือนเนื่องจากคุณไม่จำเป็นต้องระบุโปรโตคอลหรือค่าคงที่การแจ้งเตือน "น่าเกลียด" เหล่านี้ หากคุณตั้งชื่อตัวแปรใน vc ที่นำเสนอซึ่งถือการปิดได้ดีอาจเป็นรหัสที่ใช้งานง่ายเช่น Vc.didCancel, vc.didFinish ... คุณสามารถตั้งค่าเหล่านี้ได้ในการจัดเตรียมสำหรับการกำหนดค่า f vc ที่นำเสนอ (หากคุณกำลังใช้ segues)
HixField

4

อืมมองหาศูนย์การแจ้งเตือนและส่งข้อมูลกลับในการแจ้งเตือน นี่คือแอปเปิ้ลรับมัน - ฉันใช้แนวทางนี้เป็นการส่วนตัวเว้นแต่จะมีข้อเสนอแนะอื่นใด


ลิงก์นั้นซับซ้อนเกินจริงสิ่งที่คุณต้องมีคือผู้สังเกตการณ์ (ตัวควบคุมมุมมองแรก) และส่งการแจ้งเตือนจากวินาที คุณสามารถกำหนดตัวเลือกให้กับการแจ้งเตือนและรับข้อมูลที่ส่งกลับผ่านการแจ้งเตือนได้เช่นกัน
theiOSDude

2

กำหนดโปรโตคอลผู้รับมอบสิทธิ์ในตัวควบคุมมุมมองที่สองและกำหนดให้โปรโตคอลแรกเป็นผู้รับมอบสิทธิ์ที่สอง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.