Должен ли IBOutlets быть сильным или слабым в ARC? - PullRequest
535 голосов
/ 06 октября 2011

Я занимаюсь разработкой исключительно для iOS 5 с использованием ARC.Должно ли IBOutlet с UIView с (и подклассами) быть strong или weak?

Следующее:

@property (nonatomic, weak) IBOutlet UIButton *button;

Избавится от всего этого:

- (void)viewDidUnload
{
    // ...
    self.button = nil;
    // ...
}

Есть ли проблемы с этим?Шаблоны используют strong, так как автоматически генерируемые свойства создаются при подключении напрямую к заголовку из редактора Interface Builder, но почему?UIViewController уже имеет ссылку strong на view, которая сохраняет свои подпредставления.

Ответы [ 11 ]

448 голосов
/ 11 октября 2011

ПРЕДУПРЕЖДЕНИЕ, УСТАРЕВШИЙ ОТВЕТ : этот ответ не актуален в соответствии с WWDC 2015, для правильного ответа обратитесь к принятому ответу (Даниэль Холл) выше. Этот ответ останется для записи.


Суммировано из библиотеки разработчиков :

С практической точки зрения в iOS и OS X выходы должны быть определены как объявленные свойства. Обычно выходы должны быть слабыми, за исключением тех, которые принадлежат Владельцу Файла, объектам верхнего уровня в файле пера (или, в iOS, сцене раскадровки), которые должны быть сильными. Поэтому созданные вами розетки по умолчанию обычно будут слабыми, потому что:

  • Выходы, которые вы создаете, например, для подпредставлений представления контроллера представления или окна контроллера окна, являются произвольными ссылками между объектами, которые не подразумевают владение.

  • Сильные выходы часто определяются классами платформы (например, выходом представления UIViewController или выходом окна NSWindowController).

    @property (weak) IBOutlet MyView *viewContainerSubview;
    @property (strong) IBOutlet MyOtherClass *topLevelObject;
    
227 голосов
/ 14 июля 2015

В настоящее время рекомендуется, чтобы Apple рекомендовала IBOutlets быть сильным , если только слабое не требуется специально, чтобы избежать цикла сохранения.Как упоминал Йоханнес выше, это было прокомментировано в сеансе «Реализация дизайна пользовательского интерфейса в Интерфейсном Разработчике» WWDC 2015, где инженер Apple сказал:

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

Я спрашивал об этом в Twitter, чтобыинженер в команде IB, и он подтвердил, что strong должен быть по умолчанию и что документы для разработчиков обновляются.

https://twitter.com/_danielhall/status/620716996326350848 https://twitter.com/_danielhall/status/620717252216623104

image image

48 голосов
/ 11 декабря 2013

В то время как документация рекомендует использовать weak в свойствах для подвидов, поскольку в iOS 6 вместо этого вполне нормально использовать strong (квалификатор владения по умолчанию). Это вызвано изменением UIViewController что представления больше не выгружаются.

  • До iOS 6, если вы сохранили прочные ссылки на подпредставления представления контроллера вокруг, если основной вид контроллера представления был выгружен, они сохранятся в подпредставлениях.пока контроллер представления находится вокруг.
  • Начиная с iOS 6, представления больше не выгружаются, а загружаются один раз, а затем остаются там до тех пор, пока там находится их контроллер.Так что сильные свойства не будут иметь значения.Они также не будут создавать сильные опорные циклы, так как они указывают на сильный опорный граф.

Тем не менее, я разрываюсь между использованием

@property (nonatomic, weak) IBOutlet UIButton *button;

и

@property (nonatomic) IBOutlet UIButton *button;

в iOS 6 и после:

  • Использование weak четко указывает на то, что контроллер не хочет владеть кнопкой.

  • Но пропуск weak не повредит в iOS 6 без выгрузки представления и является более коротким.Некоторые могут указать, что это также быстрее, но мне еще не приходилось сталкиваться с слишком медленным приложением из-за weak IBOutlet с.

  • Неиспользование weak может бытьвоспринимается как ошибка.

Итог: начиная с iOS 6 мы больше не можем ошибаться, если не используем выгрузку вида.Время вечеринки.;)

34 голосов
/ 08 октября 2011

Я не вижу никаких проблем с этим.До 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, обратный вызов делегата мог бы вызвать исключение неправильного доступа на себя.zip.text.

20 голосов
/ 04 ноября 2015

IBOutlet должен быть сильным по соображениям производительности.См. Storyboard Reference, Сильный IBOutlet, Scene Dock в iOS 9

