Должен ли IBOutlet быть имуществом и синтезироваться?
В большинстве примеров я вижу следующую настройку 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 как общедоступные свойства, поскольку они не используются как таковые, они используются только в реализации контроллера. Определение его в трех местах без реальной потребности не поражает меня, как очень СУХОЙ (не повторяйте себя).
Ответы
Ответ 1
В Mac OS X IBOutlets подключаются следующим образом:
- Ищите метод с именем set <OutletName> :. Если он существует, вызовите его.
- Если никакого метода не существует, найдите переменную экземпляра с именем <OutletName> , установите ее без сохранения.
В iPhone OS, IBOutlets подключаются следующим образом:
- call [object setValue: outletValue forKey: @ "<OutletName> " ]
Поведение заданного значения для ключа состоит в том, чтобы сделать что-то вроде этого:
- Ищите метод с именем set <OutletName> :. Если он существует, вызовите его.
- Если никакого метода не существует, найдите переменную экземпляра с именем <OutletName> , установите ее и сохранить.
Если вы используете свойство, вы попадете в "Ищите метод с именем set <OutletName> :..." на обеих платформах. Если вы просто используете переменную экземпляра, то у вас будет другое поведение сохранения/выпуска в ОС Mac OS X VS iPhone. Нет ничего плохого в использовании переменной экземпляра, вам просто нужно иметь дело с этой разницей в поведении при переходе между платформами.
Вот ссылка на полную документацию только по этой теме.
http://developer.apple.com/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html#//apple_ref/doc/uid/10000051i-CH4-SW6
Ответ 2
В Mac OS X IBOutlets не сохраняются по умолчанию. Это противоположно поведению на iPhone OS: на iPhone OS, если вы не объявляете свойство, оно сохраняется, и вы должны освободить это свойство в методе dealloc
. Кроме того, 64-битная среда выполнения может синтезировать переменные экземпляра, используя объявления свойств. Это означает, что когда-нибудь переменные экземпляра (с помощью IBOutlet
) могут быть опущены.
По этим причинам более однородно и совместимо создавать всегда свойство и использовать IBOutlet
только в свойстве. К сожалению, это также более подробно.
В первом примере вам всегда нужно выпустить розетку в методе dealloc
. В вашем втором примере вы должны выпустить выход только с iPhone OS.
Ответ 3
Конечный результат точно такой же, но вы должны помнить несколько вещей:
-
При использовании полей экземпляра в качестве выходов вы НЕ должны выпускать их в dealloc.
-
При использовании свойств, имеющих атрибут (сохранить), вы должны освободить свойство в dealloc (используя self.property=nil
или освободив переменную резервной копии). Это делает его намного более прозрачным в отношении того, что происходит.
На самом деле все сводится к одному и тому же старому правилу: "Ты выпустишь то, что ты выделишь/сохранишь". Поэтому, если вы используете поле экземпляра в качестве выхода, вы не выделяете/не сохраняете его, поэтому его не следует отпускать.
Ответ 4
Возможно, эти примеры используют сохранение, потому что образец кода программно выделяет и инициализирует UILabel, а затем добавляет его в UIView. Это случай для многих примеров, так как обучение использованию Interface Builder часто не является их точкой.
Второй пример (без свойства и без синтеза) с IBOutlet используется, когда разработчик "назначает" UILabel (Button, View и т.д.) в построителе интерфейса - перетаскивая IBOulet в Label или другой компонент View, На мой взгляд, предыдущее действие перетаскивания (Label on View) также добавляет subview, Label to View и т.д. Ярлык сохранен в представлении; Вид сохраняется в окне; Окно сохраняется владельцем файла. Владелец файла обычно является вашим Документом, который загружается в основном.
Вы заметите, что при выполнении вашей программы (добавив awakeFromNib
- (void)awakeFromNib
{
[fooLabel blahblah];
}
что fooLabel уже имеет адрес памяти.
Это потому, что Label была инициализирована из набора файлов (файл nib), используя не init, а initWithCoder. Что по существу десериализует поток подачи объекта, а затем устанавливает переменную IBOutlet. (Мы все еще говорим о методе IBOutlet).
Также обратите внимание, что вышеупомянутый метод iOS использует метод Key Value
call [object setValue:outletValue forKey:@"<OutletName>"]
который является наблюдаемым/наблюдаемым образцом. Этот шаблон требует привязки объекта 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, а также его подпункты и т.д. И впоследствии десериализуется... на следующем сеансе open (напротив, или скрытый.)