व्यू कंट्रोलर्स के बीच डेटा पास करना


1372

मैं iOS और ऑब्जेक्टिव-सी और पूरे MVC प्रतिमान के लिए नया हूं और मैं निम्नलिखित के साथ फंस गया हूं:

मेरे पास एक दृश्य है जो डेटा प्रविष्टि फॉर्म के रूप में कार्य करता है और मैं उपयोगकर्ता को कई उत्पादों का चयन करने का विकल्प देना चाहता हूं। उत्पादों को एक UITableViewControllerऔर दृश्य के साथ सूचीबद्ध किया गया है और मैंने कई चयन सक्षम किए हैं।

मेरा सवाल है, मैं डेटा को एक दृश्य से दूसरे में कैसे स्थानांतरित करूं? मैं UITableViewएक सरणी में चयनों को धारण करूंगा , लेकिन फिर मैं उस डेटा को पिछले डेटा प्रविष्टि फॉर्म दृश्य में कैसे पास करूं ताकि इसे फॉर्म जमा करने पर अन्य डेटा के साथ कोर डेटा में बचाया जा सके?

मैंने आसपास देखा और कुछ लोगों को ऐप के प्रतिनिधि में एक सरणी घोषित करने के लिए देखा। मैंने सिंग्लेटन्स के बारे में कुछ पढ़ा है, लेकिन यह नहीं समझ पाया कि ये क्या हैं और मैंने डेटा मॉडल बनाने के बारे में कुछ पढ़ा है।

यह प्रदर्शन करने का सही तरीका क्या होगा और मैं इसके बारे में कैसे जाऊंगा?

जवाबों:


1683

स्टैकओवरफ्लो पर यह सवाल यहां बहुत लोकप्रिय प्रतीत होता है, इसलिए मैंने सोचा कि मैं कोशिश करूं और मेरे जैसे आईओएस की दुनिया में शुरू होने वाले लोगों की मदद करने के लिए बेहतर जवाब दूं।

मुझे उम्मीद है कि यह जवाब लोगों को समझने के लिए पर्याप्त है और मुझे कुछ भी याद नहीं है।

डेटा अग्रेषित करना

किसी अन्य व्यू कंट्रोलर से व्यू कंट्रोलर के सामने डेटा पास करना। यदि आप किसी ऑब्जेक्ट कंट्रोलर से एक व्यू कंट्रोलर से दूसरे व्यू कंट्रोलर पर एक ऑब्जेक्ट / वैल्यू पास करना चाहते हैं, तो आप इसका इस्तेमाल नेविगेशन स्टैक पर करने पर जोर दे सकते हैं।

इस उदाहरण के लिए, हमारे पास होगा ViewControllerAऔरViewControllerB

एक BOOLमान पास करने के ViewControllerAलिए ViewControllerBहम निम्न कार्य करेंगे।

  1. के ViewControllerB.hलिए एक संपत्ति बनाने मेंBOOL

    @property (nonatomic, assign) BOOL isSomethingEnabled;
  2. , ViewControllerAतो आपको इसके बारे में बताने की आवश्यकता है ViewControllerBताकि आप इसका उपयोग कर सकें

    #import "ViewControllerB.h"

    फिर जहां आप उदाहरण के लिए दृश्य लोड करना चाहते हैं। didSelectRowAtIndexया इससे पहले कि आप इसे नौसेना स्टैक पर धकेलें, कुछ IBActionको संपत्ति सेट करने की आवश्यकता है ViewControllerB

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

    इस सेट हो जाएगा isSomethingEnabledमें ViewControllerBकरने के लिए BOOLमूल्य YES

सेगमेंट का उपयोग करके डेटा फ़ॉरवर्ड करना

यदि आप स्टोरीबोर्ड का उपयोग कर रहे हैं तो आप सबसे अधिक संभावना का उपयोग कर रहे हैं और आगे डेटा पास करने के लिए इस प्रक्रिया की आवश्यकता होगी। यह उपरोक्त के समान है, लेकिन दृश्य नियंत्रक को पुश करने से पहले डेटा को पास करने के बजाय, आप नामक एक विधि का उपयोग करते हैं

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

तो एक BOOLसे पारित ViewControllerAकरने के लिए ViewControllerBहम निम्नलिखित करेंगे:

  1. के ViewControllerB.hलिए एक संपत्ति बनाने मेंBOOL

    @property (nonatomic, assign) BOOL isSomethingEnabled;
  2. , ViewControllerAतो आपको इसके बारे में बताने की आवश्यकता है ViewControllerBताकि आप इसका उपयोग कर सकें

    #import "ViewControllerB.h"
  3. से एक segue बनाएं ViewControllerAको ViewControllerBस्टोरीबोर्ड पर है और यह एक पहचानकर्ता देना, इस उदाहरण में हम यह फोन करता हूँ"showDetailSegue"

  4. अगला, हमें उस विधि को जोड़ने की आवश्यकता ViewControllerAहै जब किसी भी सेगमेंट को निष्पादित किया जाता है, इस वजह से हमें यह पता लगाने की आवश्यकता है कि किस सेग को बुलाया गया था और फिर कुछ करें। हमारे उदाहरण में हम जाँच करेंगे "showDetailSegue"और अगर यह प्रदर्शन किया जाता है तो हम अपना BOOLमान पास करेंगेViewControllerB

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

    यदि आपके पास अपने विचार एक नेविगेशन नियंत्रक में एम्बेड किए गए हैं, तो आपको ऊपर दिए गए विधि को थोड़ा निम्नलिखित में बदलने की आवश्यकता है

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

    इस सेट हो जाएगा isSomethingEnabledमें ViewControllerBकरने के लिए BOOLमूल्य YES

डेटा वापस पास करना

डेटा को वापस से पास करने के ViewControllerBलिए ViewControllerAआपको प्रोटोकॉल और डेलिगेट्स या ब्लॉक का उपयोग करने की आवश्यकता होती है , बाद वाले को कॉलबैक के लिए शिथिल युग्मित तंत्र के रूप में इस्तेमाल किया जा सकता है।

ऐसा करने के लिए हम ViewControllerAएक प्रतिनिधि बनाएंगे ViewControllerB। यह हमें डेटा वापस भेजने में सक्षम ViewControllerBकरने के लिए एक संदेश वापस भेजने की अनुमति देता है ViewControllerA

