Установка для ненулевого объекта слабого свойства возвращает ноль во второй раз, но не первый - PullRequest
0 голосов
/ 12 июня 2018

Я работаю над унаследованным приложением, которое я рефакторинг, и есть странное поведение, я не понимаю.

Есть UIViewController с именем CANoContentViewController, и он имеет простойкод инициализации из Nib:

+ (CANoContentViewController *)instantiateController {
   CANoContentViewController *vc = [[CANoContentViewController alloc] initWithNibName:@"CANoContentViewController" bundle:[NSBundle mainBundle]];
   DLog(@"Created CANoContentViewController %@", vc);
   return vc;
}

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

@property (nonatomic, weak) UIViewController *noContentViewController;

-(void)showOrDeleteNoContentIfNeeded{
   if([self.proposals count] <= 0) { // Show No Content VC
       self.noContentViewController = [CANoContentViewController instantiateController];
       DLog(@"Set CANoContentViewController %@", self.noContentViewController);
       self.noContentViewController.view.frame = self.view.bounds;
       [self addChildViewController:self.noContentViewController];
       [self.view addSubview:self.noContentViewController.view];
       [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
   } else {
       [self.noContentViewController.view removeFromSuperview];
       [self.noContentViewController removeFromParentViewController];
       [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine];
   }
}

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

2018-06-12 00:58:29.303276+0200 Base[11828:838463] +[CANoContentViewController instantiateController](0x105cc6688) Created CANoContentViewController <CANoContentViewController: 0x7fc350e101f0>
2018-06-12 00:58:29.303517+0200 Base[11828:838463] -[CAProposalsViewController showOrDeleteNoContentIfNeeded](0x7fc35106b200) Set CANoContentViewController <CANoContentViewController: 0x7fc350e101f0>

Как вы можетевидите, созданный контроллер установлен правильно в свойстве.

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

2018-06-12 00:58:31.379708+0200 Base[11828:838463] +[CANoContentViewController instantiateController](0x105cc6688) Created CANoContentViewController <CANoContentViewController: 0x7fc350c8bca0>
2018-06-12 00:58:31.380275+0200 Base[11828:838463] -[CAProposalsViewController showOrDeleteNoContentIfNeeded](0x7fc35181f200) Set CANoContentViewController (null)

Итак, приложение вылетает, потому что оно пытается установить объект nil в методе addChildViewController.

Всем известно, почему второйвремя, когда эта строка не работает и свойство nil?

self.noContentViewController = [CANoContentViewController instantiateController];

Я проверил, что когда я изменяю свойство на strong, все прекрасно работает.Но я не могу понять, почему это происходит, потому что каждый раз, когда CANoContentViewController создается из нового родительского контроллера представления, свойство self.noContentViewController которого должно отличаться от предыдущего.

Ответы [ 2 ]

0 голосов
/ 12 июня 2018

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

Например, установите:

@property (nonatomic, strong) UIViewController *noContentViewController

Вместо:

@property (nonatomic, weak) UIViewController *noContentViewController
0 голосов
/ 12 июня 2018

После выполнения:

self.noContentViewController = [CANoContentViewController instantiateController];

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

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

-(void)showOrDeleteNoContentIfNeeded{
   if([self.proposals count] <= 0) { // Show No Content VC
       CANoContentViewController *controller = [CANoContentViewController instantiateController];
       self.noContentViewController = controller;
       DLog(@"Set CANoContentViewController %@", self.noContentViewController);
       self.noContentViewController.view.frame = self.view.bounds;
       [self addChildViewController:self.noContentViewController];
       [self.view addSubview:self.noContentViewController.view];
       [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
   } else {
       [self.noContentViewController.view removeFromSuperview];
       [self.noContentViewController removeFromParentViewController];
       [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine];
   }
}

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

...