Передача данных между контроллерами представления
Я новичок в iOS и Objective-C и во всей парадигме MVC, и я застрял в следующем:
У меня есть представление, которое действует как форма ввода данных, и я хочу дать пользователю возможность выбрать несколько продуктов. Продукты перечислены на другом экране с UITableViewController
и я включил несколько вариантов.
У меня вопрос, как мне перенести данные из одного представления в другое? Я буду проводить выборы на UITableView
в массиве, но как мне затем передать это обратно в предыдущее представление формы ввода данных, чтобы оно могло быть сохранено вместе с другими данными в Core Data при отправке формы?
Я просмотрел и видел, как некоторые люди объявляют массив в делегате приложения. Я читаю кое-что о Singletons, но не понимаю, что это такое, и я читаю кое-что о создании модели данных.
Каков будет правильный способ выполнения этого и как я буду это делать?
48 ответов
Этот вопрос, кажется, очень популярен здесь на stackru, поэтому я подумал, что постараюсь дать лучший ответ, чтобы помочь людям, начинающим в мире iOS, как я.
Я надеюсь, что этот ответ достаточно ясен для понимания людьми, и я ничего не пропустил.
Передача данных вперед
Передача данных в контроллер представления от другого контроллера представления. Вы бы использовали этот метод, если хотите передать объект / значение из одного контроллера представления в другой контроллер представления, который вы, возможно, помещаете в стек навигации.
Для этого примера мы будем иметь ViewControllerA
а также ViewControllerB
Пройти BOOL
значение от ViewControllerA
в ViewControllerB
мы бы сделали следующее.
в
ViewControllerB.h
создать свойство дляBOOL
@property (nonatomic, assign) BOOL isSomethingEnabled;
в
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
мы бы сделали следующее:
в
ViewControllerB.h
создать свойство дляBOOL
@property (nonatomic, assign) BOOL isSomethingEnabled;
в
ViewControllerA
ты должен рассказать об этомViewControllerB
так что используйте#import "ViewControllerB.h"
Создать переход от
ViewControllerA
вViewControllerB
на раскадровке и дать ему идентификатор, в этом примере мы назовем его"showDetailSegue"
Далее нам нужно добавить метод
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
какие методы он должен реализовать.
В
ViewControllerB.h
, ниже#import
, но выше@interface
вы указываете протокол.@class ViewControllerB; @protocol ViewControllerBDelegate <NSObject> - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item; @end
следующий еще в
ViewControllerB.h
вам нужно настроитьdelegate
собственность и синтезировать вViewControllerB.m
@property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
В
ViewControllerB
мы вызываем сообщение наdelegate
когда мы выскакиваем контроллер представления.NSString *itemToPassBack = @"Pass this value back to ViewControllerA"; [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
Это для
ViewControllerB
, Сейчас вViewControllerA.h
, сказатьViewControllerA
импортироватьViewControllerB
и соответствовать его протоколу.#import "ViewControllerB.h" @interface ViewControllerA : UIViewController <ViewControllerBDelegate>
В
ViewControllerA.m
реализовать следующий метод из нашего протокола- (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item { NSLog(@"This was returned from ViewControllerB %@",item); }
Перед нажатием
viewControllerB
к стеку навигации нужно сказатьViewControllerB
тотViewControllerA
является его делегатом, в противном случае мы получим ошибку.ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil]; viewControllerB.delegate = self [[self navigationController] pushViewController:viewControllerB animated:YES];
Рекомендации
- Использование делегирования для связи с другими контроллерами представления в Руководстве по программированию контроллера представления
- Шаблон делегата
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 (именно это помогло мне наконец понять, как это сделать).
- Учебник YouTube: как отправить данные через segue (swift)
Передача данных вперед на следующий 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
Чтобы передать данные от второго контроллера представления к первому контроллеру представления, вы используете протокол и делегат. Это видео очень ясно показывает, как проходит этот процесс:
- Учебник YouTube: Учебник по основам iOS Swift: протоколы и делегаты Но также прочитайте этот пост, чтобы убедиться, что вы не попали в сильный справочный цикл.
Ниже приведен пример, основанный на видео (с некоторыми изменениями).
Создайте макет раскадровки в Интерфейсном Разработчике. Опять же, чтобы сделать переход, вы просто управляете перетаскиванием с кнопки на контроллер второго вида. Установите идентификатор 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. Например -
- Прямая инициализация после выделения другого класса.
- Делегирование - для передачи данных обратно
- Уведомление - для передачи данных нескольким классам одновременно
- Сохранение в
NSUserDefaults
- для доступа к нему позже - Синглтон классы
- Базы данных и другие механизмы хранения, такие как 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.
Надеюсь, я добавил что-то к обсуждению.
:) ура.
Существует несколько способов обмена данными.
Вы всегда можете поделиться данными, используя
NSUserDefaults
, Установите значение, которым вы хотите поделиться в отношении ключа по вашему выбору и получить значение отNSUserDefault
связан с этим ключом в следующем контроллере представления.[[NSUserDefaults standardUserDefaults] setValue:value forKey:key] [[NSUserDefaults standardUserDefaults] objectForKey:key]
Вы можете просто создать недвижимость в
viewcontrollerA
, Создать объект изviewcontrollerA
вviewcontrollerB
и назначьте желаемое значение этому свойству.Вы также можете создавать собственные делегаты для этого.
В 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.
Существует несколько вариантов передачи данных между контроллерами представления.
- Использование навигационного контроллера Push
- Используя Segue
- Использование делегата
- Использование Notification Observer
- Используя Блок
Я собираюсь переписать его логику в 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 и хочет получить простой пример, здесь мой метод перехода для передачи данных, если вы используете переход, чтобы обойти.
Это похоже на выше, но без кнопок, ярлыков и тому подобное. Просто передавая данные из одного представления в другое.
Настройте раскадровку
Есть три части.
- Отправитель
- 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)")
}
}
Вот как вы можете справиться с этим, если хотите использовать переход, и у вас нет страниц под контроллером навигации.
После запуска он должен автоматически переключиться на представление получателя и передать значение от отправителя получателю, отображая это значение в консоли.
Передача данных между 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.
- Programatically
- переход
- UserDefaults
Ссылка на демонстрационный проект здесь - https://github.com/kamanijasmin13/Swift-Pass-data-between-viewcontrollers
Ссылка на демонстрационный проект здесь - https://github.com/kamanijasmin13/Swift-Pass-data-between-viewcontrollers
Мне нравится идея объектов Model и объектов Mock на основе NSProxy для фиксации или отбрасывания данных, если то, что выбирает пользователь, может быть отменено.
Данные легко передавать, так как это один объект или пара объектов, и, если у вас есть, скажем, контроллер UINavigationController, вы можете сохранить ссылку на модель внутри, и все контроллеры push-представления могут получить к ней доступ непосредственно из контроллера навигации.