Мене завжди бентежило, чи повинні делегати бути слабкими чи ні. Нещодавно я дізнався більше про делегатів і коли використовувати слабкі посилання, тож дозвольте тут додати деякі додаткові моменти заради майбутніх глядачів.
Метою використання weakключового слова є уникнення сильних еталонних циклів (збереження циклів). Сильні еталонні цикли трапляються, коли два екземпляри класу мають чіткі посилання один на одного. Їх посилання ніколи не доходять до нуля, тому вони ніколи не дістаються.
Вам потрібно використовувати лише weakякщо делегат - клас. Структури та перерахунки Swift - це типові значення (їх значення копіюються при створенні нового екземпляра), а не типові типи, тому вони не роблять сильних еталонних циклів.
weakпосилання завжди необов’язкові (інакше ви б використовувались unowned) та завжди використовуєте var(не let), щоб необов'язково можна було встановити, nilколи воно розміщене.
Батьківський клас, природно, повинен мати чітке посилання на його дочірні класи і, таким чином, не використовувати weakключове слово. Коли дитина хоче посилання на свого батька, вона повинна зробити це слабким посиланням, використовуючи weakключове слово.
weakйого слід використовувати, коли ви хочете посилання на клас, яким ви не володієте, а не лише для дитини, що посилається на свого батька. Коли два неієрархічні класи потребують посилання один на одного, виберіть один із слабких. Вибір, який ви виберете, залежить від ситуації. Більше про це див. У відповідях на це запитання .
Як правило, делегатів слід позначати так,weak оскільки більшість делегатів посилаються на класи, якими вони не володіють. Це, безумовно, вірно, коли дитина використовує делегата для спілкування з батьком. Використання слабкого посилання для делегата - це те, що рекомендується в документації . (Але дивіться і це .)
Протоколи можна використовувати як для типів посилань (класів), так і для типів значень (структури, перерахунки). Тож у ймовірному випадку, що вам потрібно зробити делегата слабким, ви повинні зробити його протоколом лише для об'єктів. Спосіб зробити це - додати AnyObjectдо спадкового списку протоколу. (Раніше ви робили це за допомогою classключового слова, але AnyObjectзараз його віддають перевагу .)
protocol MyClassDelegate: AnyObject {
// ...
}
class SomeClass {
weak var delegate: MyClassDelegate?
}
Читання наступних статей - це те, що допомогло мені зрозуміти це набагато краще. Вони також обговорюють пов'язані з ними питання, як unownedключове слово, і чіткі еталонні цикли, що відбуваються із закриттям.