के लिए ViewControllerAहोने के लिए के एक प्रतिनिधि ViewControllerBयह के अनुरूप होना चाहिए ViewControllerBके प्रोटोकॉल जो हम निर्दिष्ट करना होगा। यह बताता है ViewControllerAकि इसे किन तरीकों को लागू करना चाहिए।

  1. में ViewControllerB.h, नीचे दिए गए #import, लेकिन इसके बाद के संस्करण @interfaceआप प्रोटोकॉल निर्दिष्ट करें।

    @class ViewControllerB;
    
    @protocol ViewControllerBDelegate <NSObject>
    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
    @end
  2. अगले अभी भी ViewControllerB.hआप में एक delegateसंपत्ति की स्थापना और में संश्लेषित करने की जरूरत हैViewControllerB.m

    @property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
  3. में ViewControllerBहम पर एक संदेश फोन delegateजब हम दृश्य नियंत्रक पॉप।

    NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
    [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
  4. वह इसके लिए है ViewControllerB। अब ViewControllerA.h, ViewControllerAआयात ViewControllerBऔर इसके प्रोटोकॉल के अनुरूप बताने के लिए ।

    #import "ViewControllerB.h"
    
    @interface ViewControllerA : UIViewController <ViewControllerBDelegate>
  5. में ViewControllerA.mहमारे प्रोटोकॉल से निम्न विधि को लागू

    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
    {
        NSLog(@"This was returned from ViewControllerB %@",item);
    }
  6. viewControllerBनेविगेशन स्टैक पर धकेलने से पहले हमें यह बताना होगा ViewControllerBकि ViewControllerAयह उसका प्रतिनिधि है, अन्यथा हमें एक त्रुटि मिलेगी।

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

संदर्भ

  1. नियंत्रक नियंत्रक गाइड में अन्य दृश्य नियंत्रकों के साथ संचार करने के लिए प्रतिनिधिमंडल का उपयोग करना
  2. डेलिगेट पैटर्न

NSNotification केंद्र डेटा पास करने का एक और तरीका है।

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

डेटा को एक कक्षा से दूसरी कक्षा में वापस भेजना (ए क्लास किसी भी कंट्रोलर, नेटवर्क / सेशन मैनेजर, यूविवि सबक्लास या किसी अन्य क्षेत्र में हो सकता है)

ब्लॉक अनाम कार्य हैं।

यह उदाहरण नियंत्रक B से नियंत्रक A के डेटा को पास करता है

एक ब्लॉक को परिभाषित करें

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

ब्लॉक हैंडलर (श्रोता) जोड़ें, जहाँ आपको एक मान की आवश्यकता होती है (उदाहरण के लिए आपको नियंत्रक की एपीआई प्रतिक्रिया की आवश्यकता है या आपको A पर ContorllerB डेटा की आवश्यकता है)

// in ContollerA.m

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

कंट्रोलर बी के पास जाएं

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

फायर ब्लॉक

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

ब्लॉक के लिए एक और कार्य उदाहरण


24
क्या हमें @class ViewControllerB;@protocol परिभाषा के ऊपर भी रखना होगा? इसके बिना मुझे लाइन में ViewControllerB पर एक "अपेक्षित प्रकार" त्रुटि मिलती है: घोषणा के - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item; भीतर@protocol
एलन-पी

4
यह बहुत अच्छा काम करता है। जैसा कि एलन-पी कहते हैं, @class ViewControllerB लिखना न भूलें; प्रोटोकॉल के ऊपर अन्यथा आपको "अपेक्षित एक प्रकार" त्रुटि प्राप्त होगी।
एंड्रयू डेविस

6
आपको वापस जाने के लिए प्रतिनिधियों की आवश्यकता नहीं है, बस आराम का उपयोग करें।
मल्हल

4
जब मैंने "viewControllerB.delegate = self?" डाला। ViewControllerB में मुझे एक त्रुटि मिल रही है। असंगत प्रकार 'ViewControllerB * const __strong' से 'id <ViewControllerBDelegate>' को असाइन करते हुए, मुझे यकीन नहीं है कि मैं क्या गलत कर रहा हूं। क्या कोई मदद कर सकता है? इसके अलावा मुझे बदलना पड़ा: initWithNib -> initWithNibName।
uplearnedu.com 21

4
यदि आप उपयोग कर रहे हैं तो आपको इसके स्थान NavigationControllerपर उपयोग [self.navigationController pushViewController:viewController animated:YES];करना होगा[self pushViewController:viewControllerB animated:YES];
Nazir

192

तीव्र

StackOverflow के आसपास और यहाँ स्पष्टीकरण के टन हैं, लेकिन अगर आप अभी शुरुआत कर रहे हैं तो काम करने के लिए कुछ बुनियादी पाने की कोशिश कर रहे हैं, इस YouTube ट्यूटोरियल को देखने की कोशिश करें (यह आखिरकार मुझे यह समझने में मदद करता है कि यह कैसे करना है)।

डेटा को अगले व्यू कंट्रोलर के पास भेजना

निम्नलिखित वीडियो पर आधारित एक उदाहरण है। विचार यह है कि पहले दृश्य नियंत्रक में पाठ क्षेत्र से एक स्ट्रिंग को दूसरे दृश्य नियंत्रक में लेबल पर पास किया जाए।

यहां छवि विवरण दर्ज करें

इंटरफ़ेस बिल्डर में स्टोरीबोर्ड लेआउट बनाएं। सेग करने के लिए, आप बस Controlबटन पर क्लिक करें और सेकंड व्यू कंट्रोलर पर खींचें।

पहले देखें नियंत्रक

प्रथम दृश्य नियंत्रक के लिए कोड है

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

}

दूसरा दृश्य नियंत्रक

और दूसरा दृश्य नियंत्रक के लिए कोड है

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
    }

}

मत भूलना

  • UITextFieldऔर के लिए आउटलेट हुक UILabel
  • IB में उपयुक्त स्विफ्ट फ़ाइलों के लिए पहला और दूसरा दृश्य नियंत्रक सेट करें।

डेटा को पिछले व्यू कंट्रोलर को वापस पास करना

डेटा को दूसरे व्यू कंट्रोलर से फ़र्स्ट व्यू कंट्रोलर में वापस भेजने के लिए, आप एक प्रोटोकॉल और एक प्रतिनिधि का उपयोग करते हैं । यह वीडियो उस प्रक्रिया के बावजूद बहुत स्पष्ट चलना है:

निम्नलिखित वीडियो पर आधारित एक उदाहरण है (कुछ संशोधनों के साथ)।

यहां छवि विवरण दर्ज करें

इंटरफ़ेस बिल्डर में स्टोरीबोर्ड लेआउट बनाएं। फिर से, सेगमेंट बनाने के लिए, आप बस Controlबटन से दूसरे व्यू कंट्रोलर तक खींचें। सेग पहचानकर्ता को सेट करें showSecondViewController। इसके अलावा, निम्नलिखित कोड में नामों का उपयोग करके आउटलेट्स और कार्यों को हुक करना न भूलें।

पहले देखें नियंत्रक

प्रथम दृश्य नियंत्रक के लिए कोड है

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

हमारे कस्टम DataEnteredDelegateप्रोटोकॉल के उपयोग पर ध्यान दें ।

दूसरा दृश्य नियंत्रक और प्रोटोकॉल

दूसरे दृश्य नियंत्रक के लिए कोड है

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

ध्यान दें कि protocolव्यू कंट्रोलर क्लास के बाहर है।

बस। ऐप को चलाना अब आपको दूसरे व्यू कंट्रोलर से पहले में डेटा वापस भेजने में सक्षम होना चाहिए।


नवीनतम स्विफ्ट अपडेट में से कुछ को देखते हुए, क्या यह अभी भी लागू करने के लिए एक सामान्य पैटर्न है?
piofusco

4
स्विफ्ट के अधिकांश अपडेट जो मैंने देखे हैं, वे अपेक्षाकृत मामूली रूप से छोटे-छोटे बदलाव किए गए हैं, न कि डेटा कंट्रोलर्स के बीच डेटा कैसे पास होता है, इसमें बदलाव। अगर मुझे इस तरह का कोई बड़ा बदलाव आता है, तो मैं अपने उत्तर को अपडेट करूंगा।
सुरगछ

2
ऑफटॉपिक - iOS के पास नए व्यू कंट्रोलर के लिए मापदंडों को पास करने के लिए ऐसा एक बदसूरत तरीका है, अविश्वसनीय - आपको कॉल करते समय एक जगह नहीं, बल्कि कुछ अन्य में पैरामीटर सेट करना होगा। इस संबंध में एंड्रॉइड का एक बेहतर दृष्टिकोण है - जब आप एक गतिविधि शुरू करते हैं तो आप किसी भी डेटा (अच्छी तरह से, लगभग) को उसके शुरुआती इरादे से पारित कर सकते हैं। आसान। न कास्ट करने की जरूरत न कुछ करने की। कॉलर के लिए रिटर्न वैल्यू पास करना एक आवश्यक बात है, प्रतिनिधि की जरूरत नहीं है। बेशक यह बदसूरत दृष्टिकोण का उपयोग करना संभव है, वहां कोई समस्या नहीं))
मिक्साज़

1
@ हिमांशु, पहले दूसरे व्यू कंट्रोलर का संदर्भ लें। फिर सार्वजनिक चर को अपडेट करें जिसमें यह शामिल है।
सूर्याग

8
@शहद। मुझे लगता है कि "प्रतिनिधि" शब्द भ्रामक है। मुझे "कार्यकर्ता" शब्द का उपयोग करने दें। "कार्यकर्ता" (पहला दृश्य नियंत्रक) जो कुछ भी करता है वह "बॉस" (दूसरा दृश्य नियंत्रक) उसे करने के लिए कहता है। "बॉस" नहीं जानता कि उसका "कार्यकर्ता" कौन होगा; यह कोई भी हो सकता है। तो पहले दृश्य नियंत्रक ("कार्यकर्ता" वर्ग) में, यह कहता है, मैं आपका "कार्यकर्ता" बनूंगा। आप मुझे बताएं कि लेबल में क्या लिखना है और मैं इसे आपके लिए करूंगा। इस प्रकार, का secondViewController.delegate = selfअर्थ है "मैं मालिक के कार्यकर्ता होने के लिए सहमत हूं।" एक और उदाहरण और अधिक स्पष्टीकरण के लिए इस उत्तर को देखें ।
सुरगाछ

136

एमवीसी में एम "मॉडल" के लिए है और एमवीसी प्रतिमान में मॉडल कक्षाओं की भूमिका एक कार्यक्रम के डेटा का प्रबंधन करना है। एक मॉडल एक दृश्य के विपरीत है - एक दृश्य जानता है कि डेटा कैसे प्रदर्शित किया जाए, लेकिन यह डेटा के साथ क्या करना है, इसके बारे में कुछ भी नहीं जानता है, जबकि एक मॉडल डेटा के साथ काम करने के तरीके के बारे में सब कुछ जानता है, लेकिन इसे कैसे प्रदर्शित किया जाए, इसके बारे में कुछ नहीं। मॉडल जटिल हो सकते हैं, लेकिन उनका होना आवश्यक नहीं है - आपके ऐप के लिए मॉडल स्ट्रिंग्स या शब्दकोशों के एक सरणी के रूप में सरल हो सकता है।

