ios - экранами - переход между viewcontroller swift




Передача данных между контроллерами просмотра (20)

стриж

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

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

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

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

Контроллер первого взгляда

Код для первого контроллера просмотра

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 розетки для UITextField и UILabel .
  • Установите первый и второй контроллеры просмотра в соответствующие файлы Swift в IB.

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

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

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

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

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

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

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

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

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

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


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

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


Во многих ответах есть какая-то хорошая информация, но никто не затрагивает вопрос полностью.

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

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

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

Сценарии приложений

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

Сценарий один: максимум два диспетчера представлений требуют обмена информацией. См. Диаграмму 1.

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

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

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

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

Каждый раз, когда отдельный элемент создается или редактируется, он также должен синхронизироваться с другими контроллерами представлений. Например, если мы добавим лодку в ViewControllerD, но она еще не застрахована, тогда лодка должна появиться, когда пользователь перейдет в ViewControllerA (Luxury Items), а также ViewControllerC (Entire Home Inventory), но не тогда, когда пользователь переходит к ViewControllerB (незастрахованные элементы). Нам нужно не только добавлять новые элементы, но и удалять элементы (которые могут быть разрешены с любого из четырех контроллеров представления) или редактировать существующие элементы (которые могут быть разрешены из «Добавить новую форму элемента», для редактирования).

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

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

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

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

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

  • Схема наблюдателя
  • Одиночки

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

+ (HouseholdInventoryManager*) sharedManager; {
    static dispatch_once_t onceQueue;
    static HouseholdInventoryManager* _sharedInstance;

    // dispatch_once is guaranteed to only be executed once in the
    // lifetime of the application
    dispatch_once(&onceQueue, ^{
        _sharedInstance = [[self alloc] init];
    });
    return _sharedInstance;
}

Теперь, когда мы понимаем, что такое синглтон, давайте обсудим, как синглтон вписывается в шаблон наблюдателя. Шаблон наблюдателя используется для того, чтобы один объект реагировал на изменения другого объекта. Во втором сценарии у нас есть четыре разных контроллера представлений, которые все хотят знать об изменениях в базовых данных. «Базовые данные» должны принадлежать одному экземпляру, одноточечному. «Знание об изменениях» достигается путем наблюдения за изменениями, внесенными в синглтон.

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

#import <Foundation/Foundation.h>

@class JGCHouseholdInventoryItem;

@interface HouseholdInventoryManager : NSObject
/*!
 The global singleton for accessing application data
 */
+ (HouseholdInventoryManager*) sharedManager;


- (NSArray *) entireHouseholdInventory;
- (NSArray *) luxuryItems;
- (NSArray *) nonInsuredItems;

- (void) addHouseholdItemToHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) editHouseholdItemInHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) deleteHoueholdItemFromHomeInventory:(JGCHouseholdInventoryItem*)item;
@end

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

  • Наблюдение за ключевыми значениями (КВО)
  • NSNotificationCenter.

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

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

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

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


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

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

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

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

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


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

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

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

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

В этом примере мы будем иметь ViewControllerA и ViewControllerB

Чтобы передать значение BOOL из ViewControllerA в ViewControllerB мы сделали бы следующее.

  1. в ViewControllerB.h создайте свойство для BOOL

    @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  2. в ViewControllerA вам нужно рассказать об этом ViewControllerB поэтому используйте

    #import "ViewControllerB.h"
    

    Затем, где вы хотите загрузить представление, например. didSelectRowAtIndex или какой-то IBAction вам нужно установить свойство в ViewControllerB прежде чем вы нажмете его на навигационный стек.

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

    Это установит isSomethingEnabled в ViewControllerB на значение BOOL YES .

Передача данных вперед с помощью Segues

Если вы используете раскадровки, вы, скорее всего, используете 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 из ViewControllerA в ViewControllerB на раскадровке и дайте ему идентификатор, в этом примере мы будем называть его "showDetailSegue"

  4. Затем нам нужно добавить метод в ViewControllerA который вызывается, когда выполняется какой-либо segue, из-за этого нам нужно определить, какой вызов был вызван, а затем что-то сделать. В нашем примере мы проверим "showDetailSegue" и если это будет выполнено, мы передадим наше значение BOOL в ViewControllerB

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

    Если у вас есть свои взгляды, встроенные в контроллер навигации, вам нужно немного изменить метод выше на следующие

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

    Это установит isSomethingEnabled в ViewControllerB на значение BOOL YES .

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

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

Для этого мы сделаем ViewControllerA делегатом ViewControllerB . Это позволяет ViewControllerB отправлять сообщение обратно в ViewControllerA позволяя нам отправлять данные обратно.

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

  1. В ViewControllerB.h , ниже #import , но выше @interface вы указываете протокол.

    @class ViewControllerB;
    
    @protocol ViewControllerBDelegate <NSObject>
    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
    @end
    
  2. следующий еще в ViewControllerB.h вам нужно настроить свойство delegate и синтезировать в ViewControllerB.m

    @property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
    
  3. В ViewControllerB мы вызываем сообщение в ViewControllerB когда мы выходим на контроллер вида.

    NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
    [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
    
  4. Это для ViewControllerB . Теперь в ViewControllerA.h скажите ViewControllerA импортировать ViewControllerB и соответствовать его протоколу.

    #import "ViewControllerB.h"
    
    @interface ViewControllerA : UIViewController <ViewControllerBDelegate>
    
  5. В ViewControllerA.m реализуем следующий метод из нашего протокола

    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
    {
        NSLog(@"This was returned from ViewControllerB %@",item);
    }
    
  6. Прежде чем нажать viewControllerB на стек навигации, нам нужно указать ViewControllerB что ViewControllerA является его делегатом, иначе мы получим ошибку.

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

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

  1. Использование делегирования для связи с другими контроллерами представления в Руководстве по программированию контроллера просмотра
  2. Шаблон делегирования

Центр NSNotification Это другой способ передачи данных.

// add observer in controller(s) where you want to receive data
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDeepLinking:) name:@"handleDeepLinking" object:nil];

-(void) handleDeepLinking:(NSNotification *) notification {
    id someObject = notification.object // some custom object that was passed with notification fire.
}

// post notification
id someObject;
[NSNotificationCenter.defaultCenter postNotificationName:@"handleDeepLinking" object:someObject];

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

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

В этом примере данные передаются от контроллера B к контроллеру 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];
}

Другой рабочий пример для блоков


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

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

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

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


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;

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

Например:

Значение строки FirstViewController as

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

В настоящее время я вношу свой вклад в решение этой проблемы с открытым исходным кодом с помощью проекта 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 и передать данные, вы создаете новое намерение и добавляете данные в свой словарь (savedInstanceState). Затем просто установите текущее намерение завода:

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

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


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

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


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

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

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

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


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

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

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

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


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

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

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


если вы хотите передать данные из ViewControlerOne в ViewControllerTwo попробовать эти ..

делайте это в 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);
}

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


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

Другим решением является использование singleton class pattern, инициализирующее его один раз и использование его во всем приложении.


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

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

Общие данные

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

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

Поскольку подготовка к segue является наиболее распространенной, вот пример:

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

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

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

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

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

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

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

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

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

let notebookName = note.notebook.name

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


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

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

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

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

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

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

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

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

}

4 строки кода внутри метода, и все готово.





uiviewcontroller