बर्खास्त करेंमॉडल दृश्य नियंत्रक और डेटा वापस पास करें


84

मेरे पास दो दृश्य नियंत्रक हैं, पहला दृश्य नियंत्रक और दूसरा दृश्य नियंत्रक । मैं इस कोड का उपयोग अपने दूसरे दृश्य स्विच करने के लिए कर रहा हूं (मैं इसे एक स्ट्रिंग भी दे रहा हूं):

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

फिर मैं पहले दृश्य में वापस स्विच करने के लिए सेकंड कोड में इस कोड का उपयोग करता हूं।

[self dismissModalViewControllerAnimated:YES];

यह सब ठीक काम करता है। मेरा सवाल है, मैं पहली बार कैसे डेटा को पास करूंगा? मैं पहले दृश्य में एक अलग स्ट्रिंग पास करना चाहूंगा दूसरे दृश्यकंट्रोलर से।

जवाबों:


142

आपको डेलिकेट प्रोटोकॉल का उपयोग करने की आवश्यकता है ... यह कैसे करना है:

अपने दूसरे दृश्य नियंत्रक के हेडर फ़ाइल में एक प्रोटोकॉल घोषित करें। इसे ऐसा दिखना चाहिए:

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

अब जब आप FirstViewController में SecondViewController इंस्टेंट करते हैं, तो आपको निम्नलिखित करना चाहिए:

// 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 की विधि लागू करें:

- (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 ऐसा करने का एक और तरीका है, लेकिन एक सर्वोत्तम अभ्यास के रूप में, मैं इसका उपयोग तब करना पसंद करता हूं जब मैं कई व्यू कॉन्ट्रोलर्स या ऑब्जेक्ट्स में संचार करना चाहता हूं। यदि आप NSNotifications का उपयोग करने के बारे में उत्सुक हैं, तो यहां एक उत्तर मैंने पहले पोस्ट किया है: Appdelegate में एक थ्रेड से कई व्यू-कंट्रोलर के पार फायरिंग की घटनाएं

संपादित करें:

यदि आप कई तर्क पारित करना चाहते हैं, तो खारिज करने से पहले कोड इस तरह दिखता है:

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

इसका मतलब है कि आपके FirstViewController के अंदर आपका SecondDelegate विधि कार्यान्वयन अब इस तरह दिखाई देगा:

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

IOS के लिए Apple के व्यू कंट्रोलर प्रोग्रामिंग गाइड के अनुसार, दूसरे व्यू कंट्रोलर को प्रेजेंटिंग व्यू कंट्रोलर में खारिज किया जाना चाहिए, न कि प्रस्तुत में।
माइकल

लगता है जैसे आपने UITableView के प्रतिनिधि को सेट नहीं किया है। क्या आप इसे एक प्रश्न के रूप में पोस्ट कर सकते हैं, जिस कोड के साथ आपके पास है और वापस सर्कल है? मैं आपकी मदद करने में सक्षम हो सकता हूं।
सिड

1
@ मिचेल डॉक्यूमेंटेशन में कहा गया है कि कॉलिंग सेल्फ डिसकस को कॉल फॉरवर्डिंग प्रेजेंटिंग व्यू कंट्रोलर को करता है। इसके अलावा, स्वयं को कॉल करना इस तरह से क्लीनर है कि आप जिस iOS संस्करण को लक्षित कर रहे हैं (5 या उससे पहले) के आधार पर presentingViewController और parentViewController के बीच स्विच करने के बारे में चिंता करने की ज़रूरत नहीं है।
सिड

1
@ ईमानदारी मैं सहमत हूँ; ब्लॉक आश्चर्यजनक रूप से उपयोगी हैं। मैं कुछ बिंदुओं पर समर्थन ब्लॉकों में इस उत्तर को बदलने पर विचार कर रहा था। हालाँकि इस मामले में, मैंने अभी के लिए दिखाई देने वाले प्रतिनिधि के जवाब को छोड़ दिया क्योंकि यह हमें उन वस्तुओं में हेरफेर करने के लिए थोड़ी अधिक स्वतंत्रता देता है जिन्हें मोडल में पारित किया जा सकता था। मैं सिर्फ आलसी हूं और जल्द ही ब्लॉक का उपयोग करने के लिए इस उत्तर को अपडेट करूंगा :)
सिड

1
@ एसआईडी धन्यवाद भाई यह मेरे लिए काम करता है लेकिन यू थोड़ा संशोधित करने की आवश्यकता है। जितनी चीजें बदल गईं। कृपया इसे संपादित करें
ChenSmile

40

मैं यहां से बाहर का रास्ता बना सकता हूं, लेकिन मैं ब्लॉक सिंटैक्स को बहुत वर्बोस डेलीगेट / प्रोटोकॉल दृष्टिकोण के लिए पसंद करना शुरू कर रहा हूं। यदि आप vc1 से vc2 बनाते हैं, तो vc2 पर एक गुण रखें जिसे आप vc1 से सेट कर सकते हैं जो एक ब्लॉक है!

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

तब, जब vc2 में कुछ ऐसा होता है, जिसके बारे में आप vc1 को बताना चाहते हैं, तो उस ब्लॉक को निष्पादित करें जिसे आपने vc1 में परिभाषित किया है!

