Почему ключевое слово weak можно применять только к классам и типам протоколов с привязкой к классу

Когда я объявляю переменные как weak в Swift, я иногда получаю сообщение об ошибке от Xcode:

'weak' может применяться только к классам и типам протоколов, привязанных к классу

Мне просто интересно, почему ключевое слово weak может применяться только к классам и типам протоколов, привязанных к классам? В чем причина этого?


person Thor    schedule 09.08.2016    source источник
comment
weak относится только к подсчету ссылок, и только классы подсчитываются   -  person dan    schedule 09.08.2016


Ответы (11)


weak - это квалификатор для ссылочных типов (в отличие от типов значений, таких как structs и встроенные типы значений).

Типы ссылок позволяют иметь несколько ссылок на один и тот же объект. Объект освобождается, когда последняя сильная ссылка перестает ссылаться на него (слабые ссылки не учитываются).

С другой стороны, типы значений присваиваются копией. Подсчет ссылок не применяется, поэтому модификатор weak для них не имеет смысла.

person Sergey Kalinichenko    schedule 09.08.2016

Одна из частых причин этой ошибки заключается в том, что вы объявили собственный протокол, но забыли наследовать от AnyObject:

protocol PenguinDelegate: AnyObject {
    func userDidTapThePenguin()
}

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

Приведенный выше код выдаст вам ошибку, если вы забудете наследовать от AnyObject. Причина в том, что weak имеет смысл только для ссылочных типов (классов). Таким образом, вы уменьшите нервозность компилятора, четко указав, что PenguinDelegate предназначен для классов, а не для типов значений.

person Jak    schedule 22.10.2016
comment
в чем преимущество наследования от NSObjectProtocol? Мои собственные делегаты этого не делают, и я не сталкивался с какими-либо проблемами при использовании - person Apostolos Apostolidis; 25.04.2017
comment
@Apostolos Слабые ссылки действительны только в классах. Унаследовав от NSObjectProtocol, вы гарантируете компилятору, что протокол будет использоваться только для классов (а не для перечислений и т. Д.). - person Vince O'Sullivan; 06.05.2017
comment
@ VinceO'Sullivan В чем преимущество гарантии этого для компилятора? Разве не легче просто не унаследовать от NSObjectProtocol? Во-первых, вам не нужно иметь дело с добавлением модификатора weak. - person yesthisisjoe; 03.08.2017
comment
Ага, работает. Но вы не знаете почему. weak - это квалификатор для ссылочных типов, он не имеет смысла для типов значений, поскольку типы значений не могут быть слабыми по определению. Протокол может быть принят ссылочными типами и типами значений. Поэтому вы должны ограничить его реализацию только ссылочными типами: protocol PenguinDelegate: class { } Здесь вы ограничиваете реализацию протокола только NSObjectProtocols, которые тоже являются ссылочными типами, поэтому он работает. - person Martin; 10.08.2017
comment
Используйте protocol PenguinDelegate: class, который не зависит от среды выполнения Objective-C, но все же решает проблему. - person Feuermurmel; 14.01.2018

protocol PenguinDelegate: class {
    func userDidTapThePenguin()
}

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

Если вы вводите class после вашего протокола, он также работает и кажется более подходящим, чем для NSObjectProtocol.

person Aaronium112    schedule 11.06.2017
comment
Мне кажется, что сочетание этого и ответа @dasblinkenlight полностью ответит на этот вопрос. dasblinkenlight объяснил, почему отображается сообщение об ошибке, и объясняет, как добиться того, что вы, вероятно, пытались сделать как разработчик. - person stuckj; 10.04.2018

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

Вот что у меня было. Это также давало мне ту же ошибку, что и выше:

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 может применяться только к классам и типам протоколов, привязанных к классам

:-<

person Patrick Miron    schedule 15.02.2018

Я узнал об одном случае, когда у вас даже есть тип класса, но вы все равно получаете это сообщение об ошибке.

Например,

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
   }()
}
person David.Chu.ca    schedule 03.10.2017

weak для ARC (автоматический подсчет ссылок). Это означает, что счетчик ссылок не добавляется. Так что это работает только для Class. А в Swift вы получите необязательное значение для безопасности.

person Lumialxk    schedule 09.08.2016

Я попытался захватить свойства типа String и Array для закрытия. У меня такие ошибки:

'weak' может применяться только к классам и типам протоколов с привязкой к классу, но не к '[String]'

'weak' может применяться только к классам и типам протоколов, привязанных к классу, но не к 'String'

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

person iOS Developer    schedule 27.02.2018

введите описание изображения здесь Я быстро использовал целевой класс C для scrolView. Я создал IBOutlet для этой прокрутки. И при компиляции кода эта ошибка начала проявляться.

Итак, чтобы решить эту проблему, импортируйте этот класс в свой заголовок моста.

импортировать YourClass.h

Я использовал Xcode 9.2 с быстрым 3.2

person Pramod More    schedule 07.05.2018

Просто к вашему сведению, а кто не обновляется. После быстрого предложения SE-0156 https://github.com/apple/swift-evolution/blob/master/proposals/0156-subclass-existentials.md, есть в Swift docs "Class-Only Protocols section" https://docs.swift.org/swift-book/LanguageGuide/Protocols.html теперь описано использовать AnyObject вместо класса. Таким образом, возможно, что в будущем : class будет устаревшим.

person Dren    schedule 26.06.2018

weak работает только для ссылочного типа, поэтому Xcode сообщит об ошибке, если вы звоните из struct (вместо class).

person superarts.org    schedule 25.09.2019

  1. weak не для типа значения.
  2. слабый попадает в картину только для класса.

"weak" может применять все, что унаследовано от классов или типов протоколов, связанных с классом.

  1. Протокол класса: протокол ViewControllerDelegate: class {func getInformationk (value: String?)}
  2. NSObjectProtocol:

    протокол ViewControllerDelegate: NSObjectProtocol {func getInformation (value: String?)}

person Divesh singh    schedule 23.10.2019
comment
Не могли бы вы объяснить немного больше? - person Dieter Meemken; 23.10.2019