Как написать собственный инициализатор, который предотвращает вызов viewDidLoad? - PullRequest
2 голосов
/ 23 октября 2011

Я хотел бы создать собственный метод init для UIViewController, но после копания в Интернете и, в частности, в SO, я запутался в назначенных инициализаторах.

У меня есть подкласс UIViewController с этими двумя инициализаторами:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
  self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
  if ( self ) {

  }
  return self;
}

- (id) initWithFilename:(NSString *)aFilename {
  self = [self initWithNibName:@"WallpaperDetailsViewController" bundle:nil];
  if ( self ) { 
    self.filename = aFilename;
  }
  return self;
}

Тогда у меня есть метод viewDidLoad, который настраивает представление в соответствии со свойством filename:

- (void)viewDidLoad {
  [super viewDidLoad];

  // Create a UIImageView to display the wallpaper
  self.wallpaper = [[UIImageView alloc] initWithImage:[UIImage imageNamed:self.filename]];
  // ...
}

В другом UIViewController я делаю следующий звонок:

WallpaperDetailsViewController *detailsViewController = [[WallpaperDetailsViewController alloc] initWithFilename:@"foobar.png"];
[[self navigationController] pushViewController:detailsViewController animated:YES];

В результате viewDidLoad вызывается как следствие [self initWithNibName:], который не инициализирует UIImageView, поскольку self.filename равен нулю.

Согласно другим вопросам и ответам SO, это должно быть ожидаемое поведение. Я не уверен в этом из-за моего собственного опыта в других проектах до iOS 5. Мой вопрос:

Как я могу убедиться, что viewDidLoad: - это вызов после initWithFilename:, а не между initWithFilename: и initWithNibNameOrNil:bundle:?

Если это невозможно, как я могу реализовать метод инициализатора, который получает пользовательские данные для создания и настройки представления?

Спасибо!

Ответы [ 4 ]

2 голосов
/ 23 октября 2011

Я нашел проблему.

WallpaperDetailsViewController не наследуется напрямую от UIViewController, но от другого пользовательского UIViewController, который я реализовал.

А в чем была проблема? То, что я инициализировал подпредставление в методе initWithNibName родителя, вместо того, чтобы следовать технике ленивой загрузки и делать это в viewDidLoad. Когда WallpaperDetailsViewController вызывал свой родительский инициализатор, это приводило в замешательство и заставляло viewDidLoad вести себя неправильно.

Решение? Я переместил каждую инициализацию подпредставления в родительском классе в метод viewDidLoad и сохранил мою первоначальную реализацию WallpaperDetailsViewController в неизменном виде. Теперь все работает как положено

Благодарю @Josh Caswell и @ logancautrell

1 голос
/ 23 октября 2011

Вам не нужна эта пустая реализация initWithNibName:bundle:.Кроме того, похоже, что ваш класс устанавливает свой инициализатор на initWithFilename: Если это так, initWithFilename: должен вызывать DI суперкласса:

- (id) initWithFilename:(NSString *)aFilename {
  // Call super's designated initializer
  self = [super initWithNibName:@"WallpaperDetailsViewController" 
                         bundle:nil];
  if ( self ) { 
    self.filename = aFilename;
  }
  return self;
}

Правило состоит в том, что все инициализаторы в пределах класс должен вызывать DI класса, а сам DI должен вызывать DI

* 1010 суперкласса. Из того, что вы опубликовали, не совсем понятно, почему loadView: вызывается до завершения инициализации.Комментарий Logancautrell, предлагающий установить точки останова в методах загрузки представлений, хорош.
0 голосов
/ 23 октября 2011

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

Синтаксис и инициализация точки Objective C

Во-вторых, вы также можете назначить изображение в инициализаторе.Таким образом, вы можете сделать что-то вроде

- (id) initWithFilename:(NSString *)aFilename {
   self = [self initWithNibName:@"WallpaperDetailsViewController" bundle:nil];
   if ( self ) { 
      filename = [aFilename retain];
      wallpaper = [[UIImageView alloc] initWithImage:[UIImage imageNamed:aFileName]];
   }
   return self;
}

. Это позволит вам настроить все в хорошем состоянии до вызова viewDidLoad.

Удачи!

0 голосов
/ 23 октября 2011

Почему бы вам не использовать пользовательский установщик для свойства имени файла, который инициализирует UIImage каждый раз, когда задается имя файла?

Или, альтернативно, установите UIImage из свойства filename в viewWillAppear: вместо viewDidLoad.

...