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

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

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

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

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

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

48 ответов

Решение

Этот вопрос, кажется, очень популярен здесь на stackru, поэтому я подумал, что постараюсь дать лучший ответ, чтобы помочь людям, начинающим в мире 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 <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 Center Это еще один способ передачи данных.

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

Передача данных обратно из одного класса в другой (классом может быть любой контроллер, менеджер сети / сеанса, подкласс UIView или любой другой класс)

Блоки являются анонимными функциями.

В этом примере данные передаются с контроллера B на контроллер A

определить блок

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

добавьте обработчик блоков (слушатель) там, где вам нужно значение (например, вам нужен ответ API в Controller A или вам нужны данные ContorllerB на A)

// in ContollerA.m

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

Перейти к контроллеру B

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

Еще один рабочий пример для блоков

стриж

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

Передача данных вперед на следующий View Controller

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

Создайте макет раскадровки в Интерфейсном Разработчике. Чтобы перейти к следующему этапу, просто нажмите " 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.

Передача данных обратно в предыдущий View Controller

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

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

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

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

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

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

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

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

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

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

Предположим, в классе 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.

Надеюсь это поможет

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

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

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

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

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

Я нахожу самый простой и самый элегантный вариант с прохождением блоков. Давайте назовем контроллер представления, который ожидает возвращенные данные, как "A" и возвращающий контроллер представления как "B". В этом примере мы хотим получить 2 значения: первое из Type1 и второе из Type2.

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

- (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.h:

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

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

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

Следует помнить одну вещь: использование блока часто требует управления сильными и слабыми ссылками, как описано здесь.

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

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

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

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

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

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

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

схема исходной задачи

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

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

схема применения домашнего инвентаря

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

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

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

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

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

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

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

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

  • Шаблон наблюдателя
  • Одиночки

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

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

  • Key-Value-Observing (KVO)
  • NSNotificationCenter.

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

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

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

Рекомендации

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

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

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

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

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

использовать его в prepareForSegue метод в ВК1

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

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

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

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

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

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

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

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

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

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

:) ура.

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

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

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

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

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

Swift 5

Ответ Мэтта Прайса отлично подходит для передачи данных, но я собираюсь переписать его, в последней версии Swift, потому что я верю, что новые программисты считают его более сложным из-за нового синтаксиса и методов / фреймворков, как и оригинальная статья в Objective-C.

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

  1. Использование навигационного контроллера Push
  2. Используя Segue
  3. Использование делегата
  4. Использование Notification Observer
  5. Используя Блок

Я собираюсь переписать его логику в Swift с последней iOS Framework


Передача данных через контроллер Navigation Push: из 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)
    }
}

Передача данных через Segue: из ViewControllerA в ViewControllerB

Шаг 1. Создайте Segue из ViewControllerA в ViewControllerB и задайте Identifier = showDetailSegue в раскадровке, как показано ниже

Шаг 2. В ViewControllerB объявите переменную с именем isSomethingEnabled и напечатайте ее значение.

Шаг 3. В ViewControllerA передайте значение isSomethingEnabled при передаче Segue

Итак, вот полный код для:

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. Отправка данных для делегата внутри метода viewDidLoad ViewControllerB

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

Шаг 4. Подтвердите ViewControllerBDelegate в ViewControllerA

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

Передача данных через Notification Observer: из 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 authorizationCompletionBlock: ((Bool) -> ())? = {_ 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. Пожалуйста, дайте мне знать, если у вас есть какие-либо вопросы по этому вопросу.

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

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

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

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

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

Надеюсь это поможет.

Я долго искал это решение, 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.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 ];

Берегите орфографические ошибки.

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

Добавьте новый файл в ваш проект (протокол Objective-C) Файл -> Новый, теперь назовите его 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; 

Теперь, если вы создаете 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

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

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

Скажем, у нас есть viewControllers: 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 без установки какого-либо делегата.;)

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

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

Настройте раскадровку

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

  1. Отправитель
  2. Segue
  3. Получатель

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


Очень простой вид компоновки.  Примечание: нет контроллера навигации


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


Отправитель


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


Получатель


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


Идентификатор Segue


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

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

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

//
//  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 - это классические люди

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

Например:

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

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

В настоящее время я участвую в разработке решения этой проблемы с открытым исходным кодом через проект 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];
}

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

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

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

@property (strong, nonatomic) NSString *indexNumber;

добавлять

@synthesize indexNumber; в NextVC.m

И последнее

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

vc.indexNumber=@"123";

[self.navigationController vc animated:YES];

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

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

Общие данные

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

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

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

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

Подробнее об этом читайте в моем блоге: разделение кода модели

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

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

 @property (nonatomic, strong) NSString *str1;

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

 @property (nonatomic, strong) NSString *str2;

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

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

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

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

Например

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

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;

Делегирование является единственным решением для выполнения таких операций при использовании файлов.xib, однако все ответы, описанные выше, предназначены для storyboard для файлов.xibs необходимо использовать делегирование. это единственное решение, которое вы можете.

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

Для SwiftUI

Думать о @EnvironmentObject как более умный и простой способ использования @ObservedObjectна большом количестве просмотров. Вместо того, чтобы создавать некоторые данные в представлении A, а затем передавать их представлению B, затем представлению C, затем представлению D, прежде чем, наконец, использовать его, вы можете создать его в представлении и поместить в среду, чтобы представления B, C и D автоматически получить к нему доступ.

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

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

class UserSettings: ObservableObject {
     @Published var score = 0
}

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

Скажем, у нас есть viewControllers: 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

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

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

  1. Programatically
  2. переход
  3. UserDefaults

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

Programatically введите описание изображения здесь

переход введите описание изображения здесь

UserDefaults введите описание изображения здесь

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

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

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

Другие вопросы по тегам