Я разрабатываю исключительно для iOS 5, используя ARC. Если IBOutlet
- UIView
(и подклассы) - strong
или weak
?
Следующее:
@property (nonatomic, weak) IBOutlet UIButton *button;
Избавьтесь от всего этого:
- (void)viewDidUnload
{
// ...
self.button = nil;
// ...
}
Есть ли проблемы с этим? Шаблоны используют strong
, а также автоматически создаваемые свойства, созданные при непосредственном подключении к заголовку из редактора "Interface Builder", но почему? UIViewController
уже имеет ссылку strong
на свой view
, который сохраняет свои поднастройки.
Текущая рекомендуемая передовая практика от Apple заключается в том, чтобы IBOutlets были сильными, если только слабый не нужен, чтобы избежать цикла сохранения. Как упоминал Йоханнес, это было прокомментировано в разделе "Реализация интерфейса пользовательского интерфейса в интерфейсе" от WWDC 2015, где Apple Engineer сказал:
И последний параметр, который я хочу указать, - это тип хранилища, который может либо быть сильным или слабым. В общем, вы должны сделать свой выход сильный, особенно если вы подключаете розетку к подсмотру или к ограничение, которое не всегда будет сохранено в представлении иерархия. Единственный раз, когда вам действительно нужно сделать выход слабым, если у вас есть пользовательский вид, который ссылается на что-то резервное копирование представления иерархии и вообще не рекомендуется.
Я спросил об этом в Твиттере инженера команды IB, и он подтвердил, что сильный должен быть по умолчанию и что документы разработчика обновляются.
https://twitter.com/_danielhall/status/620716996326350848 https://twitter.com/_danielhall/status/620717252216623104
ПРЕДУПРЕЖДЕНИЕ, НАНЕСЕННЫЙ ОТВЕТ: этот ответ не обновляется в соответствии с WWDC 2015, для правильного ответа см. принятый ответ (Daniel Hall) выше. Этот ответ останется для записи.
Обобщены из библиотека разработчиков:
С практической точки зрения, в iOS и OS X выходы должны быть определены как объявленные свойства. Розетки, как правило, должны быть слабыми, за исключением тех, которые принадлежат файловому владельцу, для объектов верхнего уровня в файле nib (или в iOS, сценае раскадровки), который должен быть сильным. Таким образом, создаваемые вами ролики обычно будут слабыми по умолчанию, потому что:
Розетки, которые вы создаете, например, в виде представлений в представлении диспетчера представлений или окне оконных контроллеров, представляют собой произвольные ссылки между объектами, которые не подразумевают право собственности.
Сильные розетки часто задаются классами framework (например, UIViewControllers view outlet или NSWindowControllers).
@property (weak) IBOutlet MyView *viewContainerSubview; @property (strong) IBOutlet MyOtherClass *topLevelObject;
В то время как в документации рекомендуется использовать weak
для свойств для subviews, так как iOS 6, похоже, будет использовать strong
(классификатор прав собственности по умолчанию).. Это вызвано изменением UIViewController
, что представления больше не выгружаются.
Тем не менее, я разорван между использованием
@property (nonatomic, weak) IBOutlet UIButton *button;
и
@property (nonatomic) IBOutlet UIButton *button;
в iOS 6 и после:
Использование weak
четко указывает, что контроллер не хочет владеть кнопкой.
Но опускать weak
не вредит в iOS 6 без разгрузки изображения и короче. Некоторые могут указать, что это также быстрее, но мне еще предстоит встретить приложение, которое слишком медленно из-за weak
IBOutlet
s.
Не использовать weak
можно воспринимать как ошибку.
Итог: с iOS 6 мы больше не можем ошибаться, пока мы не используем разгрузку вида. Время вечеринки.;)
nil
вручную.
weak
это немного дешевле в ARM64: D
Я не вижу никаких проблем с этим. Pre-ARC, я всегда делал свои IBOutlets assign
, так как они уже сохранены их супервизорами. Если вы сделаете их weak
, вы не должны будете их выводить в viewDidUnload, как вы указываете.
Одно предупреждение: вы можете поддерживать iOS 4.x в проекте ARC, но если вы это сделаете, вы не можете использовать weak
, поэтому вам нужно будет сделать их assign
, и в этом случае вы по-прежнему хотите использовать ссылку в viewDidUnload
, чтобы избежать оборванного указателя. Вот пример ошибки оборванного указателя, с которой я столкнулся:
UIViewController имеет UITextField для почтового индекса. Он использует CLLocationManager для изменения геокодирования местоположения пользователя и установки почтового индекса. Здесь обратный вызов делегата:
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
Class geocoderClass = NSClassFromString(@"CLGeocoder");
if (geocoderClass && IsEmpty(self.zip.text)) {
id geocoder = [[geocoderClass alloc] init];
[geocoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, NSError *error) {
if (self.zip && IsEmpty(self.zip.text)) {
self.zip.text = [[placemarks objectAtIndex:0] postalCode];
}
}];
}
[self.locationManager stopUpdatingLocation];
}
Я обнаружил, что если я отклонил это представление в нужное время и не сделал nil self.zip в viewDidUnload
, обратный вызов делегата мог бы вызвать исключение плохого доступа в self.zip.text.
weak
свойства не нужно обнулять в viewDidUnload
. Но почему шаблон Apple для создания торговых точек включает [self setMySubview:nil]
?
В iOS-разработке загрузка NIB немного отличается от разработки Mac.
В Mac-разработке IBOutlet обычно является слабой ссылкой: если у вас есть подкласс NSViewController, то будет сохранено только представление верхнего уровня, и когда вы отключите контроллер, все его подпункты и выходы будут освобождены автоматически.
UiViewController использует Key Value Coding для установки розеток с использованием сильных ссылок. Поэтому, когда вы отключите свой UIViewController, верхний вид автоматически будет освобожден, но вы также должны освободить все его выходы в методе dealloc.
В этом сообщении от Big Nerd Ranch, они охватывают эту тему, а также объясняют, почему использование сильной ссылки в IBOutlet не является хорошим выбором (даже если это рекомендуется Apple в этом случае).
Одна вещь, которую я хочу отметить здесь, и это, несмотря на то, что инженеры Apple заявили в своем собственном видео WWDC 2015:
https://developer.apple.com/videos/play/wwdc2015/407/
Apple постоянно меняет свое мнение по этому вопросу, что говорит нам о том, что на этот вопрос нет единого правильного ответа. Чтобы показать, что даже инженеры Apple разделены по этому вопросу, взгляните на Apple в последнее время пример кода, и вы увидите, что некоторые люди используют слабый, а некоторые нет.
В этом примере Apple PayPack используется слабый: https://developer.apple.com/library/ios/samplecode/Emporium/Listings/Emporium_ProductTableViewController_swift.html#//apple_ref/doc/uid/TP40016175-Emporium_ProductTableViewController_swift-DontLinkElementID_8
Как и в примере с изображением в картинке: https://developer.apple.com/library/ios/samplecode/AVFoundationPiPPlayer/Listings/AVFoundationPiPPlayer_PlayerViewController_swift.html#//apple_ref/doc/uid/TP40016166-AVFoundationPiPPlayer_PlayerViewController_swift-DontLinkElementID_4
Как и пример Листера: https://developer.apple.com/library/ios/samplecode/Lister/Listings/Lister_ListCell_swift.html#//apple_ref/doc/uid/TP40014701-Lister_ListCell_swift-DontLinkElementID_57
Как и пример Core Location: https://developer.apple.com/library/ios/samplecode/PotLoc/Listings/Potloc_PotlocViewController_swift.html#//apple_ref/doc/uid/TP40016176-Potloc_PotlocViewController_swift-DontLinkElementID_6
Как и пример предварительного просмотра контроллера: https://developer.apple.com/library/ios/samplecode/ViewControllerPreviews/Listings/Projects_PreviewUsingDelegate_PreviewUsingDelegate_DetailViewController_swift.html#//apple_ref/doc/uid/TP40016546-Projects_PreviewUsingDelegate_PreviewUsingDelegate_DetailViewController_swift-DontLinkElementID_5
Все они полностью обновлены для iOS 9, и все используют слабые розетки. Из этого мы узнаем, что А. Проблема не такая простая, как некоторые люди делают это. B. Apple неоднократно передумала, и C. Вы можете использовать то, что делает вас счастливым:)
Особая благодарность Полю Хадсону (автор www.hackingwithsift.com), который дал мне разъяснения и ссылки на этот ответ.
Надеюсь, это немного улучшит тему!
Позаботьтесь.
IBOutlet
должен быть сильным, по соображениям производительности. См. Справочник раскадровки, Сильный IBOutlet, Сцена Dock в iOS 9
Как поясняется в этом параграфе, выходы в подпункты представления просмотр контроллеров может быть слабым, поскольку эти подзадачи уже принадлежащий объекту верхнего уровня файла nib. Однако, когда выход определяется как слабый указатель, и указатель установлен, ARC вызывает функция выполнения:
id objc_storeWeak(id *object, id value);
Это добавляет указатель (объект) в таблицу, используя значение объекта в качестве ключа. Эта таблица называемый слабым столом. ARC использует эту таблицу для хранения всех слабые указатели на ваше приложение. Теперь, когда значение объекта deallocated, ARC будет перебирать слабую таблицу и устанавливать слабые ссылка на ноль. Альтернативно, ARC может вызывать:
void objc_destroyWeak(id * object)
Затем объект незарегистрированный и objc_destroyWeak снова вызывает:
objc_storeWeak(id *object, nil)
Этот бухгалтерский учет со слабым эталоном может занять 2-3 раза дольше сильный ссылка. Таким образом, слабая ссылка вводит накладные расходы для который можно избежать, просто определяя выходные точки как сильные.
Как и в Xcode 7, предлагается strong
Если вы смотрите сеанс WWDC 2015 407 Внедрение дизайна пользовательского интерфейса в построителе интерфейсов, он предлагает (стенограмма из http://asciiwwdc.com/2015/sessions/407)
И последний параметр, который я хочу указать, - это тип хранилища, который может быть сильным или слабым.
В общем, вы должны сделать свою розетку сильной, особенно если вы подключаете розетку к подвидному представлению или к ограничению, которое не всегда будет сохраняться иерархией представлений.
Единственный раз, когда вам действительно нужно сделать выход слабым, - это если у вас есть пользовательский вид, который ссылается на что-то, поддерживающую иерархию представлений, и вообще не рекомендуется.
Итак, я собираюсь выбрать сильный, и я нажму кнопку connect, которая будет генерировать мою розетку.
Из WWDC 2015 существует сессия на Внедрение дизайна пользовательского интерфейса в построителе интерфейса. Около 32 минут он говорит, что вы всегда хотите сделать свой @IBOutlet
сильный.
Знайте, IBOutletCollection
должен быть @property (strong, nonatomic)
.
copy
как NSArray
?
Похоже, что с годами что-то изменилось, и теперь Apple рекомендует использовать сильные в целом. Свидетельства на их сессии WWDC находятся в сеансе 407 - Внедрение дизайна пользовательского интерфейса в Interface Builder и начинается в 32:30. Мое замечание из того, что он говорит (почти, если не совсем, цитируя его):
выходные соединения вообще должны быть сильными, особенно если мы подключаем subview или ограничение, которое не всегда сохраняется иерархия представлений
может возникнуть необходимость подключения к слабым розеткам при создании пользовательских представлений, содержащих некоторую ссылку на что-то, что находится в иерархии представлений и вообще не рекомендуется
В других палатах он всегда должен быть сильным, пока некоторые из наших пользовательских представлений не создают цикл сохранения с некоторым представлением в иерархии представлений
EDIT:
Некоторые могут задать вопрос. Поддерживает ли он сильную ссылку, не создает цикл сохранения, поскольку контроллер корневого представления и вид собственности сохраняют ссылку на него? Или почему это изменилось? Я думаю, что ответ более ранний в этом разговоре, когда они описывают, как создаются новички из xib. Существует отдельный наконечник, созданный для VC и для представления. Я думаю, что это может быть причиной того, что они меняют рекомендации. Тем не менее было бы неплохо получить более глубокое объяснение от Apple.
Я думаю, что самая важная информация: Элементы в xib автоматически отображаются в представлении. Subviews - NSArray. NSArray владеет его элементами. и т.д. имеют сильные ориентиры на них. Поэтому в большинстве случаев вы не хотите создавать еще один сильный указатель (IBOutlet)
И с ARC вам не нужно ничего делать в viewDidUnload
IBOutletCollection()
не должен бытьweak
, иначе он возвращается какnil
.