Чому ключове слово „слабкий” може застосовуватися лише до типів протоколів класів та класів


74

Коли я оголошую змінні як weakу Swift, я іноді отримую повідомлення про помилку від Xcode:

"слабкий" може застосовуватися лише до типів протоколів класу та класів

Мені просто цікаво, чому ключове слово weakможе застосовуватися лише до класів і типів протоколів, пов’язаних із класами? У чому причина цього?


8
weakмає значення тільки для підрахунку посилань і тільки класів підрахунку посилань
дан

Відповіді:


70

weakє кваліфікатором для посилальних типів (на відміну від типів значень, таких як structs та вбудовані типи значень).

Типи посилань дозволяють мати кілька посилань на один і той же об’єкт. Об’єкт звільняється, коли остання сильна посилання перестає посилатися на нього (слабкі посилання не враховуються).

Типи значень, навпаки, присвоюються за допомогою копії. Підрахунок посилань не застосовується, тому weakмодифікатор не має для них сенсу.


128

Однією з найпоширеніших причин цієї помилки є те, що ви оголосили власний протокол, але забули успадкувати від AnyObject:

protocol PenguinDelegate: AnyObject {
    func userDidTapThePenguin()
}

class MyViewController: UIViewController {
    weak var delegate: PenguinDelegate?
}

Наведений вище код дасть вам помилку, якщо ви забудете успадкувати від AnyObject. Причина в тому, що weakмає сенс лише для посилальних типів (класів). Отже, ви змушуєте компілятор менш нервувати, чітко заявляючи, що PenguinDelegate призначений для класів, а не типів цінностей.


1
яка перевага успадкування від NSObjectProtocol? Мої власні представники цього не роблять, і я не стикався з жодною проблемою у своєму використанні
Апостолос Апостолідіс,

3
@Apostolos Слабкі посилання діють лише в класах. Успадкувавши від NSObjectProtocol, ви гарантуєте компілятору, що протокол буде використовуватися лише для класів (а не для перерахувань тощо).
Вінс О'Салліван,

@ VinceO'Sullivan Яка перевага гарантування компілятору? Хіба не простіше просто не успадковувати від NSObjectProtocol? Для одного вам не доведеться мати справу з додаванням weakмодифікатора.
yesthisisjoe

12
Так, це працює. Але ви не знаєте чому. weakє кваліфікатором для посилальних типів, це не має сенсу для типів значень, оскільки типи значень не можуть бути слабкими за визначенням. Протокол може бути прийнятий за посилальними типами та типами значень. Отже, вам слід обмежити його реалізацію лише за допомогою посилальних типів: protocol PenguinDelegate: class { }Тут ви обмежуєте протокол, який повинен реалізовуватися лише NSObjectProtocols-ями, чиї посилальні типи теж є, тому це працює.
Мартін

4
Використання, protocol PenguinDelegate: classяке не залежить від середовища виконання Objective-C, але вирішує проблему.
Feuermurmel

63
protocol PenguinDelegate: class {
    func userDidTapThePenguin()
}

class MyViewController: UIViewController {
    weak var delegate: PenguinDelegate?
}

Якщо ви вводите клас після вашого протоколу, він також працює, і здається більш доречним, ніж для NSObjectProtocol.


Я відчуваю, що поєднання цього та відповідь від @dasblinkenlight повністю відповіли б на це питання. dasblinkenlight пояснив, чому відображається повідомлення про помилку, і це пояснює, як досягти того, що ви, ймовірно, намагалися зробити як розробник.
stuckj

14

Ну тільки в разі , якщо хто - то думає , що у вас є все правильно в вашому коді , як я, переконайтеся , що ви не помилково замінили :на= .

Ось що я мав. Це також дало мені ту ж помилку, що і вище:

protocol PenguinDelegate: class {
    func userDidTapThePenguin()
}

class MyViewController: UIViewController {
    weak var delegate = PenguinDelegate?
}

Але правильний спосіб:

protocol PenguinDelegate: class {
    func userDidTapThePenguin()
}

class MyViewController: UIViewController {
    weak var delegate: PenguinDelegate?
}

Ви бачите різницю? Мені знадобився час, щоб побачити, що у мене замість товстої кишки є знак рівності. Також зауважте, що я все-таки отримував інші помилки для того самого рядка, оскільки я вирішив, що моя перша помилка здається найімовірнішою справжньою проблемою:

- weakможе застосовуватися лише до типів протоколів класу та класів

: - <


5

В одному випадку я з'ясовую, де у вас навіть є клас, але все одно ви отримуєте це повідомлення про помилку.

Наприклад,

class MyVC: UIViewController {
   var myText: UITextView = {
      [weak self]
      let text = UITextView()
      // some codes using self
      return text
   }()
}

Тут UITextViewоб'єкт повертається з анонімного блоку як ініціалізація var myText. Я отримав повідомлення про помилку того ж типу. Щоб вирішити проблему, її varслід позначити як lazy:

class MyVC: UIViewController {
   lasy var myText: UITextView = {
      [weak self]
      let text = UITextView()
      // some codes using self
      return text
   }()
}

2

weakпризначений для ARC (автоматичний підрахунок посилань). Це означає не додавати кількість посилань. Тож це працює лише для Class. А в Swift ви отримаєте необов’язкове значення для безпеки.


1

Я намагався захопити властивості типу String та Array для закриття. Я отримав такі помилки:

"слабкий" може застосовуватися лише до типів протоколів класу та класів, а не "[рядок]"

"слабкий" може застосовуватися лише до типів протоколів класу та класів, а не "рядок"

Я деякий час грав на дитячому майданчику, і виявилося, що захоплення себе досить для цих типів.


1

введіть тут опис зображенняЯ швидко використовував об’єктивний клас C для scrolView. Я створив IBOutlet цього виду прокрутки. І під час компіляції коду ця помилка почала відображатися.

Тож, щоб виправити подібну проблему, імпортуйте цей клас у свій мостовий заголовок

імпортувати "YourClass.h"

Я використовував Xcode 9.2 із швидкою версією 3.2


1

Просто FYI і хто не оновлюється. Після того, як була реалізована швидка пропозиція SE-0156 https://github.com/apple/swift-evolution/blob/master/proposals/0156-subclass-existentials.md , в документах Swift є "Розділ протоколів лише класу" https : //docs.swift.org/swift-book/LanguageGuide/Protocols.html тепер описано для використання AnyObject замість класу . Отже, можливо : клас буде застарілим у майбутньому.


0

weakпрацює лише для довідкового типу, тому Xcode повідомляє про помилку, якщо ви телефонуєте з struct(замість class).


0
  1. слабкий - не для типу значення.
  2. слабкий приходить до картини лише для класу.

"слабкий" може застосувати будь-що, що успадковується від класу або пов'язаних з класами типів протоколів

  1. Протокол класу: протокол ViewControllerDelegate: клас {func getInformationk (значення: String?)}
  2. Протокол NSObject:

    протокол ViewControllerDelegate: NSObjectProtocol {func getInformation (значення: String?)}


Ви можете пояснити трохи більше?
Дітер Меемкен,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.