Свойства IBOutlet не обновляются при использовании метода prepareForSegue

У меня возникает проблема передачи значения для свойства IBOutlet для destinationViewController, но он отлично работает на обычном свойстве, см. Код ниже

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:@"NewsCellToDetail"]) { testViewController *viewController = segue.destinationViewController; viewController.titleLabel.text = @"test"; // set the IBOutlet label text to something NSLog(@"%@",viewController.titleLabel.text); // this will output to nil viewController.textTest = @"testing2"; // set the property to something NSLog(@"%@", viewController.textTest) // this will output the string testing2 } 

Это код для файла заголовка testviewcontroller.h

 #import  @interface NewsDetailViewController : UIViewController @property (strong, nonatomic) IBOutlet UILabel *titleLabel; @property (strong, nonatomic) NSString *textTest; @end 

Я уже синтезирую и свойство.

Спасибо за помощь.

Недавно у меня была такая же проблема. Но когда я отлаживаю его шаг за шагом, я нахожу возможную причину. (Прошу прощения, я тоже новичок в Objective C, поэтому мое следующее объяснение может быть не таким точным и профессиональным … Мой предыдущий опыт – это в основном веб-разработка.)

Если вы установили точку останова сразу после строки, которую вы вызываете

testViewController *viewController = segue.destinationViewController;

при создании и запуске проекта вы обнаружите, что свойство UITextField в destinationViewController не назначено и не инициировано (память 0x0) в точке останова. Между тем свойство NSString уже выделено и инициализировано (поэтому вы можете установить его значение).

Я думаю, вероятно, UITextfield – дочернее представление, поэтому оно инициируется только тогда, когда инициируется его родительское представление (представление места назначения). Но NSString – это свойство, которое не связано с каким-либо видом, поэтому оно назначается и инициируется с помощью controllerа представления, который его объявляет.

Когда я еще раз проведу это, я нахожу очень интересную вещь: второе представление загружается во время - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender . Я делаю тестовый код, как показано ниже:

В первом представлении управляющий файл .m:

 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { NSLog(@"1. %@, %@",[segue identifier],segue.destinationViewController); Scene2Controller *scene2ViewController = [segue destinationViewController]; [txtScene2 resignFirstResponder]; NSLog(@"2. scene2ViewController: %@", scene2ViewController); NSLog(@"3. txtScene1: %@; passValue: %@", [scene2ViewController txtScene1], scene2ViewController.passValue); NSLog(@"4. View2: %@; passValue: %@", [scene2ViewController view], scene2ViewController.passValue); NSLog(@"5. txtScene1: %@; passValue: %@", [scene2ViewController txtScene1], scene2ViewController.passValue); //txtScene1 is the UITextfield property I declared in the second view controller //txtScene2 is the UITextfield property I declared in the first view controller //passValue is the NSString property I declared in the second view controller } 

Во втором представлении файл .m-файла:

 - (void)viewDidLoad { NSLog(@"6. txtScene1: %@; passValue: %@", txtScene1,passValue); [super viewDidLoad]; } 

Заметил, что перед сообщениями NSLog я добавляю порядковые номера. Я обнаружил, что конечная последовательность результатов журнала была 1,2,3,6,4,5, а не 1,2,3,4,5,6. И в журнале 3 результат txtScene1 был нулевым (не инициированным), но после log 4 (второе представление было загружено), в журнале 5 txtScene1 не был нулевым и был инициирован. Это показало, что второе представление было загружено во время выполнения сеанса. Поэтому я предполагаю, что во время перехода segue последовательность инициализации объектов второго представления controllerа будет: второй controller представления -> свойство NSString (и другие подобные свойства, такие как NSInteger и т. Д.) -> второй вид -> свойство UITextfield (и другие свойства subview).

Поэтому я изменил свои коды в первом файле .m-файла диспетчера представлений:

 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { Scene2Controller *scene2ViewController = [segue destinationViewController]; [txtScene2 resignFirstResponder]; if ([scene2ViewController view]) { if ([txtScene2.text isEqualToString:@""]) { scene2ViewController.txtScene1.text = @"No Value"; } else { scene2ViewController.txtScene1.text = txtScene2.text; } } } 

Этот код работает отлично, и значение передается непосредственно в свойство UITextfield во втором представлении.

Надежда выше объяснения ясна и полезна для вас.

Я немного поздно прихожу к этому ответу, но недавно я столкнулся с этой проблемой, и причина этого была бы очевидна, если бы мы все еще создавали вещи вручную, а не позволяли раскадровке справляться с этим. Так случается так, что вы никогда не манипулируете представлением, когда вручную создаете контрольные controllerы представлений: целевой элемент segue destinationViewController не вызвал loadView: все же, который в раскадровке проходит через десериализацию всех объектов вида из связанного nib.

Очень простой способ увидеть это в действии:

  1. Создайте две сцены ViewController (ViewController1 и ViewController2)
  2. Добавить кнопку в ViewController1 и выполнить действие от кнопки до ViewController2
  3. Добавьте subview в ViewControler2 и IBOutlet к этому подвью
  4. В prepareForSegue: из ViewController1, попробуйте ссылаться на эту точку доступа для просмотра ViewController2 – вы обнаружите, что она равна нулю, а ее frameworks / границы равны нулю.

Это связано с тем, что представление ViewController2 еще не добавлено для просмотра стека, но controller был инициализирован. Таким образом, вы никогда не должны пытаться манипулировать представлением ViewController2 в файле prepareForSegue: иначе вы ничего не потеряете. Ссылка на Руководство по программированию на ViewController от Apple для жизненного цикла: https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html

Принятый здесь ответ заставляет loadView запускаться в prepareForSegue: путем доступа к свойству .view адресата, поэтому вещи выходят из строя и будут иметь неизвестные / трудно воспроизвести результаты, если вы пытаетесь сделать какие-либо действия просматривать обработку в viewDidLoad для учета любых загрузок данных, потому что без представления представления, загруженного в viewStack, любые ссылки на родительское представление для ссылок на кадры будут равны нулю.

TL; DR; – Если у вас есть данные, которые необходимо передать, как в случае с OP, установите его с использованием общедоступных свойств в целевом объекте, а затем в viewDidLoad controllerа назначения загрузите эти данные в подзадачи представления.

Редактировать:

Аналогичный вопрос здесь – IBOutlet – это нуль внутри пользовательского UIView (с помощью STORYBOARD)

Вы также можете использовать viewDidLayoutSubviews: для любых манипуляций с subview.

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

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

Как правило, в FirstViewController.m:

 -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([[segue identifier] isEqualToString:@"segueName"]) { SecondViewController *destinationVC = [segue destinationViewController]; destinationVC.test = @"Test string"; } } 

И в файле SecondViewController.m

  -(void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. self.testLabel.text = self.test; } 

secondViewController = destinationViewController;

Другой способ – объявить делегатский метод на secondViewController. on secondViewController:

 @protocol SecondViewControllerDelegate  @optional - (void) InitilizeSecondViewController:(SecondViewController*) listVC; @end 

Реализованный в firstViewController, в этом методе используется свойство подclassа вида secondViewController. on firstViewController:

 - (void) InitilizeSecondViewController:(SecondViewController*) listVC { listVC.btn0.textLabel.text = @"Aha"; } 

Инициализировать firstViewController как делегат второгоViewController в prepareForSegue. on firstViewController:

 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { SecondViewController* list = segue.destinationViewController; list.delegate = self; } 

вызовите этот метод делегата после метода viewDidLoad в secondViewController. on secondViewController:

 - (void)viewDidLoad { [super viewDidLoad]; [delegate InitilizeSecondViewController:self]; } 
Interesting Posts

Какую команду я могу использовать для рекурсивного переименования или перемещения файла в Windows?

Имитировать низкий уровень заряда аккумулятора и низкую память в Android

Ошибка «произошла ошибка чтения диска» в Windows XP

Как обеспечить загрузку файла из компонента поддержки JSF?

Доверенные сертификаты Root регулярно исчезают в Windows 7

Выполнение ярлыка из командной строки без расширения .lnk (Windows)

Странное поведение при печати массива в C?

Windows 10 не будет спать, даже после переопределения драйверов

Laravel 4: как запустить сырой SQL?

Веб-сайты не загружаются в Firefox, но работают в Chrome и Internet Explorer

Разделить список на несколько списков с фиксированным числом элементов в java 8

Что мне нужно учитывать при покупке оборудования для удовлетворения моих потребностей?

Стандартная альтернатива трюку ## __ VA_ARGS__ GCC?

jQuery draggable + droppable: как привязать упавший элемент к включенному элементу

Как импортировать закладки Opera в Chrome?

Давайте будем гением компьютера.