Как объяснено в этом параграфе, выходы для подпредставлений представления контроллера представления могут быть слабыми, потому что эти подпредставленияуже принадлежит объекту верхнего уровня файла пера.Однако, когда Outlet определен как слабый указатель, и указатель установлен, ARC вызывает функцию времени выполнения:

id objc_storeWeak(id *object, id value);

Это добавляет указатель (объект) к таблице, используязначение объекта в качестве ключа.Эта таблица называется слабой таблицей.ARC использует эту таблицу для хранения всех слабых указателей вашего приложения.Теперь, когда значение объекта освобождено, ARC будет перебирать слабую таблицу и устанавливать для слабой ссылки значение nil.В качестве альтернативы, ARC может вызвать:

void objc_destroyWeak(id * object)

Затем объект незарегистрированный и objc_destroyWeak снова вызывает:

objc_storeWeak(id *object, nil)

Эта книга-поддержание связи со слабой ссылкой может занять в 2–3 раза дольше, чем выпуск сильной ссылки.Таким образом, слабая ссылка вводит накладные расходы для времени выполнения, которых вы можете избежать, просто определяя торговые точки как сильные.

Начиная с Xcode 7, он предлагает strong

image

Если вы смотрите сеанс WWDC 2015 407 Реализация дизайна пользовательского интерфейса в Интерфейсном Разработчике , он предлагает (расшифровка http://asciiwwdc.com/2015/sessions/407)

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

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

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

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

20 голосов
/ 10 октября 2011

В разработке для iOS загрузка NIB немного отличается от разработки для Mac.

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

UiViewController использует Key Value Coding для установки выходов с использованием сильных ссылок. Поэтому, когда вы освобождаете свой UIViewController, вид сверху будет автоматически освобожден, но вы также должны освободить все его выходы в методе dealloc.

В этом сообщении с ранчо Большого ботаника они освещают эту тему и также объясняют, почему использование строгой ссылки в IBOutlet не является хорошим выбором (даже если в этом случае Apple рекомендует).

15 голосов
/ 06 мая 2016

Я хотел бы отметить одну вещь: несмотря на то, что инженеры Apple заявили здесь в своем видео на WWDC 2015:

https://developer.apple.com/videos/play/wwdc2015/407/

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

В этом примере Apple Pay используются слабые: 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

Как и пример HomeKit: https://developer.apple.com/library/ios/samplecode/HomeKitCatalog/Listings/HMCatalog_Homes_Action_Sets_ActionSetViewController_swift.html#//apple_ref/doc/uid/TP40015048-HMCatalog_Homes_Action_Sets_ActionSetViewController_swift-DontLinkElementID_23

Все они полностью обновлены для iOS 9 и используют слабые выходы. Из этого мы узнаем, что А. Проблема не так проста, как это делают некоторые люди. B. Apple неоднократно меняла свое мнение, и C. Вы можете использовать все, что вас радует:)

Особая благодарность Полу Хадсону (автору www.hackingwithsift.com), который дал мне разъяснения и ссылки на этот ответ.

Надеюсь, это прояснит тему немного лучше!

Берегите себя.

9 голосов
/ 09 июля 2015

Начиная с WWDC 2015, существует сеанс Реализация дизайна пользовательского интерфейса в Интерфейсном Разработчике .На отметке 32 минуты он говорит, что вы всегда хотите, чтобы ваш @IBOutlet сильный .

6 голосов
/ 25 марта 2014

Знайте, IBOutletCollection должно быть @property (strong, nonatomic).

5 голосов
/ 07 августа 2015

Похоже, что с годами что-то изменилось, и теперь Apple рекомендует использовать сильный в целом.Свидетельство об их сеансе WWDC находится в сеансе 407. Реализация проектов пользовательского интерфейса в Интерфейсном Разработчике и начинается в 32:30.Моя записка из того, что он говорит (почти, если не совсем, цитируя его):

  • выходные соединения в целом должны быть сильными, особенно если мы подключаем подпредставление или ограничение, котороене всегда сохраняется в иерархии представлений

  • слабое выходное соединение может потребоваться при создании пользовательских представлений, которые имеют некоторую ссылку на что-то резервное в иерархии представлений и в целомэто не рекомендуется

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

РЕДАКТИРОВАТЬ:

Некоторые могут задать вопрос.Сохраняет ли это сильную ссылку, не создает ли цикл сохранения, поскольку корневой контроллер представления и собственное представление сохраняют ссылку на него?Или почему это изменилось?Я думаю, что ответ более ранний в этом выступлении, когда они описывают, как перья создаются из XIB.Существует отдельный кончик, созданный для VC и для представления.Я думаю, что это может быть причиной, по которой они меняют рекомендации.Тем не менее, было бы неплохо получить более подробное объяснение от Apple.

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