एक नियंत्रक की भूमिका दृश्य और मॉडल के बीच मध्यस्थता करना है। इसलिए, उन्हें एक या अधिक दृश्य ऑब्जेक्ट और एक या अधिक मॉडल ऑब्जेक्ट के संदर्भ की आवश्यकता होती है। मान लें कि आपका मॉडल एक प्रकार का शब्दकोष है, जिसमें प्रत्येक शब्दकोश आपकी तालिका में एक पंक्ति का प्रतिनिधित्व करता है। आपके एप्लिकेशन के लिए रूट दृश्य उस तालिका को प्रदर्शित करता है, और यह फ़ाइल से सरणी को लोड करने के लिए जिम्मेदार हो सकता है। जब उपयोगकर्ता तालिका में एक नई पंक्ति जोड़ने का फैसला करता है, तो वे कुछ बटन टैप करते हैं और आपका नियंत्रक एक नया (परिवर्तनशील) शब्दकोश बनाता है और इसे सरणी में जोड़ता है। पंक्ति को भरने के लिए, नियंत्रक एक विस्तार दृश्य नियंत्रक बनाता है और इसे नया शब्दकोश देता है। डिटेल व्यू कंट्रोलर डिक्शनरी में भरता है और लौटता है। शब्दकोश पहले से ही मॉडल का हिस्सा है, इसलिए कुछ और होने की आवश्यकता नहीं है।


95

आईओएस में विभिन्न तरीकों से एक डेटा प्राप्त किया जा सकता है। उदाहरण के लिए -

  1. दूसरे वर्ग के आवंटन के बाद प्रत्यक्ष आरंभीकरण।
  2. प्रतिनिधिमंडल - डेटा वापस पारित करने के लिए
  3. अधिसूचना - एक ही समय में कई कक्षाओं में डेटा प्रसारित करने के लिए
  4. NSUserDefaultsबाद में इसे एक्सेस करने के लिए इसमें बचत करना
  5. एकल वर्ग
  6. डेटाबेस और अन्य भंडारण तंत्र जैसे कि प्लिस्ट, आदि।

लेकिन एक अलग वर्ग के मूल्य को पारित करने के सरल परिदृश्य के लिए जिसका आवंटन वर्तमान वर्ग में किया जाता है, सबसे सामान्य और पसंदीदा तरीका आवंटन के बाद मूल्यों की प्रत्यक्ष सेटिंग होगी। यह अग्रानुसार होगा:-

हम इसे दो नियंत्रकों - नियंत्रक 1 और नियंत्रक 2 का उपयोग करके समझ सकते हैं

नियंत्रक 1 वर्ग में मान लें कि आप नियंत्रक 2 ऑब्जेक्ट बनाना चाहते हैं और इसे स्ट्रिंग मूल्य के साथ धक्का दिया जा रहा है। इसे इस प्रकार किया जा सकता है: -

- (void)pushToController2 {

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

नियंत्रक 2 वर्ग के कार्यान्वयन में यह कार्य निम्नानुसार होगा-

@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

आप इस तरह से सीधे नियंत्रक 2 वर्ग के गुण भी निर्धारित कर सकते हैं:

- (void)pushToController2 {

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

कई मान पास करने के लिए आप कई मापदंडों का उपयोग कर सकते हैं जैसे: -

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

या यदि आपको 3 से अधिक मापदंडों को पारित करने की आवश्यकता है, जो एक सामान्य विशेषता से संबंधित हैं, तो आप एक मॉडल वर्ग के लिए मूल्यों को संग्रहीत कर सकते हैं और उस मॉडल को पास कर सकते हैं।

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

यदि आप चाहते हैं तो संक्षेप में -

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.

उम्मीद है की यह मदद करेगा


84

अधिक शोध के बाद ऐसा लगा कि प्रोटोकॉल और डेलिगेट्स ऐसा करने का सही / Apple पसंदीदा तरीका है।

मैं इस उदाहरण का उपयोग कर समाप्त हुआ

दृश्य नियंत्रकों और अन्य वस्तुओं के बीच डेटा साझा करना @ iPhone देव एसडीके

ठीक काम किया और मुझे अपने विचारों के बीच आगे और पीछे एक स्ट्रिंग और एक सरणी पास करने की अनुमति दी।

आपकी सभी मदद का धन्यवाद


3
प्रोटोकॉल और प्रतिनिधियों का उपयोग न करें, बस खोलना का उपयोग करें।
मल्हल

1
@ अगर आप स्टोरीबोर्ड का उपयोग नहीं करते हैं तो क्या होगा ??
इवान आर

मुझे बेकार प्रोटोकॉल और प्रतिनिधियों से भी नफरत है। @माल
डॉनसॉन्ग

@ EvanR आप कोड में सेगमेंट बना और बना सकते हैं। सभ एक ही है।
डॉनसॉन्ग

1
अनिवार्य रूप से इस पृष्ठ पर संपूर्ण क्यूए "कंटेनर विचारों से पहले पुराने दिनों से" है। आप एक लाख वर्षों में कभी भी प्रोटोकॉल या प्रतिनिधियों से परेशान नहीं होंगे। किसी भी स्क्रीन पर आपके द्वारा की जाने वाली हर छोटी चीज वैसे भी एक कंटेनर दृश्य है, इसलिए, यह प्रश्न वास्तव में अब मौजूद नहीं है - आपके पास पहले से ही सभी कंटेनर दृश्यों से "ऊपर और नीचे" सभी संदर्भ हैं।
फेटी

66

मुझे पासिंग ब्लॉक के साथ सबसे सरल और सबसे सुंदर संस्करण लगता है। आइए नाम नियंत्रक को देखें जो "ए" के रूप में लौटाए गए डेटा का इंतजार करता है और "बी" के रूप में रिटर्न कंट्रोलर देखता है। इस उदाहरण में हम 2 मान प्राप्त करना चाहते हैं: टाइप 1 का पहला और टाइप 2 का दूसरा।

मान लें कि हम स्टोरीबोर्ड का उपयोग करते हैं, पहला नियंत्रक कॉलबैक ब्लॉक सेट करता है, उदाहरण के लिए सेगमेंट की तैयारी के दौरान:

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

    }
}

और "बी" व्यू कंट्रोलर को कॉलबैक प्रॉपर्टी घोषित करनी चाहिए, BViewController.h:

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

लागू होने वाली फ़ाइल में BVVController.m के बाद जब हम अपने कॉलबैक को वापस करने के लिए वांछित मान रखते हैं, उसे कॉल किया जाना चाहिए:

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

एक बात याद रखें कि ब्लॉक का उपयोग करने के लिए अक्सर मजबूत और __weak संदर्भों को प्रबंधित करने की आवश्यकता होती है जैसे कि यहां बताया गया है


एक अलग संपत्ति होने के बजाय कॉलबैक ब्लॉक के लिए एक मान क्यों नहीं है?
तैमुकिन

56

दिए गए कई उत्तरों में कुछ अच्छी जानकारी है, लेकिन कोई भी प्रश्न को पूरी तरह से संबोधित नहीं करता है।

प्रश्न व्यू कंट्रोलर्स के बीच सूचनाओं को पास करने के बारे में पूछता है। दिए गए विशिष्ट उदाहरण विचारों के बीच से गुजरने वाली जानकारी के बारे में पूछते हैं, लेकिन आईओएस को स्व-घोषित नयापन दिया गया है, मूल पोस्टर संभावित रूप से viewControllers के बीच होता है, न कि विचारों के बीच (ViewControllers से किसी भी भागीदारी के बिना)। ऐसा लगता है कि सभी उत्तर दो दृश्य नियंत्रकों पर केंद्रित हैं, लेकिन क्या होगा यदि ऐप सूचना विनिमय में दो से अधिक दृश्य नियंत्रकों को शामिल करने की आवश्यकता है?

मूल पोस्टर ने सिंगलेट्स और ऐपडेलगेट के उपयोग के बारे में भी पूछा । इन सवालों के जवाब दिए जाने की जरूरत है।

इस प्रश्न को देखने में किसी और की मदद करने के लिए, जो पूर्ण उत्तर चाहता है, मैं इसे प्रदान करने का प्रयास करने जा रहा हूं।

अनुप्रयोग परिदृश्य

अत्यधिक काल्पनिक, सारगर्भित चर्चा करने के बजाय, यह ठोस अनुप्रयोगों को ध्यान में रखने में मदद करता है। दो-दृश्य-नियंत्रक स्थिति और अधिक-से-दो-दृश्य-नियंत्रक स्थिति को परिभाषित करने में मदद करने के लिए, मैं दो ठोस अनुप्रयोग परिदृश्यों को परिभाषित करने जा रहा हूं।

परिदृश्य एक: अधिकतम दो दृश्य नियंत्रकों को कभी भी जानकारी साझा करने की आवश्यकता होती है। आरेख देखें।

