Передача данных между контроллерами представления - PullRequest
1304 голосов
/ 06 марта 2011

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

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

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

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

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

Ответы [ 42 ]

28 голосов
/ 18 ноября 2013

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

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];
 }
26 голосов
/ 27 июля 2013

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

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

22 голосов
/ 01 сентября 2014

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

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

20 голосов
/ 29 июля 2012

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

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

Теперь в viewControllerB.h

@interface viewControllerB : UIViewController {

  NSString *string;
  NSArray *array;

}

- (id)initWithArray:(NSArray)a andString:(NSString)s;

В viewControllerB.m

#import "viewControllerB.h"

@implementation viewControllerB

- (id)initWithArray:(NSArray)a andString:(NSString)s {

   array = [[NSArray alloc] init];
   array = a;

   string = [[NSString alloc] init];
   string = s;

}

В viewControllerA.m

#import "viewControllerA.h"
#import "viewControllerB.h"

@implementation viewControllerA

- (void)someMethod {

  someArray = [NSArray arrayWithObjects:@"One", @"Two", @"Three", nil];
  someString = [NSString stringWithFormat:@"Hahahahaha"];

  viewControllerB *vc = [[viewControllerB alloc] initWithArray:someArray andString:someString];

  [self.navigationController pushViewController:vc animated:YES];
  [vc release];

}

Таким образом, вы можете передавать данные из viewControllerA в viewControllerB без установки какого-либо делегата.;)

19 голосов
/ 23 мая 2012

Это очень старый ответ, и это анти образец, пожалуйста, используйте делегатов. Не используйте этот подход !!

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

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

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

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

17 голосов
/ 23 октября 2013

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

Например:

Значение FirstViewController String как

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 ];
17 голосов
/ 16 сентября 2014

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

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

17 голосов
/ 25 августа 2015

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

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

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

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

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

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


Very simple view layout.  Note : No navigation controller


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


The Sender


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


The Receiver


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


The Segue Identifier


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

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

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

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

    }

}

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

import UIKit

class ViewControllerReceiver: UIViewController {

    //Basic empty variable waiting for you to pass in your fantastic favorite movie.
    var yourFavMovie = ""

    override func viewDidLoad() {
        super.viewDidLoad()

        //And now we can view it in the console.
        println("The Movie is \(self.yourFavMovie)")

    }   
}

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

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

Ghost Busters is a classic folks.

17 голосов
/ 06 марта 2011

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

14 голосов
/ 02 января 2014

Создайте свойство на следующем 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];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...