it-swarm.com.ru

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

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

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

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

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

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

1254
Matt Price

Этот вопрос, кажется, очень популярен здесь на 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 в значение BOOLYES.

Передача данных через Segues

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

-(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", и если это будет выполнено, мы передадим наше значение BOOLViewControllerB

    -(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 в значение BOOLYES.

Передача данных назад

Чтобы передать данные обратно из 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 или любой другой класс)

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

В этом примере данные передаются из Controller B в Controller A

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

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

добавить обработчик блока (слушатель) , где вам нужно значение (например, вам нужен ваш ответ API в ControllerA или вам нужны данные 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];
}

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

1599
Matt Price

Стриж

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

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

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

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.

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

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

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

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.

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

164
Suragch

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

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

122
Caleb

Существуют различные способы получения данных в другом классе в 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.

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

87
borncrazy

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

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

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

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

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

78
Matt Price

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

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

61
Leszek Zarna

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

Вопрос касается передачи информации между контроллерами представления. В приведенном конкретном примере запрашивается передача информации между представлениями, но с учетом самооценки новизны 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 контроллеров представления каждый раз, когда один контроллер представления вносит изменения?

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

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

  • перетекает
  • делегаты
  • установка свойств на контроллеры вида напрямую
  • 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

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

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

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

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

50
Jason Cross

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

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

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

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

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

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

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

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

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

-(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 вы можете изменить любое свойство, которым хотите поделиться.

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

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

:) ура.

38
Yevgeni

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

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

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

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

37
Anubrata Santra

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

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

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

Я долго искал это решение, 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 должен иметь функцию setter.

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

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

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

25
AsifHabib

Это не способ сделать это, вы должны использовать делегаты, я предполагаю, что у нас есть два контроллера представления 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

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

21
Boda Taljo

Если вы хотите отправить данные из одного в другой 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 без установки какого-либо делегата. ;)

19
Aniruddh Joshi

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

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

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

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

18
kaar3k

Передача данных между 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 ];
16
Chris Alan

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

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

16
user2563044

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

15
petershine

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

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

@property (strong, nonatomic) NSString *indexNumber;

Добавлять 

@synthesize indexNumber; в NextVC.m

И последнее

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

[email protected]"123";

[self.navigationController vc animated:YES];
13
Vivek Yadav

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

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

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

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

  1. Отправитель
  2. 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.

12
Christopher Wade Cantley

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

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

10
user2786888

если вы хотите передать данные из 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);
}
10
krushnsinh

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

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

Общие данные

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

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

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

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

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

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

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

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

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

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

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

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

let notebookName = note.notebook.name

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

10
Korey Hinton

NewsViewController

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
  [tbl_View deselectRowAtIndexPath:indexPath animated:YES];
  News *newsObj = [newstitleArr objectAtIndex:indexPath.row];
  NewsDetailViewController *newsDetailView = [[NewsDetailViewController alloc] initWithNibName:@"NewsDetailViewController" bundle:nil];

  newsDetailView.newsHeadlineStr = newsObj.newsHeadline;

  [self.navigationController pushViewController:newsDetailView animated:YES];
}

NewsDetailViewController.h

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

NewsDetailViewController.m

@synthesize newsHeadlineStr;
10
Mohsin Sabasara

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

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

Например

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

10
ak_tyagi

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

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

8
highmaintenance

Если вы хотите отправить данные из одного в другой 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

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

8
Sabs

Я видел, как многие люди усложняли это, используя метод 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 строки кода внутри метода, и все готово. 

7
App Dev Guy

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

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

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

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

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

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

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

5
Matteo Manferdini

Есть 3 типа для передачи данных от одного ViewController к другому ViewController.

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

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

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

Segue enter image description here

UserDefaults enter image description here

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

4
Kamani Jasmin

Swift 5

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

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

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

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


Передача данных через контроллер навигации 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 в раскадровке, как показано ниже

 enter image description here 

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

3
swiftBoy

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

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

ИСПОЛЬЗОВАНИЕ ЦЕНТРА УВЕДОМЛЕНИЙ

Для Swift 3