मूल समस्या का आरेख

आवेदन में दो दृश्य नियंत्रक हैं। एक ViewControllerA (डेटा एंट्री फॉर्म), और व्यू कंट्रोलर B (उत्पाद सूची) है। उत्पाद सूची में चयनित आइटम डेटा प्रविष्टि फॉर्म में टेक्स्ट बॉक्स में प्रदर्शित वस्तुओं से मेल खाना चाहिए। इस परिदृश्य में, ViewControllerA और ViewControllerB एक दूसरे के साथ सीधे संवाद करना चाहिए और कोई अन्य दृश्य नियंत्रक नहीं है।

परिदृश्य दो : दो से अधिक दृश्य नियंत्रकों को समान जानकारी साझा करने की आवश्यकता होती है। आरेख दो देखें।

घर सूची अनुप्रयोग आरेख

आवेदन में चार दृश्य नियंत्रक हैं। यह घर सूची का प्रबंधन करने के लिए एक टैब-आधारित अनुप्रयोग है। तीन दृश्य नियंत्रक एक ही डेटा के अलग-अलग फ़िल्टर किए गए दृश्य प्रस्तुत करते हैं:

  • ViewControllerA - लक्जरी आइटम
  • ViewControllerB - गैर-बीमित आइटम
  • ViewControllerC - संपूर्ण होम इन्वेंटरी
  • ViewControllerD - नया आइटम प्रपत्र जोड़ें

किसी भी समय एक व्यक्तिगत आइटम बनाया या संपादित किया जाता है, इसे अन्य दृश्य नियंत्रकों के साथ भी सिंक्रनाइज़ करना होगा। उदाहरण के लिए, यदि हम ViewControllerD में एक नाव को जोड़ते हैं, लेकिन यह अभी तक बीमा नहीं है, तो उपयोगकर्ता को ViewControllerA (लक्जरी आइटम), और ViewControllerC (संपूर्ण होम इन्वेंटरी) में भी जाने पर नाव दिखाई देनी चाहिए, लेकिन उपयोगकर्ता के पास जाने पर नहीं ViewControllerB (गैर-बीमित आइटम)। हमें न केवल नई वस्तुओं को जोड़ने के लिए चिंतित होना चाहिए, बल्कि उन वस्तुओं को हटाना भी होगा (जो किसी चार व्यू कंट्रोलर से अनुमति ली जा सकती हैं), या मौजूदा आइटम को संपादित करना (जिसे "नया आइटम जोड़ें" से अनुमति दी जा सकती है) संपादन के लिए)।

चूंकि सभी दृश्य नियंत्रकों को समान डेटा साझा करने की आवश्यकता होती है, इसलिए सभी चार दृश्य नियंत्रकों को सिंक्रनाइज़ेशन में बने रहने की आवश्यकता होती है, और इसलिए सभी अन्य दृश्य नियंत्रकों को किसी प्रकार का संचार करने की आवश्यकता होती है, जब भी कोई एकल दृश्य नियंत्रक अंतर्निहित डेटा को बदलता है। यह स्पष्ट रूप से स्पष्ट होना चाहिए कि हम इस परिदृश्य में प्रत्येक दृश्य नियंत्रक को एक-दूसरे दृश्य नियंत्रक से सीधे संवाद नहीं करना चाहते हैं। यदि यह स्पष्ट नहीं है, तो विचार करें कि क्या हमारे पास 20 अलग-अलग दृश्य नियंत्रक हैं (केवल 4 के बजाय)। किसी भी समय एक दृश्य नियंत्रक ने परिवर्तन किए जाने पर किसी भी अन्य 19 दृश्य नियंत्रकों को सूचित करना कितना मुश्किल और त्रुटि-रहित होगा?

समाधान: प्रतिनिधि और प्रेक्षक पैटर्न, और एकल

परिदृश्य एक में, हमारे पास कई व्यवहार्य समाधान हैं, जैसा कि अन्य उत्तर दिए गए हैं

  • segues
  • प्रतिनिधियों
  • सीधे नियंत्रकों पर गुण सेट करना
  • NSUserDefaults (वास्तव में एक खराब विकल्प)

परिदृश्य दो में, हमारे पास अन्य व्यवहार्य समाधान हैं:

  • ऑब्जर्वर पैटर्न
  • एकमात्र

एक सिंगलटन एक वर्ग का एक उदाहरण है, यह उदाहरण अपने जीवनकाल के दौरान अस्तित्व में एकमात्र उदाहरण है। एक सिंगलटन को इस तथ्य से अपना नाम मिलता है कि यह एकल उदाहरण है। आम तौर पर डेवलपर जो एकल का उपयोग करते हैं, उनके पास पहुंचने के लिए विशेष वर्ग विधियां हैं।

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

अब जब हम समझते हैं कि एक सिंगलटन क्या है, आइए चर्चा करते हैं कि एक सिंगलटन पर्यवेक्षक पैटर्न में कैसे फिट बैठता है। ऑब्जर्वर पैटर्न का उपयोग एक ऑब्जेक्ट के लिए किसी अन्य ऑब्जेक्ट द्वारा परिवर्तनों का जवाब देने के लिए किया जाता है। दूसरे परिदृश्य में, हमारे पास चार अलग-अलग दृश्य नियंत्रक हैं, जो सभी अंतर्निहित डेटा में परिवर्तन के बारे में जानना चाहते हैं। "अंतर्निहित डेटा" एकल उदाहरण, एक सिंगलटन से संबंधित होना चाहिए। "परिवर्तन के बारे में पता है" एकल के लिए किए गए परिवर्तनों को देखते हुए पूरा किया जाता है।

होम इन्वेंट्री एप्लिकेशन में एक वर्ग का एक एकल उदाहरण होगा जो इन्वेंट्री आइटम की सूची का प्रबंधन करने के लिए डिज़ाइन किया गया है। प्रबंधक घरेलू वस्तुओं के संग्रह का प्रबंधन करेगा। निम्नलिखित डेटा प्रबंधक के लिए एक वर्ग परिभाषा है:

#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

जब होम इन्वेंट्री आइटम का संग्रह बदलता है, तो इस बदलाव के बारे में देखने के लिए नियंत्रकों को जागरूक किया जाना चाहिए। उपरोक्त वर्ग की परिभाषा यह स्पष्ट नहीं करती है कि यह कैसे होगा। हमें पर्यवेक्षक पैटर्न का पालन करने की आवश्यकता है। व्यू कंट्रोलर्स को औपचारिक रूप से शेअरमैनगर का निरीक्षण करना चाहिए। किसी अन्य वस्तु का निरीक्षण करने के दो तरीके हैं:

  • कुंजी-मान-अवलोकन (KVO)
  • NSNotificationCenter।

परिदृश्य दो में, हमारे पास HomeInventoryManager की एक भी संपत्ति नहीं है जिसे KVO का उपयोग करके देखा जा सकता है। क्योंकि हमारे पास एक भी संपत्ति नहीं है जो आसानी से देखने योग्य हो, पर्यवेक्षक पैटर्न, इस मामले में, NSNotificationCenter का उपयोग करके लागू किया जाना चाहिए। चार में से प्रत्येक व्यू कंट्रोलर सूचनाओं की सदस्यता लेता है, और साझा किए जाने पर प्रबंधक सूचना केंद्र को सूचना भेज देगा। इन्वेंट्री प्रबंधक को किसी भी अन्य वर्गों के दृश्य नियंत्रकों या उदाहरणों के बारे में कुछ भी जानने की आवश्यकता नहीं है जो इन्वेंट्री आइटम के संग्रह में परिवर्तन होने पर जानने में रुचि हो सकती है; NSNotificationCenter इन कार्यान्वयन विवरणों का ध्यान रखता है। नियंत्रण नियंत्रक केवल सूचनाओं की सदस्यता लेते हैं, और डेटा प्रबंधक केवल सूचनाएं पोस्ट करते हैं।

कई शुरुआती प्रोग्रामर इस तथ्य का लाभ उठाते हैं कि आवेदन के जीवनकाल में हमेशा एक ही एप्लिकेशन डेलिगेट होता है, जो विश्व स्तर पर सुलभ है। शुरुआत प्रोग्रामर इस तथ्य का उपयोग ऑब्जेक्ट और कार्यक्षमता को ऐपडेलगेट में एप्लिकेशन में कहीं और से एक्सेस करने की सुविधा के रूप में करने के लिए करते हैं। सिर्फ इसलिए कि AppDelegate एक सिंगलटन है इसका मतलब यह नहीं है कि इसे अन्य सभी सिंग्लेटों को बदलना चाहिए। यह एक खराब प्रथा है क्योंकि यह एक वर्ग पर बहुत अधिक बोझ डालता है, अच्छी वस्तु-उन्मुख प्रथाओं को तोड़ता है। प्रत्येक वर्ग की एक स्पष्ट भूमिका होनी चाहिए जिसे आसानी से समझाया जाए, अक्सर केवल कक्षा के नाम से।