self.somethingHappenedInVC2(@"Hello!");

यह आपको vc2 से vc1 पर डेटा भेजने की अनुमति देता है। बिल्कुल जादू की तरह। IMO, यह प्रोटोकॉल की तुलना में बहुत आसान / क्लीनर है। ब्लॉक भयानक हैं और जितना संभव हो उतना गले लगाने की आवश्यकता है।

EDIT - बेहतर उदाहरण

मान लीजिए कि हमारे पास एक मेनवीसी है जिसे हम उपयोगकर्ता से कुछ इनपुट प्राप्त करने के लिए अस्थायी रूप से एक मोडलवीवी पेश करना चाहते हैं। MainVC से उस modalVC को प्रस्तुत करने के लिए, हमें इसे mainVC के अंदर आवंटित / इनिट करने की आवश्यकता है। सुंदर बुनियादी सामान। खैर जब हम इस modalVC ऑब्जेक्ट को बनाते हैं, तो हम उस पर एक ब्लॉक प्रॉपर्टी भी सेट कर सकते हैं, जो हमें दोनों vc ऑब्जेक्ट्स के बीच आसानी से संवाद करने की अनुमति देता है। तो चलिए ऊपर से उदाहरण लेते हैं और follwing संपत्ति को modalVC की .h फ़ाइल में रखते हैं:

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

उसके बाद, हम एक नए modalVC ऑब्जेक्ट को आवंटित / init'd करने के बाद, हमारे mainVC में, आप इस के साथ 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 हो सकता है जो स्ट्रिंग्स के डेटा स्रोत सरणी द्वारा समर्थित है। एक बार पंक्ति चयन हो जाने के बाद, हम कुछ ऐसा कर सकते हैं:

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

और हां, हर बार जब हम modalVC में एक पंक्ति का चयन करते हैं, तो हम अपने NSLog लाइन से mainVC में कंसोल आउटपुट प्राप्त करने जा रहे हैं। उम्मीद है की वो मदद करदे!


1
स्टोरीबोर्ड का उपयोग करते समय क्या यह अभी भी काम करना चाहिए? अभी यह मेरे लिए काम नहीं कर रहा है। बस एक lldb त्रुटि के साथ आता है। मुख्य अंतर है। मैं देख सकता हूं कि vc का आवंटन अब एक त्वरित स्टोरीबोर्ड प्रवाह है। EDIT और मैं ब्लॉक बनाने से पहले प्रस्तुत कर रहे थे। फिक्स्ड।
malaki1974

2
मैं आपसे सहमत हूं :) मैंने अपना उत्तर काफी पहले पोस्ट किया था। अब, मैं उपयोग के आधार पर ब्लॉक / प्रोटोकॉल का उपयोग करने के बीच स्विच करता हूं। यह देखते हुए कि यह धागा आज भी काफी सक्रिय है, मुझे किसी बिंदु पर, ब्लॉक शामिल करने के लिए अपने उत्तर को संपादित करना चाहिए।
सिड

1
इस उत्तर को स्वीकार करने की आवश्यकता है क्योंकि यह सबसे सहज समाधान लाता है।
सुचिता उदुगमसूरिया

2
दो उपयुक्त उत्तरों में से, यह सबसे अच्छा है!
किग्क्लेमैन

1
यह अब तक का मेरा पसंदीदा तरीका है। स्विफ्ट में यह फिर क्लोजर के साथ पूरा किया जाता है। बहुत बेहतर तो प्रतिनिधियों और सूचनाओं को क्योंकि आपको प्रोटोकॉल या इन "बदसूरत" अधिसूचना स्थिरांक को निर्दिष्ट करने की आवश्यकता नहीं है। यदि आप प्रस्तुत vc में वैरिएबल का नाम बनाते हैं जो क्लोजर को अच्छा रखता है तो यह बहुत सहज कोड हो सकता है जैसे। Vc.didCancel, vc.didFinish ... आप इन्हें तैयार कर सकते हैं fForSegue च में vc जो इसे प्रस्तुत करता है (यदि आप सेग का उपयोग कर रहे हैं)।
हिक्सफिल्ड

4

हम्म, सूचना केंद्र की तलाश करें और सूचना में वापस सूचना पास करें। यहाँ सेब इस पर ले जाता है - मैं इस दृष्टिकोण को व्यक्तिगत रूप से लेता हूं जब तक कि किसी के पास कोई अन्य सुझाव न हो


लिंक वास्तव में इसे जटिल बनाता है, आपको बस एक पर्यवेक्षक (पहला दृश्य नियंत्रक) की आवश्यकता है और दूसरे से नोटिफ़ भेजना है। आप एक सूचना के लिए चयनकर्ताओं को असाइन कर सकते हैं और अधिसूचना के माध्यम से वापस भेजी गई जानकारी भी प्राप्त कर सकते हैं।
theiOSDude

2

दूसरे दृश्य नियंत्रक में एक प्रतिनिधि प्रोटोकॉल को परिभाषित करें और पहले एक को दूसरे का प्रतिनिधि बनाएं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.