Доступ к другому контроллеру представления

Я пытаюсь получить доступ к некоторым вещам из другого контроллера просмотра (iOS).

У меня есть ViewController.h:

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <UITextFieldDelegate> {
    ...
}

@end

ViewController.m:

#import "ViewController.h"
#import "ViewController2.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
   ViewController2.someVar = @"cakes"; // this is where I'm trying to set something in vc2
}

ViewController2.h:

#import <UIKit/UIKit.h>

@interface ViewController2 : UIViewController <UITableViewDataSource, UITableViewDelegate, UISearchDisplayDelegate>
{
   ...
}

@property (nonatomic, copy) NSString *someVar;

@end

ViewController2.m:

#import "ViewController2.h"

@interface ViewController2 ()

@end

@implementation ViewController2

@synthesize someVar;

etc.

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

Свойство «someVar» не найдено в объекте типа «ViewController2».

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


person Cake    schedule 12.01.2013    source источник


Ответы (2)


Вам нужно создать объект ViewControlle2 в файле Viewcontroller.m.

ViewController2 *myVC2 = [[ViewController2 alloc] initWithNibName:@"ViewController2" bundle:nil];
myVC2.someVar = @"cakes";
person JAA    schedule 12.01.2013
comment
Хорошо вроде работает. Когда я NSLog var в VC1, как myVC2.var, он показывает, и это здорово. Но когда я NSLog из VC2, он снова пуст! - person Cake; 12.01.2013
comment
@Cake, где ты это зарегистрировал в VC2? - person rdelmar; 12.01.2013
comment
просмотрDidLoad. Но я не понимаю, почему это имеет значение :/ - person Cake; 12.01.2013
comment
@Cake: Если вы зарегистрируете его в обоих местах, в каком порядке вы их увидите? И вы создаете свой ViewController2 в nib, в коде или в обоих? - person Peter Hosey; 13.01.2013
comment
вы должны регистрировать self.someVar, а не только someVar. - person JAA; 13.01.2013
comment
@JJSaccolo: поскольку Cake явно синтезирует свойство, переменная синтезированного экземпляра имеет то же имя. someVar и self.someVar действительно означают разные вещи, но в этом контексте (извлечение, а не присваивание) и без реализации переопределения -someVar они фактически эквивалентны. Доступ к свойству (self.someVar) был бы более правильным, но не решил бы проблему. - person Peter Hosey; 13.01.2013
comment
@PeterHosey да, правильно. Извините, я не увидел @synthesize. Итак, я думаю, что проблема в том, как вы (@Cake) создаете и показываете ViewController2. Вы должны показать объект myVC2 после его создания. Например, если вы используете UINavigationController, вы должны нажать myVC2 с помощью [self.navigationController pushViewController:myVC2];. - person JAA; 13.01.2013
comment
Не могу проверить заказ прямо сейчас, так как я не дома, но большую его часть я создал в конструкторе интерфейсов. И я думаю, что проблема действительно может быть в том, что нет связи между объектом VC2 и фактическим ViewController2, в который должны быть загружены данные. - person Cake; 13.01.2013
comment
@Cake: Если вы создали контроллер представления в наконечнике, то вы правы: создание его один раз в наконечнике и один раз в коде создаст два ViewController2. Скорее всего, вы захотите добавить розетку и соединить ее с той, что в наконечнике. - person Peter Hosey; 13.01.2013
comment
Хорошо, я пытаюсь создать IBOutlet для viewcontroller2 в viewcontroller, чтобы я мог получить к нему доступ. Я добавляю это в VC.h: IBOutlet ViewController2 *myVC2; Но я не могу связать это ни с чем в раскадровке - person Cake; 19.01.2013

Другой способ сделать это — использовать делегатов. Если вы создали ViewController1 в AppDelegate, вам также следует создать ViewController2 в AppDelegate или там, где вы когда-либо создавали свои ViewControllers. Затем вы ViewController1 отправите сообщение AppDelegate, чтобы получить данные от ViewController2 и наоборот. Это делает ViewController1 и ViewController2 больше не зависящими друг от друга.

Итак, в AppDelegate.h у нас будет что-то вроде этого

@interface AppDelegate : NSObject <MyViewControllerDelegate>

@property (nonatomic) ViewController1 *viewController1;
@property (nonatomic) ViewController2 *viewController2;

@end

Затем в обоих контроллерах представления вы можете добавить эту строку в .h

@property (nonatomic) id<MyViewControllerDelegate> delegate;

Это просто дает нам переменную для обращения к делегату из .m ViewController.

Вам также необходимо создать протокол MyViewControllerDelegate, поэтому в файле с именем MyViewControllerDelegate.h

@protocol MyViewControllerDelegate

- (ViewController1 *) viewController1;

- (ViewControlelr2 *) viewController2;

@end

Затем, когда вы создаете ViewControllers в AppDelegate.m, вы также должны установить AppDelegate в качестве делегата ViewController.

self.viewController1 = [[ViewController1 alloc] init];
self.viewController1.delegate = self;
self.viewController2 = [[ViewController2 alloc] init];
self.viewController2.delegate = self;

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

self.delegate.viewController2.someVar = @"Cakes";

Надеюсь, это не слишком затянуто.

person TheEnigma2112    schedule 12.01.2013
comment
Спасибо за этот ответ Энигма. Поскольку я еще не достиг продвинутого уровня в Cocoa, у меня есть несколько вопросов: - Является ли это лучшим способом решить эту проблему, используя класс делегата для управления обоими контроллерами представления? - Я не был уверен в определении «делегирования», поэтому я проверил описание Apple. Вот что там: в среде со сборкой мусора получатель поддерживает сильную ссылку на своего делегата. Википедия говорит: слабая ссылка — это ссылка, которая не защищает объект, на который ссылаются, от сбора сборщиком мусора. Разве это не 2 противоположных утверждения? Я потерялся :Р - person Cake; 13.01.2013
comment
В этом случае мы используем делегата в качестве источника данных, что немного отличается. В нижней части страницы разработчика Apple, об этом немного говорят. В нем также рассказывается о делегатах в целом, что может оказаться полезным. Я обычно заканчиваю тем, что использую их как интерфейсы в таком языке, как JAVA, поэтому контроллер представления делегирует тело одной из своих более общих функций своему делегату, а не определяет его сам. - person TheEnigma2112; 15.01.2013
comment
Насколько это хорошее решение, я почти всегда реализую его таким образом только потому, что оно отделяет контроллеры представления от данных. Поэтому, если вы удалите один из ваших контроллеров представления или радикально измените его позже в своем проекте, вам не нужно полностью менять способ хранения вашей информации, она просто живет в делегате и по-прежнему доступна для других контроллеров. - person TheEnigma2112; 15.01.2013
comment
Спасибо. А что касается вашего решения, как должен выглядеть MyViewControllerDelegate.h? Потому что - (ViewController1 *) viewController1; выдаст мне ошибку Отсутствует контекст для объявления метода. - person Cake; 19.01.2013
comment
Убедитесь, что вы указали @protocol и @end. Я думаю, это должно помочь. Также убедитесь, что вы включили заголовки для ваших классов в верхней части протокола. - person TheEnigma2112; 30.01.2013