किसी भी समय आपका एप्लिकेशन डेलीगेट फूला हुआ लगने लगता है, सिंगलनेट में कार्यक्षमता निकालना शुरू कर देता है। उदाहरण के लिए, कोर डेटा स्टैक को ऐपडेलगेट में नहीं छोड़ा जाना चाहिए, बल्कि इसके बजाय अपनी खुद की क्लास में रखा जाना चाहिए, एक कोरडैटेमनगर क्लास।

संदर्भ


41

ओपी ने व्यू कंट्रोलर्स का उल्लेख नहीं किया, लेकिन इतने सारे उत्तर हैं, कि मैं एलएलवीएम की नई विशेषताओं में से कुछ को देखने की अनुमति देना चाहता हूं, जब एक व्यू कंट्रोलर से दूसरे और फिर डेटा पास करना चाहते हैं। कुछ परिणाम वापस मिल रहा है।

स्टोरीबोर्ड के तर्क, एआरसी और एलएलवीएम ब्लॉक मेरे लिए पहले से कहीं अधिक आसान बनाते हैं। उपर्युक्त कुछ स्टोरीबोर्ड और सीग्यू पहले से ही हैं लेकिन फिर भी प्रतिनिधिमंडल पर निर्भर हैं। प्रतिनिधियों को परिभाषित करना निश्चित रूप से काम करता है लेकिन कुछ लोगों को संकेत या कोड ब्लॉक पास करना आसान हो सकता है।

यूनीवीगेटर्स और सेगमेंट के साथ, उप-नियंत्रक के पास जानकारी पास करने और जानकारी वापस पाने के आसान तरीके हैं। एआरसी NSObjects से प्राप्त चीजों को पासिंग पॉइंटर्स को सरल बनाता है इसलिए यदि आप चाहते हैं कि सबसेंवर कंट्रोलर आपके लिए कुछ डेटा जोड़ें / बदलें / संशोधित करें, तो इसे पॉइंटर को एक म्यूट उदाहरण में पास करें। ब्लॉक पासिंग एक्शन को आसान बनाते हैं, इसलिए यदि आप चाहते हैं कि सबसेंवर कंट्रोलर आपके उच्च स्तर के कंट्रोलर पर एक्शन लागू करे, तो उसे ब्लॉक कर दें। आप किसी भी तर्क को स्वीकार करने के लिए ब्लॉक को परिभाषित करते हैं जो आपको समझ में आता है। यदि आप चीजों को बेहतर तरीके से सूट करते हैं, तो आप कई ब्लॉकों का उपयोग करने के लिए एपीआई को डिजाइन कर सकते हैं।

यहाँ segue गोंद के दो तुच्छ उदाहरण हैं। पहला सीधा इनपुट के लिए पारित एक पैरामीटर दिखा रहा है, दूसरा आउटपुट के लिए।

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

यह दूसरा उदाहरण दूसरे तर्क के लिए कॉलबैक ब्लॉक पास करने को दर्शाता है। मुझे ब्लॉक का उपयोग करना पसंद है क्योंकि यह प्रासंगिक विवरणों को स्रोत में एक साथ रखता है - उच्च स्तर का स्रोत।

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

ViewController 2 (गंतव्य) से viewController 1 (स्रोत) से डेटा पास करना अधिक दिलचस्प बात है। यह मानते हुए कि आप स्टोरीबोर्ड का उपयोग करते हैं, वे सभी तरीके हैं जो मुझे पता चले हैं:

  • प्रतिनिधि
  • अधिसूचना
  • उपयोगकर्ता की चूक
  • एकाकी वस्तु

जिनकी चर्चा यहाँ पहले से ही थी।

मैंने पाया कि और भी तरीके हैं:

-बैंकिंग ब्लॉक कॉलबैक:

इसका उपयोग prepareForSegueVC1 में विधि में करें

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

स्टोरीबोर्ड का उपयोग करना उल्टा (बाहर निकलें)

कुलपति 1 में एक UIStoryboardSegue तर्क के साथ एक विधि को लागू करें, इस तरह:

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

स्टोरीबोर्ड में "वापसी" बटन को वीसी के हरे निकास बटन (अनवाइंड) पर हुक करें। अब आपके पास एक तर्क है कि "वापस चला जाता है" तो u VC2 की तैयारी में बहस में गंतव्य दृश्य नियंत्रक का उपयोग कर सकते हैं और वापस जाने से पहले VC1 की किसी भी संपत्ति को बदल सकते हैं।

  • स्टोरीबोर्ड का उपयोग करने का एक अन्य विकल्प अंडरविंड (बाहर निकलें) - आप वीसी 1 में लिखी गई विधि का उपयोग कर सकते हैं

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

    और VC1 की तैयारी में आप जिस भी संपत्ति को साझा करना चाहते हैं उसे बदल सकते हैं।

दोनों सुगम विकल्पों में आप बटन की टैग प्रॉपर्टी सेट कर सकते हैं और इसे तैयारफॉरगेट में देख सकते हैं।

आशा है कि मैंने चर्चा में कुछ जोड़ा।

:) चीयर्स।


40

डेटा साझा करने के लिए कई तरीके हैं।

  1. आप हमेशा डेटा का उपयोग करके साझा कर सकते हैं NSUserDefaults। अपनी पसंद की कुंजी के संबंध में आप जो मूल्य साझा करना चाहते हैं, उसे निर्धारित करें और NSUserDefaultअगले दृश्य नियंत्रक में उस कुंजी से संबंधित मूल्य प्राप्त करें ।

    [[NSUserDefaults standardUserDefaults] setValue:value forKey:key]
    [[NSUserDefaults standardUserDefaults] objectForKey:key]
  2. आप बस एक संपत्ति बना सकते हैं viewcontrollerA। की एक वस्तु बनाने viewcontrollerAमें viewcontrollerBऔर है कि संपत्ति के लिए वांछित मूल्य निर्दिष्ट।

  3. आप इसके लिए कस्टम प्रतिनिधि भी बना सकते हैं।


30
NSUserDefaults का विशिष्ट उद्देश्य उपयोगकर्ता प्राथमिकताओं को संग्रहीत करना है जो एप्लिकेशन निष्पादन के बीच बनी रहती है, इसलिए यहां संग्रहीत कुछ भी तब तक यहां रहेगा जब तक कि स्पष्ट रूप से हटा नहीं दिया जाता है। किसी ऐप में व्यू कंट्रोलर्स (या किसी अन्य ऑब्जेक्ट) के बीच जानकारी पास करने के लिए इसका उपयोग करना वास्तव में एक बुरा विचार है।
जोस गोंजालेज

30

यदि आप एक कंट्रोलर से दूसरे में डेटा पास करना चाहते हैं तो इस कोड को आजमाएं

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

यह एक बहुत पुराना उत्तर है और यह विरोधी पैटर्न है, कृपया प्रतिनिधियों का उपयोग करें। इस दृष्टिकोण का उपयोग न करें !!

1. दूसरे व्यू कंट्रोलर में पहले व्यू कंट्रोलर का उदाहरण बनाएं और उसकी प्रॉपर्टी बनाएं @property (nonatomic,assign)

2.SecondviewController इस दृश्य नियंत्रक के उदाहरण को निर्दिष्ट करें ।

2. जब आप चयन कार्य पूरा कर लेते हैं, तो सरणी को पहले व्यू कंट्रोलर को कॉपी कर लें, जब आप सेकंड व्यू को अनलोड करते हैं, तो फर्स्ट व्यू एरे डेटा को होल्ड करेगा।

उम्मीद है की यह मदद करेगा।


2
मुझे विश्वास नहीं है कि यह जाने का सही तरीका है क्योंकि यह दृश्य नियंत्रकों के बीच एक बहुत ही हास्यास्पद लिंक बनाता है। वास्तव में MVC से चिपके नहीं।
मैट प्राइस

1
यदि आप एमवीसी का कड़ाई से पालन करना चाहते हैं, तो NSNotificationCenter का उपयोग करें एक विधि ViewControllerA से ViewControllerB पर कॉल किया जा सकता है, यह जांचें कि यह u
kAR3k

28

मैं लंबे समय से इस समाधान की खोज कर रहा था, एटलस ने इसे पाया। सबसे पहले अपने SecondViewController.h फ़ाइल की तरह सभी वस्तुओं को घोषित करें

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

अब आपकी कार्यान्वयन फ़ाइल में इस तरह से उन वस्तुओं के लिए मेमोरी आवंटित करें

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

अब आपने मेमोरी को Arrayऑब्जेक्ट और ऑब्जेक्ट के लिए आवंटित किया है । अब आप इसे पुश करने से पहले उस मेमोरी को भर सकते हैंViewController

