Должен ли IBOutlet быть собственностью и синтезироваться? - PullRequest
53 голосов
/ 03 августа 2009

В большинстве примеров я вижу следующую настройку IBOutlets:



(Example A)

FooController.h:

@interface FooController : UIViewController {
    UILabel *fooLabel;
}

@property (nonatomic, retain) IBOutlet UILabel *fooLabel;

@end

FooController.m:

@implementation FooController

@synthesize fooLabel;

@end

Но это также хорошо работает (обратите внимание: нет свойства и нет синтеза):



(Example B)

FooController.h:

@interface FooController : UIViewController {
    IBOutlet UILabel *fooLabel;
}

@end

FooController.m:

@implementation FooController

@end

Есть ли недостатки определения IBOutlets, как в примере B? Как утечки памяти? Кажется, работает нормально, и я предпочитаю не выставлять IBOutlets как открытые свойства, так как они не используются как таковые, они используются только в реализации контроллера. Определение его в трех местах без реальной необходимости не делает меня СУХИМЫМ (не повторяйте себя).

Ответы [ 4 ]

96 голосов
/ 06 августа 2009

В Mac OS X IBOutlets подключены так:

  1. Найдите метод с именем set :. Если он существует, позвоните.
  2. Если метода не существует, найдите переменную экземпляра с именем , установите ее без сохранения .

В iPhone OS IBOutlets подключены так:

  1. call [object setValue: outletValue forKey: @ ""]

Поведение заданного значения для ключа заключается в следующем:

  1. Найдите метод с именем set :. Если он существует, позвоните.
  2. Если метода не существует, найдите переменную экземпляра с именем , установите ее и сохраните it.

Если вы используете свойство, вы попадете в " Ищите метод с именем set : ... " на обеих платформах. Если вы просто используете переменную экземпляра, то у вас будет другое поведение сохранения / выпуска в Mac OS X VS iPhone OS. Нет ничего плохого в использовании переменной экземпляра, вам просто нужно иметь дело с этой разницей в поведении при переключении между платформами.

Вот ссылка на полную документацию только по этой теме. https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html#//apple_ref/doc/uid/10000051i-CH4-SW6

12 голосов
/ 19 декабря 2009

В Mac OS X IBOutlets по умолчанию не сохраняются. Это противоположно поведению в iPhone OS: в iPhone OS, если вы не объявляете свойство, оно сохраняется и вы должны освободить это свойство в методе dealloc. Кроме того, 64-разрядная среда выполнения может синтезировать переменные экземпляра с помощью объявлений свойств. Это означает, что когда-нибудь переменные экземпляра (с IBOutlet) могут быть опущены.

По этим причинам более однородно и совместимо всегда создавать свойство и использовать IBOutlet только в свойстве. К сожалению, это также более многословно.

В первом примере вы всегда должны разблокировать выход в методе dealloc. Во втором примере вы должны выпускать розетку только с iPhone OS.

4 голосов
/ 03 августа 2009

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

  • При использовании полей экземпляра в качестве торговых точек НЕ ДОЛЖНЫ освобождать их в dealloc .

  • При использовании свойств, имеющих атрибут (retain), вы должны разблокировать свойство в dealloc (используя self.property=nil или выпуская переменную поддержки). Это делает его более прозрачным в отношении того, что происходит.

На самом деле все сводится к одному и тому же старому правилу: « отпусти то, что ты выделил / сохранил ». Поэтому, если вы используете поле экземпляра в качестве выходного, вы не выделяете и не сохраняете его, поэтому не следует его освобождать.

1 голос
/ 10 апреля 2013

Возможно, что в этих примерах используется сохранение, поскольку образец кода программно выделяет и инициализирует UILabel, а затем добавляет его в UIView. Это относится ко многим примерам, поскольку изучение того, как использовать Интерфейсный Разработчик, часто не является их целью.

Второй пример (без свойства и без синтеза) с IBOutlet используется, когда разработчик «назначает» UILabel (Button, View и т. Д.) В Интерфейсном Разработчике - перетаскивая IBOulet в Label или другой компонент View. , По моему мнению, предыдущее действие перетаскивания (Метка на представление) также добавляет подпредставление, Метку к представлению - и так далее. Метка сохраняется в представлении; Вид сохраняется в Window; Окно сохраняется владельцем файла. Владельцем файла обычно является ваш Документ, который загружается в main.

Вы заметите, что когда вы проходите через свою программу (добавив awakeFromNib

- (void)awakeFromNib
{
    [fooLabel blahblah];
}

что fooLabel уже имеет адрес памяти.

Это потому, что метка была инициализирована из комплекта файлов (nib-файла) с использованием не init, а initWithCoder. По существу десериализует файловый поток в объект, а затем устанавливает переменную IBOutlet. (Мы все еще говорим о методе IBOutlet).

Также обратите внимание, что вышеупомянутый метод iOS использует метод Key Value

  call [object setValue:outletValue forKey:@"<OutletName>"]

который является паттерном Observer / Observable. Этот шаблон требует, чтобы объект Observable ссылался на каждого наблюдателя в наборе / массиве. Изменение значения будет повторять Set / Array и одинаково обновлять все Наблюдатели. Этот Набор уже сохранит каждого Обозревателя, поэтому в iOS его нет.

Далее, а остальное - спекуляция.

Похоже, что когда вы используете Interface Builder, тогда

 @property (nonatomic, retain) IBOutlet UILabel *fooLabel;

возможно следует изменить на

@property (nonatomic, weak) IBOutlet UILabel *fooLabel;

или @property (nonatomic, assign) IBOutlet UILabel * fooLabel;

И тогда его не нужно освобождать в методе dealloc. Кроме того, он будет соответствовать требованиям OSX и iOS.

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

Тем не менее, это может не иметь значения, если представление сохраняется в течение всей жизни вашей программы. Принимая во внимание, что метка в модальном диалоговом окне (открыть, закрыть, открыть, закрыть) может фактически иметь избыточное удержание и утечку за цикл. И это потому, что (снова предположения) каждое закрытое диалоговое окно сериализуется в файловую систему и, таким образом, сохраняет x, y позицию и размер, а также свои подпредставления и т. Д. И впоследствии десериализуется ... на следующем открытом сеансе (в противоположность минимизировать или скрытый.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...