Передача данных между контроллерами представления

Я новичок в iOS и Objective-C и во всей парадигме MVC, и я застрял со следующим:

У меня есть представление, которое действует как форма ввода данных, и я хочу дать пользователю возможность выбрать несколько продуктов. Продукты перечислены в другом представлении с UITableViewController, и я включил несколько вариантов выбора.

У меня вопрос, как мне перенести данные из одного представления в другое? Я буду держать выборки на UITableView в массиве, но как мне затем передать это обратно в предыдущее представление формы ввода данных, чтобы его можно было сохранить вместе с другими данными в Core Data при отправке формы?

Я просмотрел и видел, как некоторые люди объявляют массив в делегате приложения. Я читаю кое-что о Singletons, но не понимаю, что это такое, и я читаю кое-что о создании модели данных.

Каков будет правильный способ выполнения этого и как я буду это делать?

вопрос задан 6.03.2011
Matt Price
23081 репутация

39 ответов


  • 1571 рейтинг

    Этот вопрос, кажется, очень популярен здесь на stackoverflow, поэтому я подумал, что постараюсь дать лучший ответ, чтобы помочь людям, начинающим в мире iOS, как я.

    Я надеюсь, что этот ответ достаточно ясен для понимания людьми, и я ничего не пропустил.

    Передача данных вперед

    Передача данных в контроллер представления из другого контроллера представления. Вы бы использовали этот метод, если хотите передать объект / значение из одного контроллера представления в другой контроллер представления, который вы, возможно, помещаете в стек навигации.

    Для этого примера у нас будет 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. Создайте переход от 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 
      - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
      @end
      
    2. Следующее еще в ViewControllerB.h вам нужно установить свойство delegate и синтезировать в ViewControllerB.m

      @property (nonatomic, weak) id  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 
      
    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];
      

    Список литературы

    ответ дан Matt Price, с репутацией 23081, 16.03.2012
  • 140 рейтинг

    Swift

    Существует множество объяснений здесь и вокруг StackOverflow, но если вы новичок, просто пытающийся получить что-то базовое для работы, попробуйте посмотреть этот учебник YouTube (это то, что помогло мне наконец понять, как это сделать).

    Передача данных вперед следующему контроллеру представления

    Ниже приведен пример, основанный на видео. Идея состоит в том, чтобы передать строку из текстового поля в первом контроллере представления метке во втором контроллере представления.

    enter image description here

    Создайте макет раскадровки в Интерфейсном Разработчике. Чтобы сделать переход, вы просто 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.
    • Установите первый и второй View Controllers для соответствующих файлов Swift в IB.

    Передача данных к предыдущему контроллеру представления

    Чтобы передать данные из второго контроллера представления в первый контроллер представления, вы используете протокол и делегат . Это видео очень четкое описание этого процесса:

    Ниже приведен пример, основанный на видео (с некоторыми изменениями).

    enter image description here

    Создайте макет раскадровки в Интерфейсном Разработчике. Опять же, чтобы сделать переход, вы просто перетаскиваете Control с кнопки на контроллер второго вида. Установите идентификатор segue для 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: class {
        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 находится вне класса View Controller.

    Вот и все. Запустив приложение сейчас, вы сможете отправить данные обратно со второго контроллера представления на первый.

    ответ дан Suragch, с репутацией 180669, 11.08.2015
  • 119 рейтинг

    M в MVC предназначен для «Модели», а в парадигме MVC роль классов моделей заключается в управлении данными программы. Модель является противоположностью представления - представление знает, как отображать данные, но ничего не знает о том, что делать с данными, в то время как модель знает все о том, как работать с данными, но ничего о том, как их отображать. Модели могут быть сложными, но это не обязательно - модель для вашего приложения может быть такой же простой, как массив строк или словарей.

    Роль контроллера заключается в посредничестве между представлением и моделью. Следовательно, им нужна ссылка на один или несколько объектов вида и один или несколько объектов модели. Допустим, ваша модель представляет собой массив словарей, каждый из которых представляет одну строку в вашей таблице. Корневое представление для вашего приложения отображает эту таблицу, и оно может отвечать за загрузку массива из файла. Когда пользователь решает добавить новую строку в таблицу, он нажимает какую-то кнопку, и ваш контроллер создает новый (изменяемый) словарь и добавляет его в массив. Чтобы заполнить строку, контроллер создает контроллер подробного представления и дает ему новый словарь. Контроллер подробного представления заполняет словарь и возвращает. Словарь уже является частью модели, поэтому больше ничего не должно произойти.

    ответ дан Caleb, с репутацией 106998, 6.03.2011
  • 85 рейтинг

    Существуют различные способы получения данных в другом классе в iOS. Например -

    1. Прямая инициализация после выделения другого класса.
    2. Делегация - для передачи данных обратно
    3. Уведомление - для широковещательной передачи данных нескольким классам за один раз
    4. Сохранение в NSUserDefaults - для доступа к нему позже
    5. Синглтон классы
    6. Базы данных и другие механизмы хранения, такие как plist и т. Д.

    Но для простого сценария передачи значения другому классу, распределение которого выполняется в текущем классе, наиболее распространенным и предпочтительным методом будет прямая установка значений после выделения. Это делается следующим образом: -

    Мы можем понять это, используя два контроллера - Контроллер1 и Контроллер2

    Предположим, в классе Controller1 вы хотите создать объект Controller2 и передать его с передачей значения String. Это можно сделать так: -

    - (void)pushToController2 {
    
        Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
        [obj passValue:@"String"];
        [self pushViewController:obj animated:YES];
    }
    

    В реализации класса Controller2 будет эта функция, как

    @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
    

    Вы также можете напрямую установить свойства класса Controller2 аналогично следующему:

    - (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 параметров, связанных с общей функцией, вы можете сохранить значения в классе Model и передать этот modelObject в следующий класс

    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.
    

    Надеюсь, что это помогает

    ответ дан borncrazy, с репутацией 1314, 8.04.2014
  • 74 рейтинг

    После дополнительных исследований выяснилось, что протоколы и делегаты - верный / предпочтительный способ Apple сделать это.

    Я закончил, используя этот пример

    Обмен данными между контроллерами представления и другими объектами @ iPhone Dev SDK

    Работал нормально и позволил мне передавать строку и массив вперед и назад между моими представлениями.

    Спасибо за вашу помощь

    ответ дан Matt Price, с репутацией 23081, 13.03.2011
  • 59 рейтинг

    Я нахожу самый простой и самый элегантный вариант с проходными блоками. Давайте назовем контроллер представления, который ожидает возвращенные данные, как «A» и возвращающий контроллер представления как «B». В этом примере мы хотим получить 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);
            };
    
        }
    }
    

    и контроллер представления "B" должны объявить свойство обратного вызова, BViewController. ч:

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

    Чем в файле реализации BViewController. м после того, как мы получили желаемые значения для возврата нашего обратного вызова, должен быть вызван:

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

    Одна вещь, которую нужно помнить, заключается в том, что использование блока часто требует управления сильными и __слабыми ссылками, как объяснено здесь

    ответ дан Leszek Zarna, с репутацией 2414, 14.10.2013
  • 48 рейтинг

    Во многих из приведенных ответов содержится некоторая полезная информация, но ни один из них не дает полного ответа на этот вопрос.

    Вопрос касается передачи информации между контроллерами представления. В приведенном конкретном примере запрашивается передача информации между представлениями, но с учетом самооценки новизны iOS первоначальный плакат, скорее всего, подразумевал между viewControllers, а не между представлениями (без какого-либо участия ViewControllers). Кажется, что все ответы сосредоточены на двух контроллерах представления, но что, если приложение развивается, чтобы задействовать более двух контроллеров представления в обмене информацией?

    Оригинальный плакат также спросил о Singletons и об использовании AppDelegate . На эти вопросы нужно ответить.

    Чтобы помочь кому-то еще, смотрящему на этот вопрос, кто хочет получить полный ответ, я попытаюсь предоставить его.

    Сценарии применения

    Вместо того, чтобы иметь весьма гипотетическое, абстрактное обсуждение, оно помогает иметь в виду конкретные приложения. Чтобы помочь определить ситуацию с двумя представлениями контроллера и ситуацией с более чем двумя представлениями, я собираюсь определить два конкретных сценария применения.

    Сценарий один: максимум два контроллера представления когда-либо должны обмениваться информацией. Смотрите диаграмму один.

    diagram of original problem

    В приложении есть два контроллера представления. Существует ViewControllerA (форма ввода данных) и View Controller B (список продуктов). Элементы, выбранные в списке продуктов, должны соответствовать элементам, отображаемым в текстовом поле в форме ввода данных. В этом сценарии ViewControllerA и ViewControllerB должны взаимодействовать напрямую друг с другом, а не с другими контроллерами представления.

    Сценарий два : более двух контроллеров представления должны совместно использовать одну и ту же информацию. Смотрите диаграмму два.

    home inventory application diagram

    В приложении есть четыре контроллера представления. Это приложение на основе вкладок для управления домашним инвентарем. Три контроллера представления представляют по-разному отфильтрованные представления тех же данных:

    • ViewControllerA - Предметы роскоши
    • ViewControllerB - Не застрахованные предметы
    • ViewControllerC - Инвентарь для всего дома
    • ViewControllerD - Добавить новый элемент формы

    Каждый раз, когда отдельный элемент создается или редактируется, он также должен синхронизироваться с другими контроллерами представления. Например, если мы добавляем лодку в ViewControllerD, но она еще не застрахована, тогда лодка должна появиться, когда пользователь перейдет к ViewControllerA (Предметы роскоши), а также ViewControllerC (Весь инвентарь дома), но не когда пользователь перейдет к ViewControllerB (не застрахованные предметы). Нам нужно заботиться не только о добавлении новых элементов, но и об удалении элементов (которые могут быть разрешены с любого из четырех контроллеров представления) или редактировании существующих элементов (что можно разрешить из «Формы добавления нового элемента», с целью повторного использования того же самого). для редактирования).

    Поскольку все контроллеры представления должны совместно использовать одни и те же данные, все четыре контроллера представления должны оставаться синхронизированными, и, следовательно, должна быть какая-то связь со всеми другими контроллерами представления, всякий раз, когда какой-либо один контроллер представления изменяет базовые данные. Должно быть совершенно очевидно, что мы не хотим, чтобы каждый контроллер представления взаимодействовал напрямую друг с другом в этом сценарии. В случае, если это не очевидно, рассмотрим, было ли у нас 20 различных контроллеров представления (а не только 4). Насколько сложно и подвержено ошибкам уведомлять каждый из 19 контроллеров представления каждый раз, когда один контроллер представления вносит изменения?

    Решения: делегаты и шаблон наблюдателя, а также синглтоны

    В первом сценарии у нас есть несколько жизнеспособных решений, так как другие ответы дали

    • segues
    • делегатов
    • установка свойств на контроллерах представления непосредственно
    • NSUserDefaults (на самом деле плохой выбор)

    Во втором сценарии у нас есть другие жизнеспособные решения:

    • Наблюдатель Pattern
    • Singletons

    singleton - это экземпляр класса, который является единственным экземпляром, существующим в течение его времени жизни. Синглтон получил свое название от того факта, что это единственный экземпляр. Обычно разработчики, которые используют синглтоны, имеют специальные методы класса для доступа к ним.

    + (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 
    
    @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
    

    Когда коллекция предметов домашнего инвентаря изменяется, контроллеры представления должны быть осведомлены об этом изменении. Приведенное выше определение класса не дает понять, как это будет происходить. Нам нужно следовать схеме наблюдателя. Контроллеры представления должны формально соблюдать sharedManager. Есть два способа наблюдать за другим объектом:

    • Наблюдение ключ-значение (KVO)
    • NSNotificationCenter.

    Во втором сценарии у нас нет ни одного свойства HouseholdInventoryManager, которое можно было бы наблюдать с помощью KVO. Поскольку у нас нет единственного свойства, которое легко наблюдать, шаблон наблюдателя в этом случае должен быть реализован с использованием NSNotificationCenter. Каждый из четырех контроллеров представления будет подписываться на уведомления, а sharedManager будет отправлять уведомления в центр уведомлений, когда это необходимо. Менеджеру инвентаря не нужно ничего знать о контроллерах представления или экземплярах каких-либо других классов, которые могут быть заинтересованы в знании, когда изменяется коллекция предметов инвентаря; NSNotificationCenter заботится об этих деталях реализации. Контроллеры представления просто подписываются на уведомления, а менеджер данных просто публикует уведомления.

    Многие начинающие программисты используют тот факт, что всегда существует ровно один Application Делегат во время жизни приложения, который доступен во всем мире. Начинающие программисты используют этот факт для помещения объектов и функций в appDelegate для удобства доступа из любой точки приложения. Тот факт, что AppDelegate является синглтоном, не означает, что он должен заменить все остальные синглтоны. Это плохая практика, поскольку она ложится слишком большим бременем на один класс, нарушая хорошие объектно-ориентированные практики. Каждый класс должен иметь четкую роль, которую легко объяснить, часто просто именем класса.

    Каждый раз, когда ваш делегат приложения начинает раздуваться, начинайте удалять функциональность в одиночку. Например, основной стек данных не следует оставлять в AppDelegate, а вместо этого следует помещать в его собственный класс, класс coreDataManager.

    Ссылки

    ответ дан Jason Cross, с репутацией 891, 5.04.2015
  • 37 рейтинг

    Существует несколько способов обмена данными.

    1. Вы всегда можете обмениваться данными, используя NSUserDefaults. Установите значение, которым вы хотите поделиться в отношении ключа по вашему выбору, и получите значение от NSUserDefault, связанное с этим ключом в следующем контроллере представления.

      [[NSUserDefaults standardUserDefaults] setValue:value forKey:key]
      [[NSUserDefaults standardUserDefaults] objectForKey:key]
      
    2. Вы можете просто создать свойство в viewcontrollerA. Создайте объект viewcontrollerA в viewcontrollerB и назначьте требуемое значение этому свойству.

    3. Вы также можете создавать собственные делегаты для этого.

    ответ дан Anubrata Santra, с репутацией 526, 27.09.2013
  • 37 рейтинг

    Передача данных из ViewController 2 (назначение) в viewController 1 (Source) является более интересной вещью. Предполагая, что вы используете storyBoard, это все способы, которые я узнал:

    • Делегат
    • Уведомление
    • Пользователь по умолчанию
    • Синглтон

    Это уже обсуждалось здесь.

    Я нашел, что есть больше способов:

    -Использование обратных вызовов:

    использовать его в методе prepareForSegue в VC1

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

    -Использование раскадровки Размотка (Выход)

    Реализуйте метод с аргументом UIStoryboardSegue в VC 1, как этот:

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

    В storyBoard подключите кнопку «возврат» к зеленому выходу. Кнопка (Размотка) на ВК. Теперь у вас есть переход, который «возвращается», так что вы можете использовать свойство destinationViewController в prepareForSegue из VC2 и измените любое свойство VC1, прежде чем оно вернется.

    • Еще один вариант использования раскадровки Undwind (Выход) - вы можете используйте метод, который вы написали в VC1

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

      И в prepareForSegue из VC1 вы можете изменить любое свойство, которым хотите поделиться.

    В обоих вариантах раскрутки вы можете установить свойство тега кнопки и установить его подготовить для обсуждения.

    Надеюсь, я добавил что-то к обсуждению.

    :) Ура.

    ответ дан Yevgeni, с репутацией 1075, 11.04.2014
  • 35 рейтинг

    В OP не упоминались контроллеры представлений, но в ответах так много ответов, что я хотел бы рассказать о том, что некоторые из новых функций LLVM позволяют упростить эту задачу при передаче данных с одного контроллера представления на другой и затем получить некоторые результаты обратно.

    Сегменты раскадровки, блоки ARC и LLVM делают это проще, чем когда-либо для меня. Некоторые ответы вышеупомянутых раскадровок и сегментов уже были, но все еще полагались на делегирование. Определение делегатов, безусловно, работает, но некоторым людям может быть легче передавать указатели или блоки кода.

    С UINavigators и segues, есть простые способы передачи информации на подчиненный контроллер и получения информации обратно. ARC упрощает передачу указателей на объекты, производные от NSObjects, поэтому, если вы хотите, чтобы вспомогательный контроллер добавил / изменил / изменил некоторые данные для вас, передайте ему указатель на изменяемый экземпляр. Блоки облегчают прохождение действий, поэтому, если вы хотите, чтобы подчиненный контроллер вызывал действие на контроллере более высокого уровня, передайте ему блок. Вы определяете блок для принятия любого количества аргументов, которые имеют смысл для вас. Вы также можете спроектировать API для использования нескольких блоков, если это подходит лучше.

    Вот два тривиальных примера клея 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];
        }];
    }
    
    ответ дан WeakPointer, с репутацией 1448, 21.02.2013
  • 26 рейтинг

    Если вы хотите передать данные с одного контроллера на другой, попробуйте этот код

    FirstViewController. ч

    @property (nonatomic, retain) NSString *str;
    

    SecondViewController. ч

    @property (nonatomic, retain) NSString *str1;
    

    FirstViewController. м

    - (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];
     }
    
    ответ дан user2998756, с репутацией 324, 18.11.2013
  • 25 рейтинг

    Я долго искал это решение, Atlast я нашел его. Прежде всего объявите все объекты в вашем 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. ч и напиши два метода

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

    Позаботьтесь о орфографических ошибках.

    ответ дан AsifHabib, с репутацией 750, 27.07.2013
  • 21 рейтинг

    Это не способ сделать это, вы должны использовать делегатов, я предполагаю, что у нас есть два контроллера представления ViewController1 и ViewController2, и этот элемент проверки находится в первом, и когда его состояние изменяется, вы хотите сделать что-то в ViewController2, Чтобы добиться этого надлежащим образом, вы должны сделать следующее:

    Добавить новый файл в проект (протокол Objective-C) Файл - & gt; Новый, теперь назовите его ViewController1Delegate или как хотите и напишите их между директивами @interface и @end

    @optional
    
    - (void)checkStateDidChange:(BOOL)checked;
    

    Теперь перейдите к ViewController2. ч и добавить

    #import "ViewController1Delegate.h"
    

    , затем измените его определение на

    @interface ViewController2: UIViewController
    

    Теперь перейдите к ViewController2. м и внутри реализации добавить:

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

    Теперь, если вы создаете ViewController1 внутри ViewController2 после некоторого события, то вы должны сделать это таким образом, используя файлы 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
    

    Скажите, пожалуйста, есть ли что-то, из чего не ясно, правильно ли я понял ваш вопрос.

    ответ дан Boda Taljo, с репутацией 1141, 1.09.2014
  • 18 рейтинг

    Если вы хотите отправить данные из одного в другой viewController, вот способ:

    Скажем, у нас есть viewController: viewControllerA и viewControllerB

    Теперь в viewControllerB. h

    @interface viewControllerB : UIViewController {
    
      NSString *string;
      NSArray *array;
    
    }
    
    - (id)initWithArray:(NSArray)a andString:(NSString)s;
    

    В представлении контролер. м

    #import "viewControllerB.h"
    
    @implementation viewControllerB
    
    - (id)initWithArray:(NSArray)a andString:(NSString)s {
    
       array = [[NSArray alloc] init];
       array = a;
    
       string = [[NSString alloc] init];
       string = s;
    
    }
    

    В представлении контролер. м

    #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 без установки какого-либо делегата. ;)

    ответ дан Aniruddh Joshi, с репутацией 5929, 29.07.2012
  • 18 рейтинг

    1. Создайте экземпляр первого View Controller во втором View Controller и присвойте ему свойство @property (nonatomic,assign).

    2. Назначьте экземпляр SecondviewController этого контроллера представления.

    2. Когда вы закончите операцию выделения, скопируйте массив в первый View Controller. Когда вы выгрузите SecondView, FirstView будет содержать данные массива.

    Надеюсь, что это помогает.

    ответ дан kaar3k, с репутацией 789, 23.05.2012
  • 16 рейтинг

    Передача данных между FirstViewController в SecondViewController, как показано ниже

    Например:

    FirstViewController Строковое значение как

    StrFirstValue = @"first";
    

    , чтобы мы могли передать это значение во второй класс, используя шаг

    1 & gt; Нам нужно создать строковый объект в SecondViewController. файл h

    NSString *strValue;
    

    2 & gt; Необходимо объявить свойство, как указано ниже, в разделе. файл h

    @property (strong, nonatomic)  NSString *strSecondValue;
    

    3> Нужно синтезировать это значение в FirstViewController. m файл ниже объявления заголовка

    @synthesize strValue;
    

    и в FirstViewController. ч:

    @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 ];
    
    ответ дан Chris Alan, с репутацией 1326, 23.10.2013
  • 16 рейтинг

    В настоящее время я участвую в решении этой проблемы с открытым исходным кодом через проект MCViewFactory, который можно найти здесь:

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

    Идея состоит в том, чтобы подражать парадигме намерений Android, используя глобальную фабрику для управления видом, который вы просматриваете, и используя «намерения» для переключения и передачи данных между представлениями. Вся документация находится на странице github, но вот некоторые основные моменты:

    Вы настраиваете все ваши взгляды в. XIB-файлы и зарегистрируйте их в приложении-делегате при инициализации фабрики.

    // Register activities
    
    MCViewFactory *factory = [MCViewFactory sharedFactory];
    
    // the following two lines are optional. 
    [factory registerView:@"YourSectionViewController"]; 
    

    Теперь, в вашем VC, каждый раз, когда вы хотите перейти к новому VC и передать данные, вы создаете новое намерение и добавляете данные в его словарь (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];
    }
    

    Надеюсь, некоторые из вас найдут это решение полезным / интересным.

    ответ дан does_not_exist, с репутацией , 16.09.2014
  • 14 рейтинг

    В моем случае я использовал одноэлементный класс, который может работать как глобальный объект, предоставляя доступ к данным практически из любого места в приложении. Первое, что нужно сделать - создать класс синглтона. Пожалуйста, обратитесь к странице " Как должен выглядеть мой синглтон Objective-C? " И что я сделал для того, чтобы сделать объект глобально доступным, просто импортировал его в appName_Prefix.pch, который предназначен для применения оператора импорта во всех классах. Чтобы получить доступ к этому объекту и использовать его, я просто реализовал метод класса для возвращения общего экземпляра, который содержит свои собственные переменные

    ответ дан petershine, с репутацией 2495, 6.03.2011
  • 13 рейтинг

    Создайте свойство на следующем view controller .h и определите геттер и сеттер.

    Добавить это property в NextVC. ч на nextVC

    @property (strong, nonatomic) NSString *indexNumber;
    

    Добавить

    @synthesize indexNumber; в NextVC. м

    и последний

    NextVC *vc=[[NextVC alloc]init];
    
    vc.indexNumber=@"123";
    
    [self.navigationController vc animated:YES];
    
    ответ дан Vivek Yadav, с репутацией 440, 2.01.2014
  • 12 рейтинг

    Я знаю, что это непростая тема, но для тех, кто хочет ответить на этот вопрос с уклоном SWIFT и хочет получить простой пример, здесь мой метод перехода для передачи данных, если вы используете переход, чтобы обойти.

    Это похоже на выше, но без кнопок, меток и тому подобное. Просто передавая данные из одного представления в другое.

    Настройка раскадровки

    Есть три части.

    1. Отправитель
    2. The Segue
    3. Приемник

    Это очень простой макет представления с переходом между ними.


    Very simple view layout. Note : No navigation controller


    Вот настройка для отправителя


    The Sender


    Вот настройка для приемника.


    The Receiver


    Наконец, установка для перехода.


    The Segue Identifier


    Контроллеры представления

    Мы придерживаемся этого простого, поэтому никаких кнопок, а не действий, мы просто перемещаем данные от отправителя к получателю при загрузке приложения, а затем выводим переданное значение на консоль.

    Эта страница принимает изначально загруженное значение и передает его.

    //
    //  ViewControllerSender.swift
    //  PassDataBetweenViews
    //
    //  Created by Chris Cantley on 8/25/15.
    //  Copyright (c) 2015 Chris Cantley. All rights reserved.
    //
    
    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
    
        }
    
    }
    

    Эта страница просто отправляет значение переменной в консоль при загрузке. К этому моменту наш любимый фильм должен быть в этой переменной.

    //
    //  ViewControllerReceiver.swift
    //  PassDataBetweenViews
    //
    //  Created by Chris Cantley on 8/25/15.
    //  Copyright (c) 2015 Chris Cantley. All rights reserved.
    //
    
    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)")
    
        }
    
    
    
    }
    

    Вот как вы можете справиться с этим, если хотите использовать переход, и у вас нет страниц под контроллером навигации.

    После запуска он должен автоматически переключиться на представление получателя и передать значение от отправителя получателю, отображая это значение в консоли.

    Ghost Busters is a classic folks.

    ответ дан Christopher Wade Cantley, с репутацией 3917, 25.08.2015
  • 10 рейтинг

    Делегирование - это единственное решение для выполнения таких операций при использовании. XIB-файлы, однако все ответы, описанные выше, для storyboard для. XIBS файлы вам нужно использовать делегирование. это единственное решение, которое вы можете.

    Другое решение - использовать шаблон класса singleton, инициализировать его один раз и использовать во всем приложении.

    ответ дан user2786888, с репутацией 101, 17.09.2013
  • 10 рейтинг

    , если вы хотите передать данные из ViewControlerOne в ViewController, попробуйте следующее. ,

    сделать это в ViewControlerOne. ч

     @property (nonatomic, strong) NSString *str1;
    

    сделать это в ViewControllerTwo. ч

     @property (nonatomic, strong) NSString *str2;
    

    Синтезировать str2 во ViewControllerTwo. м

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

    сделать это в ViewControlerOne. м

     - (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. м

    - (void)viewDidLoad
    {
     [super viewDidLoad];
      NSLog(@"%@",str2);
    }
    
    ответ дан krushnsinh, с репутацией 784, 27.05.2015
  • 10 рейтинг

    Есть множество способов сделать это, и важно выбрать правильный. Вероятно, одно из самых важных архитектурных решений заключается в том, каким образом код модели будет доступен или доступен во всем приложении.

    Некоторое время назад я написал сообщение в блоге об этом: Совместное использование кода модели . Вот краткое резюме:

    Общие данные

    Один из подходов заключается в совместном использовании указателей на объекты модели между контроллерами представления.

    • Итерация грубой силы на контроллерах представления (в контроллере навигации или панели вкладок) для установки данных
    • Установить данные в prepareForSegue (если раскадровки) или init (если программно)

    Так как подготовка к segue является наиболее распространенным, вот пример:

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

    Независимый доступ

    Другой подход заключается в одновременной обработке экрана, заполненного данными, и вместо того, чтобы соединять контроллеры представления друг с другом, соединяйте каждый контроллер представления с одним источником данных, к которому они могут обращаться независимо.

    Наиболее распространенный способ, которым я видел это, - это экземпляр синглтона . Поэтому, если ваш одноэлементный объект был DataAccess, вы могли бы сделать следующее в методе viewDidLoad объекта UIViewController:

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

    Существуют дополнительные инструменты, которые также помогают передавать данные:

    • Наблюдение значения ключа
    • NSNotification
    • Основные данные
    • NSFetchedResultsController
    • Источник данных

    Основные данные

    Приятно, что в Core Data есть обратные отношения. Поэтому, если вы хотите просто дать NotesViewController объект notes, вы можете это сделать, потому что он будет иметь обратную связь с чем-то другим, таким как блокнот. Если вам нужны данные на ноутбуке в NotesViewController, вы можете вернуться к графу объектов, выполнив следующие действия:

    let notebookName = note.notebook.name
    

    Подробнее об этом можно узнать из моего блога: Совместное использование кода модели

    ответ дан Korey Hinton, с репутацией 1946, 29.01.2015
  • 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. ч

    @interface NewsDetailViewController : UIViewController
    @property(nonatomic,retain) NSString *newsHeadlineStr;
    @end
    

    NewsDetailViewController. м

    @synthesize newsHeadlineStr;
    
    ответ дан Mohsin Sabasara, с репутацией 368, 24.10.2013
  • 10 рейтинг

    Вы можете сохранить данные в приложении делегат для доступа к ним через контроллеры представления в вашем приложении. Все, что вам нужно сделать, это создать общий экземпляр делегата приложения

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

    для примера

    если вы объявляете NSArray object *arrayXYZ, то вы можете получить к нему доступ в любом контроллере представления по appDelegate.arrayXYZ

    ответ дан ak_tyagi, с репутацией 614, 29.05.2015
  • 8 рейтинг

    Мне нравится идея объектов Model и объектов Mock на основе NSProxy для фиксации или отбрасывания данных, если то, что выбирает пользователь, может быть отменено.

    Легко передавать данные, так как это один объект или пара объектов, и, если у вас есть, скажем, контроллер UINavigationController, вы можете сохранить ссылку на модель внутри, и все контроллеры push-представления могут получить к ней доступ непосредственно из контроллера навигации.

    ответ дан highmaintenance, с репутацией 8424, 8.05.2014
  • 8 рейтинг

    Если вы хотите отправить данные из одного в другой viewController, вот способ:

    Скажем, у нас есть viewControllers: ViewController и NewViewController.

    в ViewController. ч

    #import 
    
    @interface ViewController : UIViewController
    {
        IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;
    }
    
    @property (nonatomic,retain) IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;
    
    -(IBAction)goToNextScreen:(id)sender;
    
    @end
    

    в ViewController. м

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

    #import 
    
    @interface NewViewController : UITableViewController
    {
        NSArray *arrayList;
    
        NSString *name,*age,*dob,*mobile;
    
    }
    
    @property(nonatomic, retain)NSArray *arrayList;
    
    @end
    

    В NewViewController. м

    #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
    

    Таким образом, мы можем передать данные из одного контроллера представления в другой контроллер представления. , ,

    ответ дан Sabs, с репутацией 669, 5.08.2013
  • 7 рейтинг

    Я видел много людей, которые усложняли это, используя метод didSelectRowAtPath. Я использую основные данные в моем примере.

    - (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 строки кода внутри метода, и все готово.

    ответ дан App Dev Guy, с репутацией 3400, 16.01.2015
  • 3 рейтинг

    Существует множество ответов на эти вопросы, предлагающих множество различных способов осуществления связи с контроллером представления, которые действительно будут работать, но я нигде не вижу упоминания, какой из них на самом деле лучше использовать, а какие - избегать.

    На практике, на мой взгляд, рекомендуется всего несколько решений:

    • Для передачи данных вперед:
      • переопределяет метод prepare(for:sender:) для UIViewController при использовании раскадровки и сегментов
      • передавать данные через инициализатор или через свойства при выполнении переходов контроллера представления через код
    • Для передачи данных в обратном направлении
      • Обновление общего состояния приложения (которое можно передать между контроллерами представления одним из указанных выше способов).
      • делегирование использования
      • использовать раскрутить Segu

    Решения, которые я НЕ рекомендую использовать:

    • Ссылка на предыдущий контроллер напрямую вместо использования делегирования
    • Обмен данными через синглтон
    • Передача данных через приложение-делегат
    • Обмен данными через пользователя по умолчанию
    • Передача данных через уведомления

    Эти решения, хотя и работают в краткосрочной перспективе, вводят слишком много зависимостей, которые искажают архитектуру приложения и создают дополнительные проблемы в дальнейшем.

    Для тех, кто заинтересован, я написал несколько статей, в которых более подробно рассматриваются эти вопросы и выделены различные недостатки:

    ответ дан Matteo Manferdini, с репутацией 108, 3.12.2016
  • 3 рейтинг

    Это действительно отличный учебник для всех, кто этого хочет. Вот пример кода:

    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
        if ([segue.identifier isEqualToString:@"myIdentifer]) {
            NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
            myViewController *destViewController = segue.destinationViewController;
            destViewController.name = [object objectAtIndex:indexPath.row];
        }
    }
    
    ответ дан crazy_tiger_corp, с репутацией 81, 28.09.2015
  • 2 рейтинг

    для отправки данных из одного VC в другой используйте этот простой подход:

    YourNextVC *nxtScr = (YourNextVC*)[self.storyboard  instantiateViewControllerWithIdentifier:@"YourNextVC"];//Set this identifier from your storyboard
    
    nxtScr.comingFrom = @"PreviousScreen"l
    [self.navigationController nxtScr animated:YES];
    
    ответ дан Dalvik, с репутацией 2026, 28.11.2015
  • 1 рейтинг

    хорошо у нас есть несколько способов, которыми мы можем работать с системой делегатов или с использованием раскадровкиSegue

    1- As working with setter and getter method like in viewController.h
       @property (retain, nonatomic) NSString *str;
       now, in viewController.m
       @synthesize str;
    
    
       here i have pdf url and segue to another viewController like this and pdfObject is my pdfModel basicilly is NSOBJECT class.  
    
       str =[NSString stringWithFormat:@"%@",pdfObject.objPath];
    NSLog(@"pdfUrl :***: %@ :***:",pdfUrl);
    
    [self performSegueWithIdentifier:@"programPDFViewController_segue" sender:self];
    

    Прагма Марк - Навигация

      // In a storyboard-based application, you will often want to do a little preparation before navigation
    
     - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    
        if ([[segue identifier] isEqualToString:@"programPDFViewController_segue"]){
        programPDFViewController *pdfVC = [segue destinationViewController];
        [pdfVC setRecievedPdfUrl:str];
    
       }
     }
    

    Теперь успешно я получил мою строку PDF PDF и другой ViewController и использовать эту строку в веб-представлении. , ,

    2. При работе с такими делегатами у меня есть один класс утилит NSObject, содержащий мои методы dateFormatter, sharedInstance, EscapeWhiteSpaceCharacters, convertImageToGrayScale и другие методы, с которыми я работал через приложение, так что теперь в утилитах. ч

    в этом вам не нужно создавать переменные при постоянном анализе данных от одного к другому контроллеру представления один раз, когда вы создали строковую переменную в утилитах. час просто сделай это ноль; и использовал снова

      @interface Utilities : NSObject
    
      Utilities.h
     +(Utilities*)sharedInstance;
    
     @property(nonatomic,retain)NSString* strUrl;
    

    сейчас в ЖКХ. м

       @implementation utilities
    
    
      +(utilities*)sharedInstance
      {
      static utilities* sharedObj = nil;
      if (sharedObj == nil) {
        sharedObj = [[utilities alloc] init];
        }
       return sharedObj;
      }
    
    now its done come to your firstViewController.m and call delegate
    
    NSString*str =[NSString stringWithFormat:@"%@",pdfObject.objPath];
    
    [Connection sharedInstance].strUrl=nil;
    [Connection sharedInstance].strUrl=str;
    
     Now go to you secondViewController.m directly use it without creating variable 
    
     in viewwillapear what i did
    
     -(void)viewWillAppear:(BOOL)animated{
         [super viewWillAppear:YES];
    
       [self webViewMethod:[Connection sharedInstance].strUrl];
    
     }
    
    
     -(void)WebViewMethod:(NSString)Url{
    
     // working with webview enjoy coding :D
    
     }
    

    эта работа делегата является надежной с управлением памятью

    ответ дан Nayab Khan, с репутацией 86, 7.05.2018
  • 1 рейтинг

    Я рекомендую блоки / замыкания и пользовательские конструкторы.

    Предположим, вам нужно передать строку из FirstViewController в SecondViewController.

    Ваш первый контроллер просмотра.

    class FirstViewController : UIViewController {
    
        func moveToViewControllerB() {
    
            let second_screen = SecondViewController.screen(string: "DATA TO PASS", call_back: {
                [weak self] (updated_data) in
                ///This closure will be called by second view controller when it updates something
            })
            self.navigationController?.pushViewController(second_screen, animated: true)
        }
    
    
    }
    

    Ваш второй контроллер просмотра

    class SecondViewController : UIViewController {
    
        var incoming_string : String?
        var call_back : ((String) -> Void)?
    
        class func screen(string: String?, call_back : ((String) -> Void)?) -> SecondViewController {
    
            let me = SecondViewController(nibName: String(describing: self), bundle: Bundle.main);
            me.incoming_string = string
            me.call_back = call_back
            return me
        }
    
        // Suppose its called when you have to update FirstViewController with new data.
        func updatedSomething() {
    
            //Executing block that is implemented/assigned by the FirstViewController.
            self.call_back?("UPDATED DATA")
        }
    
    }
    
    ответ дан Umair, с репутацией 321, 8.05.2017
  • 1 рейтинг

    Существует 3 типа для передачи данных из одного ViewController в другой ViewController.

    1. Программно
    2. Segue
    3. UserDefaults

    Демонстрационный проект Ссылка здесь - https: // github. com / kamanijasmin13 / Swift-Pass-data-Между-view-контроллерами

    Программно enter image description here

    Segue enter image description here

    UserDefaults enter image description here

    Демонстрационный проект Ссылка здесь - https: // github. com / kamanijasmin13 / Swift-Pass-data-Между-view-контроллерами

    ответ дан Kamani Jasmin, с репутацией 307, 23.03.2018
  • 1 рейтинг

    Вы можете создать push-переход от исходного viewcontroller к целевому viewcontroller и дать имя идентификатора, как показано ниже. enter image description here

    Вы должны выполнить переход от didselectRow. Вот так.

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        performSegue(withIdentifier: "segue", sender: self)
    }
    

    И вы можете передать массив выбранного элемента из функции ниже.

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let index = CategorytableView.indexPathForSelectedRow
        let indexNumber = index?.row
        print(indexNumber!)
        let VC = segue.destination as! AddTransactionVC
       VC.val = CategoryData[indexNumber!] . //You can pass here entire array instead of array element.
    
    }
    

    И вы должны проверить значение в viewdidload целевого viewcontroller и затем сохранить его в базе данных.

    override func viewDidLoad{
     if val != ""{
            btnSelectCategory.setTitle(val, for: .normal)
        }
    }
    
    ответ дан Parth Barot, с репутацией 103, 12.04.2018
  • 1 рейтинг

    Apple может сделать это, используя Segues. Вам нужно использовать функцию prepareForSegue ()

    Есть много отличных уроков, вот один: https: // www. iphonelife. com / content / unleash-your-inner-app-developer-part-21-Passing Data-Inter-Controllers

    Также ознакомьтесь с документами Apple по использованию сегментов: https: // разработчик. яблоко. ком / библиотека / ИОС / featuredarticles / ViewControllerPGforiPhoneOS / UsingSegues. HTML

    ответ дан tmac_balla, с репутацией 568, 22.12.2015
  • 0 рейтинг

    Более простой способ здесь.

    Просто используйте глобальную переменную. Объявите объект или переменную, необходимые для перехода к следующему классу.

    Например, у нас есть 2 класса - classA и classB соответственно.

    В classA обычно содержится:

    #import "classA.h"
    
    @interface classA()
    
    @end
    
    @implementation classA
    
    -(void)viewDidLoad
    {
        ...
    }
    -(void)didReceiveMemoryWarning
    {
        ...
    }
    

    и classB содержит:

    #import "classB.h"
    
    @interface classB()
    
    @end
    
    @implementation classB
    
    -(void)viewWillLoad
    {
        ...
    }
    -(void)didReceiveMemoryWarning
    {
        ...
    }
    

    Теперь импортируйте второй класс classB в classA

    #import "classA.h"
    #import "classB.h"  //---import classB to classA.
    @interface classA()
    
    @end
    
    @implementation classA
    
    -(void)viewDidLoad
    {
        ...
    }
    -(void)didReceiveMemoryWarning
    {
        ...
    }
    

    Теперь у нас есть мост, чтобы перейти ко второму классу classB Теперь, чтобы объявить переменную или объект как глобальный, объявите его в. м файл первого класса, как показано ниже

    В classA.h

    #import "classA.h"
    #import "classB.h"
    @interface classA()
    
    @end
    NSString *temp;  //----declare any object/variable as global.
    @implementation classA
    
    -(void)viewDidLoad
    {
        ...
        temp=@"Hello";
        ...
    }
    -(void)didReceiveMemoryWarning
    {
        ...
    }
    

    Здесь объект temp является глобальным объектом класса NSString для доступа к глобальному объекту или переменной в любом классе, просто повторно объявите объект или переменную во втором классе. Например. с учетом ниже:

    В classB.m

    #import "classB.h"
    
    @interface classB()
    
    @end
    extern NSString *temp;  //----use `extern` keyword for using the global object/variable in classB that was declared in classA.
    @implementation classB
    
    -(void)viewDidLoad
    {
        ...
        LabeL.text=temp;
        ...
    }
    -(void)didReceiveMemoryWarning
    {
        ...
    }
    

    Теперь к значению может обращаться второй класс. Просто! , , Этот метод может быть использован для любого количества классов.

    Примечание:

    Вы должны импортировать. h файл второго класса в первый класс. Но не нужно импортировать . h файл первого класса во второй класс.

    Запомните мост, если он есть, он должен идти с обеих сторон.

    Я думаю, что это поможет. Это помогло мне, когда я был в такой же ситуации.

    ответ дан soorej babu, с репутацией 193, 7.07.2016
  • 0 рейтинг

    Вы должны всегда следовать концепции MVC при создании приложений для iOS. Существует два сценария, когда вы можете захотеть передать данные из ViewController в другой:

    1. Когда в иерархии есть ViewContoller «A», и вы хотите отправить некоторые данные в «B», который является следующим viewcontroller. В этом случае вы должны использовать Segue. Просто установите идентификатор для перехода, а затем в «A» VC, напишите следующий код:

      override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
          if segue.identifier == "A to B segue identifier" {
              let bViewController = segue.destination as! UIDocumentBrowserViewController
              bViewController.data = someData
          }
      }
      
    2. Когда есть A, который открыл B на себя как модальный (или встроенный). Теперь B viewcontroller должен игнорировать своего родителя. Поэтому лучший способ отправить данные обратно на номер A - использовать Delegation. Создайте протокол делегата в контроллере представления B и свойстве delegate. Таким образом, B сообщит (отправит данные обратно) своему делегату. В контроллере вида A мы реализуем протокол делегата контроллера B и установим self как свойство delegate контроллера взгляда B в методе prepare(forSegue:).

    Вот как это должно быть правильно реализовано. Надеюсь, это поможет

    ответ дан Shahin, с репутацией 576, 26.03.2018
  • -4 рейтинг

    Используйте центр уведомлений для передачи данных из одного представления в другое. Шаблон слушателя-наблюдателя работает лучше всего. Другим обходным путем может быть создание одинаковых объектов в обоих классах, Создайте объект класса 2 в классе один, получите доступ к передаваемым объектам данных и установите их, а затем нажмите контроллер представления.

    ответ дан Jay Sampat, с репутацией 114, 17.07.2013