अपने SecondViewController.h पर जाएं और दो तरीके लिखें

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

कार्यान्वयन फ़ाइल में आप फ़ंक्शन को लागू कर सकते हैं

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

उम्मीद है कि आपके CustomObjectपास इसके साथ एक सेटर फ़ंक्शन होना चाहिए।

अब आपका मूल काम पूरा हो गया है। उस जगह पर जाएं जहां आप पुश करना चाहते SecondViewControllerहैं और निम्नलिखित सामान कर सकते हैं

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

वर्तनी की गलतियों का ख्याल रखें।


24

यह ऐसा करने का तरीका नहीं है, आपको प्रतिनिधियों का उपयोग करना चाहिए, मुझे लगता है कि हमारे पास दो व्यू कंट्रोलर ViewController1 और ViewController2 हैं और यह चेक चीज़ पहले एक में है और जब इसकी स्थिति बदलती है, तो आप ViewController2 में कुछ करना चाहते हैं, इसे उचित तरीके से प्राप्त करें, आपको निम्न कार्य करना चाहिए:

अपने प्रोजेक्ट में एक नई फ़ाइल जोड़ें (ऑब्जेक्टिव-सी प्रोटोकॉल) फ़ाइल -> नया, अब इसे देखें ViewController1Delegate या जो कुछ भी आप चाहते हैं और इन्हें @interface और @end निर्देशों के बीच लिखें।

@optional

- (void)checkStateDidChange:(BOOL)checked;

अब ViewController2.h पर जाएं और जोड़ें

#import "ViewController1Delegate.h"

फिर इसकी परिभाषा को बदल दें

@interface ViewController2: UIViewController<ViewController1Delegate>

अब ViewController2.m पर जाएं और कार्यान्वयन जोड़ के अंदर:

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

अब ViewController1.h पर जाएं और निम्नलिखित संपत्ति जोड़ें:

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

अब अगर आप किसी घटना के बाद ViewController2 के अंदर ViewController1 बना रहे हैं, तो आपको NIB फ़ाइलों का उपयोग करके इसे इस तरह करना चाहिए:

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

अब आप सभी तैयार हैं, जब भी आप ViewController1 में बदले गए चेक की घटना का पता लगाते हैं, तो आपको बस इतना करना है कि नीचे दिया गया है

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

कृपया मुझे बताएं कि क्या कुछ ऐसा है जो स्पष्ट नहीं है अगर मैं आपके प्रश्न को ठीक से नहीं समझ पाया।


23

यदि आप एक से दूसरे व्यू-कंट्रोलर में डेटा भेजना चाहते हैं, तो इसका एक तरीका यह है:

मान लें कि हमारे पास दृश्य नियंत्रक हैं: viewControllerA और viewControllerB

अब viewControllerB.h में

@interface viewControllerB : UIViewController {

  NSString *string;
  NSArray *array;

}

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

ViewControllerB.m में

#import "viewControllerB.h"

@implementation viewControllerB

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

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

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

}

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

}

तो यह है कि आप किसी भी प्रतिनिधि को स्थापित किए बिना viewControllerA से viewControllerB तक डेटा कैसे पारित कर सकते हैं। ;)


1
मैंने अपनी परियोजना में उर कोड का उपयोग करने की कोशिश की, लेकिन मैं viewcontrollerB में मूल्यों को प्राप्त करने में सक्षम नहीं हूं। क्या आप बता सकते हैं कि क्या समस्या हो सकती है?
एक्स-कोडर

1
@ अजीतला क्या आप एक नए प्रश्न में अपना कोड पेस्ट कर सकते हैं? मैं आपके मुद्दे को हल करने की कोशिश करूंगा। :)
अनिरुद्ध जोशी

1
क्या गलत तरीकों का इस्तेमाल नहीं करना गलत है, और सिर्फ vcB.string = @ "asdf" जैसा कुछ देखने के लिए कोई नियंत्रण है?
khanh.tran.vinh

1
@ khanh.tran.vinh इस बात पर निर्भर करता है कि आप ARC का उपयोग कर रहे हैं या नहीं।
अनिरुद्ध जोशी

21

मुझे पता है कि यह एक पीटा विषय है, लेकिन उन लोगों के लिए जो इस सवाल का जवाब एक स्विफ्ट तिरछा के साथ दे रहे हैं और नंगे-हड्डियों का उदाहरण चाहते हैं, यहां डेटा पास करने की मेरी विधि है यदि आप एक सेगमेंट का उपयोग कर रहे हैं।

यह ऊपर के समान है, लेकिन बटन, लेबल और इस तरह के बिना। बस एक दृश्य से अगले करने के लिए डेटा गुजर रहा है।

स्टोरीबोर्ड को सेटअप करें

इसके तीन भाग हैं।

  1. प्रेषक
  2. द सेग
  3. प्राप्तकर्ता

यह उनके बीच एक सेग के साथ एक बहुत ही सरल दृश्य लेआउट है।


बहुत ही सरल दृश्य लेआउट।  नोट: कोई नेविगेशन नियंत्रक नहीं


यहाँ प्रेषक के लिए सेटअप है


प्रेषक


यहां रिसीवर के लिए सेटअप है।


प्राप्तकर्ता


अंत में, सेग के लिए सेटअप।


द सेग आइडेंटिफ़ायर


नियंत्रण देखें

हम इस सरल को रख रहे हैं ताकि कोई बटन न हो, न कि कार्रवाई, हम प्रेषक से रिसीवर तक डेटा ले जा रहे हैं जब एप्लिकेशन लोड होता है और फिर कंसोल को प्रेषित मूल्य को आउटपुट करता है।

यह पृष्ठ प्रारंभ में लोड किए गए मान को लेता है और इसे पास करता है।

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

    }

}

यह पृष्ठ लोड होने पर बस चर का मान कंसोल पर भेजता है। इस बिंदु तक, हमारी पसंदीदा फिल्म उस चर में होनी चाहिए।

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

    }   
}

यदि आप एक सेग का उपयोग करना चाहते हैं तो आप इसे कैसे निपटा सकते हैं और नेविगेशन कंट्रोलर के नीचे आपके पेज नहीं हैं।

एक बार इसे चलाने के बाद इसे रिसीवर के दृश्य पर स्वचालित रूप से स्विच करना चाहिए और प्रेषक से रिसीवर तक मूल्य को पास करना चाहिए, कंसोल में मूल्य प्रदर्शित करना चाहिए।

घोस्ट बस्टर्स एक क्लासिक लोग हैं।


19

मेरे मामले में मैंने एक सिंगलटन वर्ग का उपयोग किया जो एक वैश्विक वस्तु के रूप में काम कर सकता है जो ऐप में लगभग हर जगह से डेटा तक पहुंच की अनुमति देता है। पहली बात यह है कि एक एकल वर्ग का निर्माण करना है। कृपया पृष्ठ का संदर्भ लें, " मेरा उद्देश्य-सी सिंगलटन कैसा दिखना चाहिए? " और मैंने जिस वस्तु को विश्व स्तर पर सुलभ बनाने के लिए किया था, वह बस उसे आयात करना था appName_Prefix.pchजिसमें हर वर्ग में आयात विवरण लागू करना है। इस ऑब्जेक्ट तक पहुंचने और उपयोग करने के लिए, मैंने साझा उदाहरण को वापस करने के लिए बस क्लास पद्धति को लागू किया, जिसमें इसके स्वयं के चर हैं


यह सही जवाब है। बस "मॉडल" के रूप में एक सिंगलटन का उपयोग करें। ध्यान दें कि जैसा कि कालेब कहते हैं, "आपके ऐप के लिए मॉडल स्ट्रिंग्स के एक सरणी के रूप में सरल हो सकता है" । यह ध्यान रखना महत्वपूर्ण है कि स्विफ्ट में एक सिंगलटन करना वास्तव में तुच्छ है । (इतना सरल है कि यहां उल्लेख करने लायक भी नहीं है - सिर्फ गूगल।) नए प्रोग्रामर के लिए, यह समझने लायक है कि एक सिंगलटन बनाने के लिए गधे में एक वास्तविक दर्द हुआ करता था । हालाँकि, सिंगल आईओएस प्रोग्रामिंग के लिए बिल्कुल केंद्रीय हैं - Apple जो कुछ भी करता है वह एक सिंगलटन है। यही कारण है कि Apple ने आखिरकार इसे (Swift में) trtvial बना दिया ताकि सिंग्लेट्स को ठीक से बनाया जा सके।
फेटी

