it-swarm.com.ru

Должен ли IBOutlets быть сильным или слабым в ARC?

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

Следующие:

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

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

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

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

535
hypercrypt

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

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

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

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

225
Daniel Hall

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


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

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

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

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

    @property (weak) IBOutlet MyView *viewContainerSubview;
    @property (strong) IBOutlet MyOtherClass *topLevelObject;
    
448
Alexsander Akers

Хотя документация рекомендует использовать 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 без выгрузки представления и является более коротким. Некоторые могут указать, что это также быстрее, но мне еще не приходилось сталкиваться с слишком медленным приложением из-за weakIBOutlets.

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

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

48
Tammo Freese

Я не вижу никаких проблем с этим. До 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];
}

Я обнаружил, что если я отклонил это представление в нужное время и не установил значение self.Zip в viewDidUnload, обратный вызов делегата может вызвать исключение неправильного доступа к self.Zip.text.

34
Christopher Pickslay

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

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

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

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

20
Giuseppe

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

Как объяснено в этом параграфе, выходы для подпредставлений представления контроллера представления могут быть слабыми, потому что эти подпредставления уже принадлежат объекту верхнего уровня файла nib. Однако, когда 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

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

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

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

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

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

20
onmyway133

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

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

Apple постоянно меняет свое мнение по этому вопросу, что говорит нам, что нет единого правильного ответа на этот вопрос. Чтобы показать, что даже инженеры 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

Как и в примере Lister: https://developer.Apple.com/library/ios/samplecode/Lister/Listings/Lister_ListCell_Swift.html#//Apple_ref/doc/uid/TP40014701-Lister_ListCell_Swift -DontLinkElementID_57

Как и в примере с основным местоположением: 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.htmlre6 -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/doctation_A_S_S_S_S_S_S_S_S_S_S_S_W_S_S_S_W -DontLinkElementID_23

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

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

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

Береги себя.

15
syedfa

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

9
Johannes

Помните, что IBOutletCollection должно быть @property (strong, nonatomic).

6
landonandrey

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

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

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

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

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

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

5
Julian Król

Я думаю, что самая важная информация: элементы в xib автоматически попадают в подпредставления представления. Subviews является NSArray. NSArray владеет своими элементами. и т.д. имеют сильные указатели на них. Так что в большинстве случаев вы не хотите создавать другой сильный указатель (IBOutlet)

А с ARC вам не нужно ничего делать в viewDidUnload

4
kraag22