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