1
हालाँकि, ध्यान दें कि इन दिनों (2016+) "सब कुछ iOS में एक कंटेनर दृश्य है"। आपके द्वारा स्क्रीन पर की जाने वाली हर एक चीज को आप थोड़ा कंटेनर व्यू बनाते हैं। यह कंटेनर विचारों के "ऊपर और नीचे" श्रृंखलाओं को प्राप्त करने के लिए काफी तुच्छ है (हालांकि Apple भविष्य में इसे आसान बना देगा), और आप वैसे भी लगभग हर कंटेनर दृश्य के लिए ऐसा करते हैं। तो, अगर आपने ऐसा किया है - तो आपके पास इसका जवाब है; एक सिंगलटन के लिए कोई ज़रूरत नहीं है। कंटेनर दृश्य परिचय ... stackoverflow.com/a/23403979/294884
फेटी

19

स्विफ्ट 5

खैर मैट प्राइस का जवाब डेटा पास करने के लिए पूरी तरह से ठीक है, लेकिन मैं इसे फिर से लिखने जा रहा हूं, नवीनतम स्विफ्ट संस्करण में क्योंकि मेरा मानना ​​है कि नए प्रोग्रामर नए सिंटैक्स और विधियों / रूपरेखाओं के कारण इसे चुनौतीपूर्ण छोड़ते हैं, क्योंकि मूल पोस्ट ऑब्जेक्टिव-सी में है।

व्यू कंट्रोलर्स के बीच डेटा पास करने के कई विकल्प हैं।

  1. नेविगेशन नियंत्रक पुश का उपयोग करना
  2. सेग का उपयोग करना
  3. डेलिगेट का उपयोग करना
  4. अधिसूचना पर्यवेक्षक का उपयोग करना
  5. ब्लॉक का उपयोग करना

मैं स्विफ्ट में नवीनतम iOS फ्रेमवर्क के साथ अपने तर्क को फिर से लिखने जा रहा हूं


नेविगेशन कंट्रोलर पुश के माध्यम से डेटा पास करना : ViewControllerA से ViewControllerB तक

चरण 1. ViewControllerB में चर घोषित

var isSomethingEnabled = false

चरण 2. ViewControllerB 'ViewDidLoad विधि में चर प्रिंट करें

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

चरण 3. नेविगेशन नियंत्रक के माध्यम से पुश करते समय ViewControllerA पास डेटा

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

तो यहाँ के लिए पूरा कोड है:

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

बहस के माध्यम से डेटा पास करना : ViewControllerA से ViewControllerB तक

चरण 1. ViewControllerA से ViewControllerB से बहस बनाएँ और स्टोरीबोर्ड में Identifier = showDetailSegue दें जैसा कि नीचे दिखाया गया है

यहां छवि विवरण दर्ज करें

चरण 2। ViewControllerB में एक समांतर नाम घोषित किया गया है जिसका नाम आइसोमेलेबल है और इसके मूल्य को प्रिंट करें।

चरण 3. ViewControllerA में पास से गुजरते समय isSomethingEnabled के मान

तो यहाँ के लिए पूरा कोड है:

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

प्रतिनिधि के माध्यम से डेटा पास करना : ViewControllerB से ViewControllerA तक

चरण 1. प्रोटोकॉल देखें ViewControllerBDelegate ViewControllerB फ़ाइल में लेकिन कक्षा के बाहर

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

चरण 2. ViewControllerB में वैरिएबल चर को घोषित करें

var delegate: ViewControllerBDelegate?

चरण 3. ViewControllerB के viewDidLoad विधि के अंदर प्रतिनिधि के लिए डेटा भेजें

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

चरण 4. ViewControllerA में ViewControllerBDelegate की पुष्टि करें

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

चरण 5. पुष्टि करें कि आप ViewControllerA में प्रतिनिधि को लागू करेंगे

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

चरण 6. ViewControllerA में डेटा प्राप्त करने के लिए प्रतिनिधि पद्धति को लागू करें

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

तो यहाँ के लिए पूरा कोड है:

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

अधिसूचना प्रेक्षक के माध्यम से डाटा पास करना : ViewControllerB से ViewControllerA तक

चरण 1. ViewControllerB में अधिसूचना पर्यवेक्षक में डेटा सेट और पोस्ट करें

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

चरण 2. ViewControllerA में अधिसूचना पर्यवेक्षक जोड़ें

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

चरण 3. ViewControllerA में अधिसूचना डेटा मूल्य प्राप्त करें

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

तो यहाँ के लिए पूरा कोड है:

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

ब्लॉक के माध्यम से डेटा पास करना : ViewControllerB से ViewControllerA तक

चरण 1. ViewControllerB में ब्लॉक घोषित करें

var प्राधिकरणकंप्लीमेंटेशनब्लॉक: ((बूल) -> ())? = {_ in}

चरण 2. ViewControllerB में ब्लॉक में डेटा सेट करें

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

चरण 3. ViewControllerA में ब्लॉक डेटा प्राप्त करें

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

तो यहाँ के लिए पूरा कोड है:

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 पर पूरा नमूना आवेदन पा सकते हैं कृपया मुझे बताएं कि क्या आपके पास इस पर कोई प्रश्न है।


18

नीचे के रूप में FirstViewController से दूसरे ViewController के बीच डेटा पास करना

उदाहरण के लिए:

FirstViewController स्ट्रिंग मान के रूप में

StrFirstValue = @"first";

इसलिए हम नीचे दिए गए चरण का उपयोग करके द्वितीय श्रेणी में इस मान को पारित कर सकते हैं

1> हमें SecondViewController.h फ़ाइल में स्ट्रिंग ऑब्जेक्ट क्रेट करने की आवश्यकता है

NSString *strValue;

2> .h फ़ाइल में घोषणा के नीचे संपत्ति घोषित करने की आवश्यकता है

@property (strong, nonatomic)  NSString *strSecondValue;

3> हेडर घोषणा के नीचे FirstViewController.m फ़ाइल में उस मूल्य को संश्लेषित करने की आवश्यकता है

@synthesize strValue;

और FirstViewController.h में:

@property (strong, nonatomic)  NSString *strValue;

4> FirstViewController में, जिस विधि से हम दूसरे दृश्य पर जाते हैं, कृपया उस विधि में कोड के नीचे लिखें।

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

[secondView setStrSecondValue:StrFirstValue];

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

SecondViewController में होने के बाद, आप FirstViewController पर वापस डेटा कैसे पास करते हैं?
ब्रूनो

18

मैं वर्तमान में MCViewFactory नामक एक परियोजना के माध्यम से इस समस्या के लिए एक खुले स्रोत समाधान में योगदान कर रहा हूं, जो यहां पाया जा सकता है:

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

यह विचार एंड्रॉइड के इरादे प्रतिमान की नकल कर रहा है, एक वैश्विक कारखाने का उपयोग करके यह देखने के लिए कि आप किस दृश्य को देख रहे हैं और विचारों के बीच डेटा को स्विच और पास करने के लिए "इंटेंट्स" का उपयोग कर रहे हैं। सभी प्रलेखन जीथब पृष्ठ पर है, लेकिन यहां कुछ हाइलाइट्स हैं:

आप अपने सभी विचारों को .XIB फ़ाइलों में सेट करते हैं और फ़ैक्टरी को इनिशियलाइज़ करते हुए उन्हें ऐप डेलिगेट में रजिस्टर करते हैं।

// Register activities

MCViewFactory *factory = [MCViewFactory sharedFactory];

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

अब, अपने वीसी में, आप कभी भी नए वीसी के पास जाना चाहते हैं और डेटा पास करना चाहते हैं, तो आप एक नया इरादा बनाते हैं और इसके शब्दकोश में डेटा जोड़ते हैं (saveInstanceState)। फिर, बस कारखाने के वर्तमान इरादे को निर्धारित करें:

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

आपके सभी विचार जो इस के अनुरूप हैं, MCViewController के उपवर्ग होने की आवश्यकता है, जो आपको नए onResume: पद्धति को ओवरराइड करने की अनुमति देता है, जिससे आप उस डेटा तक पहुंच प्राप्त कर सकते हैं जिसे आपने पास किया है।

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

आशा है कि आप में से कुछ इस समाधान को उपयोगी / दिलचस्प पाएंगे।


तब सभी नियंत्रक ऑब्जेक्ट किसी भी स्कोप में सभी पंजीकृत शब्दकोशों को प्राप्त / सेट कर सकते हैं? इसको कम करें।
इताची

15

अगले पर संपत्ति बनाएं view controller .hऔर गेट्टर और सेटर को परिभाषित करें।

propertyNextVC में यह जोड़ें

@property (strong, nonatomic) NSString *indexNumber;

जोड़ना

@synthesize indexNumber; नेक्स्टवीवीएम में

और अंतिम

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

vc.indexNumber=@"123";

[self.navigationController vc animated:YES];

11

ऐसा करने के कई तरीके हैं और सही को चुनना महत्वपूर्ण है। संभवतः सबसे बड़ा वास्तुशिल्प निर्णयों में से एक यह है कि कैसे मॉडल कोड को पूरे ऐप में साझा या एक्सेस किया जाएगा।