let imageDataDict:[String: UIImage] = ["image": image]

  // post a notification
  NotificationCenter.default.post(name: NSNotification.Name(rawValue: "notificationName"), object: nil, userInfo: imageDataDict) 
  // `default` is now a property, not a method call

 // Register to receive notification in your class
 NotificationCenter.default.addObserver(self, selector: #selector(self.showSpinningWheel(_:)), name: NSNotification.Name(rawValue: "notificationName"), object: nil)

 // handle notification
 func showSpinningWheel(_ notification: NSNotification) {
        print(notification.userInfo ?? "")
        if let dict = notification.userInfo as NSDictionary? {
            if let id = dict["image"] as? UIImage{
                // do something with your image
            }
        }
 }

Для Swift 4

let imageDataDict:[String: UIImage] = ["image": image]

  // post a notification
  NotificationCenter.default.post(name: NSNotification.Name(rawValue: "notificationName"), object: nil, userInfo: imageDataDict) 
  // `default` is now a property, not a method call

 // Register to receive notification in your class
 NotificationCenter.default.addObserver(self, selector: #selector(self.showSpinningWheel(_:)), name: NSNotification.Name(rawValue: "notificationName"), object: nil)

 // handle notification
 @objc func showSpinningWheel(_ notification: NSNotification) {
        print(notification.userInfo ?? "")
        if let dict = notification.userInfo as NSDictionary? {
            if let id = dict["image"] as? UIImage{
                // do something with your image
            }
        }
 }
3
Sachin Rasane

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

YourNextVC *nxtScr = (YourNextVC*)[self.storyboard  instantiateViewControllerWithIdentifier:@"YourNextVC"];//Set this identifier from your storyboard

nxtScr.comingFrom = @"PreviousScreen"l
[self.navigationController nxtScr animated:YES];
2
Dalvik

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

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 и другие методы, с которыми я работал через приложение, так что теперь в utilities.h

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

  @interface Utilities : NSObject

  Utilities.h
 +(Utilities*)sharedInstance;

 @property(nonatomic,retain)NSString* strUrl;

сейчас в утилитах.m

   @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

 }

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

2
Nayab Khan

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

Предположим, вам нужно передать строку из 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")
    }

}
1
Umair

Вы можете создать 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)
    }
}
1
Parth Barot

Я предпочитаю делать это без делегатов и segues. Это можно сделать с помощью пользовательского init или установив дополнительные значения.

1. Custom init

class ViewControllerA: UIViewController {
  func openViewControllerB() {
    let viewController = ViewControllerB(string: "Blabla", completionClosure: { success in
      print(success)
    })
    navigationController?.pushViewController(animated: true)
  }
}

class ViewControllerB: UIViewController {
  private let completionClosure: ((Bool) -> Void)
  init(string: String, completionClosure: ((Bool) -> Void)) {
    self.completionClosure = completionClosure
    super.init(nibName: nil, bundle: nil)
    title = string
  }

  func finishWork() {
    completionClosure()
  }
}

2. Дополнительные переменные

class ViewControllerA: UIViewController {
  func openViewControllerB() {
    let viewController = ViewControllerB()
    viewController.string = "Blabla"
    viewController.completionClosure = { success in
      print(success)
    }
    navigationController?.pushViewController(animated: true)
  }
}

class ViewControllerB: UIViewController {
  var string: String? {
    didSet {
      title = string
    }
  }
  var completionClosure: ((Bool) -> Void)?

  func finishWork() {
    completionClosure?()
  }
}
1
Timur Bernikovich

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

Вокруг много хороших учебных пособий, вот один: https://www.iphonelife.com/content/unleash-your-inner-app-developer-part-21-passing-data-between-controllers

Также ознакомьтесь с документами Apple по использованию сегментов: https://developer.Apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/UsingSegues.html

1
tmac_balla

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

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

Например, у нас есть 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
{
    ...
}

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

В classA.h

#import "classA.h"
#import "classB.h"
@interface classA()

@end
NSString *temp;  //----declare any object/variable as global.
@implementation classA

-(void)viewDidLoad
{
    ...
    [email protected]"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 первого класса во второй класс.

Помните мост, если есть мост, он должен быть в состоянии идти с обеих сторон.

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

0
soorej babu

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

  1. Когда в иерархии есть ViewContoller типа «A», и вы хотите отправить некоторые данные в «B», который является next 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 viewcontroller и свойстве delegate. Таким образом, B сообщит (отправит данные обратно) своему делегату. В A viewcontroller мы реализуем протокол делегирования B viewcontroller и установим self в качестве свойства delegateB viewcontroller в методе prepare(forSegue:).

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

0
Shahin