मैंने कुछ समय पहले इस बारे में एक ब्लॉग पोस्ट लिखी थी: मॉडल कोड साझा करना । यहाँ एक संक्षिप्त सारांश है:

साझा डेटा

एक दृष्टिकोण दृष्टिकोण नियंत्रकों के बीच मॉडल ऑब्जेक्ट के लिए पॉइंटर्स साझा करना है।

  • डेटा सेट करने के लिए व्यू कंट्रोलर्स (नेविगेशन या टैब बार कंट्रोलर में) पर ब्यूटिशन फोर्स करें
  • तैयार में डेटा सेट करेंसंगीत (यदि स्टोरीबोर्ड) या init (यदि प्रोग्रामेटिक)

चूंकि सेग की तैयारी सबसे आम है, यह एक उदाहरण है:

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

स्वतंत्र पहुंच

एक और तरीका यह है कि एक समय में डेटा से भरी स्क्रीन को हैंडल किया जाए और व्यू कंट्रोलर को एक-दूसरे को जोड़े जाने के बजाय प्रत्येक व्यू कंट्रोलर को सिंगल डेटा सोर्स से जोड़ा जाए जो उन्हें स्वतंत्र रूप से मिल सके।

मैंने जो सबसे सामान्य तरीका देखा है वह एक एकल उदाहरण है। तो अगर आपकी सिंगलटन ऑब्जेक्ट थी DataAccessतो आप UIViewController के व्यूडिडलड विधि में निम्नलिखित कर सकते थे:

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

इसके अलावा उपकरण भी हैं जो डेटा के साथ पास करने में मदद करते हैं:

  • की-वैल्यू का अवलोकन
  • NSNotification
  • कोर डेटा
  • NSFetchedResultsController
  • डेटा स्रोत

कोर डेटा

कोर डेटा के बारे में अच्छी बात यह है कि इसमें उलटे रिश्ते हैं। तो अगर आप नोट नोट्स ऑब्जेक्ट को बस देना चाहते हैं, तो आप नोट कर सकते हैं क्योंकि यह नोटबुक की तरह किसी अन्य चीज़ से उलटा संबंध रखेगा। यदि आपको नोट व्यू कंट्रोलर में नोटबुक पर डेटा की आवश्यकता है तो आप निम्नलिखित करके ऑब्जेक्ट ग्राफ को वापस ला सकते हैं:

let notebookName = note.notebook.name

मेरे ब्लॉग पोस्ट में इसके बारे में और पढ़ें: मॉडल कोड साझा करना


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

जब आप उपयोग कर रहे हों, तो ऐसे कार्यों को करने के लिए प्रतिनिधिमंडल केवल एक ही समाधान है। लेकिन ऊपर वर्णित सभी उत्तरों के लिए .xib फाइलें हैं storyboard ।xibs फ़ाइलों के लिए हैं जिनका आपको प्रतिनिधिमंडल का उपयोग करने की आवश्यकता है। केवल यही उपाय है जो आप कर सकते हैं।

एक अन्य उपाय यह है कि सिंगलटन क्लास पैटर्न का उपयोग एक बार इसे प्रारंभ करें और इसे अपने संपूर्ण ऐप में उपयोग करें।


10

यदि आप ViewControlerOne से ViewControllerTwo से डेटा पास करना चाहते हैं, तो ये प्रयास करें ..

ViewControlerOne.h में ये करें

 @property (nonatomic, strong) NSString *str1;

ViewControllerTwo.h में ये करें

 @property (nonatomic, strong) NSString *str2;

ViewControllerTwo.m में str2 को सिंथेसाइज़ करें

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

ViewControlerOne.m में ये करें

 - (void)viewDidLoad
 {
   [super viewDidLoad];

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

 }

बटन पर क्लिक करें घटना यह करते हैं ..

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

ViewControllerTwo.m में इन करें

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

10

आप अपने एप्लिकेशन में व्यू कंट्रोलर्स में इसे एक्सेस करने के लिए ऐप डेलिगेट में डेटा सेव कर सकते हैं। आपको बस इतना करना है कि ऐप डेलीगेट का साझा उदाहरण बन जाए

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

उदाहरण के लिए

यदि आप घोषणा करते हैं NSArray object *arrayXYZतो आप इसे किसी भी दृश्य नियंत्रक द्वारा एक्सेस कर सकते हैंappDelegate.arrayXYZ


यह हैकथॉन के लिए विधि-पसंद है
हाई फेंग काओ

9

यदि आप एक से दूसरे व्यू-कंट्रोलर में डेटा भेजना चाहते हैं, तो इसका एक तरीका यह है:

मान लें कि हमारे पास दृश्य नियंत्रक हैं: ViewController और NewViewController।

ViewController.h में

#import <UIKit/UIKit.h>

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

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

-(IBAction)goToNextScreen:(id)sender;

@end

ViewController.m में

#import "ViewController.h"

#import "NewViewController.h"

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

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


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

    newVc.arrayList = arr;

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

}

NewViewController.h में

#import <UIKit/UIKit.h>

@interface NewViewController : UITableViewController
{
    NSArray *arrayList;

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

}

@property(nonatomic, retain)NSArray *arrayList;

@end

NewViewController.m में

#import "NewViewController.h"

#import "ViewController.h"

@implementation NewViewController
@synthesize arrayList;

#pragma mark - Table view data source

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

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

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

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

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


}

@end

तो इस तरह हम डेटा को एक व्यू कंट्रोलर से दूसरे व्यू कंट्रोलर के पास भेज सकते हैं ...


8

मुझे एनएसपीरोक्सी पर आधारित मॉडल ऑब्जेक्ट्स और मॉक ऑब्जेक्ट्स का विचार पसंद है कि यदि उपयोगकर्ता चयन रद्द कर सकता है तो डेटा को कम या न करें।

यह एकल ऑब्जेक्ट या ऑब्जेक्ट्स के जोड़े के बाद से डेटा को पास करना आसान है और यदि आपके पास UINavigationController नियंत्रक है, तो आप संदर्भ को अंदर रखने के लिए कह सकते हैं और सभी पुश किए गए व्यू कंट्रोलर इसे सीधे नेविगेशन कंट्रोलर से एक्सेस कर सकते हैं।


8

मैंने बहुत से लोगों को इस didSelectRowAtPathपद्धति का उपयोग करते हुए जटिल करने पर देखा है । मैं अपने उदाहरण में Core Data का उपयोग कर रहा हूं।

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

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

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

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

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

}

विधि के अंदर कोड की 4 लाइनें और आप कर रहे हैं।


6

इस सवाल के कई जवाब हैं कि व्यू कंट्रोलर संचार करने के लिए कई अलग-अलग तरीके हैं जो वास्तव में काम करेंगे, लेकिन मैं कहीं भी उल्लेख नहीं करता कि कौन से वास्तव में उपयोग करने के लिए सर्वश्रेष्ठ हैं और कौन से बचने के लिए।

व्यवहार में, मेरी राय में केवल कुछ समाधान सुझाए गए हैं:

  • आगे डेटा पास करने के लिए:
    • की prepare(for:sender:)विधि को ओवरराइड करेंUIViewControllerस्टोरीबोर्ड का उपयोग करते समय और बहस करें
    • एक नियंत्रक के माध्यम से या संपत्तियों के माध्यम से डेटा पास करें जब व्यू कंट्रोलर ट्रांज़िशन थेटो कोड निष्पादित करें
  • डेटा को पीछे की ओर ले जाने के लिए
    • एप्लिकेशन साझा स्थिति को अपडेट करें (जो आप ऊपर दिए गए तरीकों में से किसी एक के साथ दृश्य नियंत्रकों के बीच आगे बढ़ सकते हैं)
    • प्रतिनिधिमंडल का उपयोग करें
    • एक आराम से बहस का उपयोग करें

समाधान मैं उपयोग न करने की सलाह देता हूं:

  • प्रतिनिधि का उपयोग करने के बजाय सीधे पिछले नियंत्रक को संदर्भित करना
  • एक सिंगलटन के माध्यम से डेटा साझा करना
  • एप्लिकेशन प्रतिनिधि के माध्यम से डेटा पास करना
  • उपयोगकर्ता डिफ़ॉल्ट के माध्यम से डेटा साझा करना
  • सूचनाओं के माध्यम से डेटा पास करना

ये समाधान, हालांकि अल्पावधि में काम कर रहे हैं, बहुत अधिक निर्भरता का परिचय देते हैं जो ऐप के आर्किटेक्चर को प्रभावित करेगा और बाद में और अधिक समस्याएं पैदा करेगा।

रुचि रखने वालों के लिए, मैंने कुछ लेख लिखे जो इन बिंदुओं को अधिक गहराई से संबोधित करते हैं और विभिन्न कमियों को उजागर करते हैं:

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