В чем разница между слабой ссылкой и неизменной ссылкой?

Swift имеет:

  • Сильные ссылки
  • Слабые ссылки
  • Неопубликованные ссылки

Как отличная ссылка отличается от слабой ссылки?

Когда безопасно использовать неопубликованную ссылку?

Не зарегистрированы ли ссылки на угрозу безопасности, например обвисшие указатели на C/С++?

Ответ 1

Обе ссылки weak и unowned не создают удержание strong для упомянутого объекта (a.k.a. они не увеличивают количество сохраняемых файлов, чтобы не допустить освобождения ARC ссылочным объектом).

Но почему два ключевых слова? Это различие связано с тем, что типы Optional встроены в язык Swift. Короткая история о них: дополнительные типы обеспечивают безопасность памяти (это прекрасно работает с правилами конструктора Swift - строгими, чтобы обеспечить это преимущество).

Ссылка weak позволяет ему стать nil (это происходит автоматически при освобождении ссылочного объекта), поэтому тип вашего свойства должен быть необязательным - поэтому вы, как программист, обязаны проверить его перед тем, как вы используете его (в основном компилятор вынуждает вас как можно больше писать безопасный код).

Ссылка unowned предполагает, что она никогда не станет nil в течение своей жизни. При инициализации должна быть установлена неизвестная ссылка - это означает, что ссылка будет определена как необязательный тип, который можно безопасно использовать без проверок. Если каким-либо образом объект, на который ссылаются, освобождается, то приложение будет аварийно завершать работу при использовании ссылки без ссылки.

Из документов Apple:

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

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

Пример ключевого слова weak:

class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
}

class Apartment {
    let number: Int
    init(number: Int) { self.number = number }
    weak var tenant: Person?
}

А теперь, для некоторого искусства ASCII (вы должны пойти , посмотрите документы - у них есть красивые диаграммы):

Person ===(strong)==> Apartment
Person <==(weak)===== Apartment

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

Пример ключевого слова unowned:

class Customer {
    let name: String
    var card: CreditCard?
    init(name: String) { self.name = name }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer
    init(number: UInt64, customer: Customer) { self.number = number; self.customer = customer }
}

В этом примере Customer может иметь или не иметь CreditCard, но CreditCard всегда будет ассоциироваться с Customer. Для представления этого у класса Customer есть необязательное свойство card, но у класса CreditCard есть необязательное (и не принадлежащее) свойство customer.

Customer ===(strong)==> CreditCard
Customer <==(unowned)== CreditCard

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

Примечание от Apple:

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

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

И есть также классические сценарии сохранения цикла, которых следует избегать при работе с замыканиями.

Для этого я советую вам посетить Apple Docs или прочитать книгу.

Ответ 2

Q1. Как "Неопубликованная ссылка" отличается от "Слабой ссылки"?

Слабая ссылка:

Слабая ссылка - это ссылка, которая не удерживает экземпляр, на который он ссылается, и поэтому не останавливает ARC от утилизации ссылочный экземпляр. Поскольку слабые ссылки разрешены "no value", вы должны объявить каждую слабую ссылку как имеющую дополнительный тип. (Apple Docs)

Неопубликованная ссылка:

Как и слабые ссылки, неопубликованная ссылка не удерживает сильную фиксацию на экземпляр, на который он ссылается. В отличие от слабой ссылки, однако, считается, что неизменная ссылка всегда имеет значение. Из-за этого, неопубликованная ссылка всегда определяется как необязательный тип. (Apple Docs)

Когда использовать каждый:

Используйте слабую ссылку, когда это действительно для этой ссылки, чтобы стать nil в какой-то момент за всю свою жизнь. И наоборот, используйте unowned если вы знаете, что ссылка никогда не будет равна нулю был установлен во время инициализации. (Apple Docs)


Q2. Когда безопасно использовать "неопубликованную ссылку"?

Как указано выше, предполагается, что неизменная ссылка всегда имеет значение. Поэтому вы должны использовать его только тогда, когда вы уверены, что эта ссылка никогда не будет равна нулю. Apple Docs иллюстрирует пример использования для неопубликованных ссылок в следующем примере.

Предположим, что у нас есть два класса Customer и CreditCard. Клиент может существовать без кредитной карты, но кредитная карта не будет существовать без клиента, т.е. Можно предположить, что у кредитной карты всегда будет клиент. Таким образом, они должны иметь следующее соотношение:

class Customer {
    var card: CreditCard?
}

class CreditCard {
    unowned let customer: Customer
}

Q3. Ссылка на справочную службу "без ссылки" на риск безопасности, такой как "оборванные указатели" на C/С++

Я так не думаю.

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

Это единственный риск, который я вижу с ним.

Ссылка на Apple Docs

Ответ 3

Если self может быть nil в закрытии, используйте [слабый я].

Если self никогда не будет равным нулю в использовании закрытия, используйте [unowned self].

Если он сбой, когда вы используете [unowned self], тогда self, вероятно, имеет значение nil в какой-то момент в этом закрытии, и вам, вероятно, придется использовать [слабый self].

Ознакомьтесь с примерами использования strong, слабых и unowned в закрытии:

https://developer.apple.com/library/ios/documentation/swift/conceptual/swift_programming_language/AutomaticReferenceCounting.html

Ответ 4

Выдержки из ссылка

Несколько Заключительные точки

  • Чтобы определить, нужно ли даже беспокоиться о сильных, слабых или не знаю, спросите: "Я имею дело с ссылочными типами". Если вы работаете с помощью Structs или Enums, ARC не управляет памятью для этих типов и вам даже не нужно беспокоиться о том, чтобы указать слабый или неактивный эти константы или переменные.
  • Сильные ссылки хороши в иерархических отношениях, где родительский язык ссылается на ребенка, но не наоборот. Фактически, сильные ссылки являются наиболее подходящим видом справки большую часть времени.
  • Если два экземпляра необязательно связаны друг с другом, убедитесь, что что один из этих экземпляров имеет слабое отношение к другому.
  • Когда два экземпляра связаны таким образом, что один из экземпляры can not существуют без другого, экземпляр с обязательная зависимость должна содержать неопубликованную ссылку на другую экземпляр.

Ответ 5

Неопубликованные ссылки - это своего рода слабая ссылка, используемая в случае отношения Same-Lifetime между двумя объектами, когда объект должен принадлежать только одному другому объекту. Это способ создания непреложной привязки между объектом и одним из его свойств.

В примере, приведенном в промежуточном быстром видео WWDC, лицо имеет кредитную карту, а кредитная карта может иметь только одного владельца. На кредитной карте человек не должен быть необязательным, потому что вы не хотите, чтобы кредитная карта плавала только с одним владельцем. Вы можете разбить этот цикл, сделав свойство владельца на кредите слабой ссылкой, но это также требует, чтобы вы сделали его необязательным, а также переменным (в отличие от константы). Неприемлемая ссылка в этом случае означает, что, хотя у CreditCard нет доли участия в Личности, ее жизнь зависит от нее.

class Person {
    var card: CreditCard?
}

class CreditCard {

    unowned let holder: Person

    init (holder: Person) {
        self.holder = holder
    }
}

Ответ 6

ARC

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

STRONG

По сути, это нормальная ссылка (указатель и все), но она сама по себе особенная, поскольку защищает указанный объект от освобождения ARC, увеличивая его, сохраняя счетчик на 1. По сути, до тех пор, пока что-либо имеет сильную ссылку на объект, он не будет освобожден.

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

Устранение сильных ссылочных циклов между экземплярами классов

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

WEAK

Слабая ссылка - это просто указатель на объект, который не защищает объект от освобождения ARC. В то время как сильные ссылки увеличивают количество сохраняемых объектов на 1, слабые ссылки - нет. Кроме того, слабые ссылки обнуляют указатель на ваш объект, когда он успешно освобождается. Это гарантирует, что при доступе к слабой ссылке это будет либо действительный объект, либо nil.

ARC автоматически устанавливает слабую ссылку на ноль, когда экземпляр, на который он ссылается, освобождается. И поскольку слабые ссылки должны позволять менять свое значение на nil во время выполнения, они всегда объявляются как переменные

С помощью

В ситуации, когда два свойства, оба из которых могут быть равны nil. Этот сценарий лучше всего разрешается со weak ссылкой.

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

бесхозный

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

ARC никогда не устанавливает значение для неиспользуемых ссылок равным nil, что означает, что неопознанные ссылки определяются с использованием необязательных типов.


ВАЖНЫЙ.

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

Если вы попытаетесь получить доступ к значению неизвестной ссылки после того, как этот экземпляр был освобожден, вы получите ошибку времени выполнения - Attempted to read an unowned reference but object was already deallocated


НОТА

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

Вы указываете небезопасную ссылку без ссылки, написав unowned(unsafe). Если вы попытаетесь получить доступ к небезопасной неопознанной ссылке после того, как экземпляр, на который она ссылается, будет освобожден, ваша программа попытается получить доступ к той области памяти, где был этот экземпляр, что является небезопасной операцией.

С помощью

В ситуации, когда одно свойство может быть равно nil а другое свойство не может быть равно nil. Этот сценарий лучше всего решать с unowned ссылкой.

Используйте unowned ссылку, когда другой экземпляр имеет такой же срок службы или более продолжительный срок службы. Точно так же, как неявно развернутый необязательный, если вы можете гарантировать, что ссылка не будет nil в своей точке использования, используйте unowned. Если нет, то вы должны использовать weak.

Настоятельно рекомендуем прочитать документ и источник

Ответ 7

Ссылки weak и strong не влияют на количество ссылок объекта. Но слабая ссылка всегда будет необязательной, то есть она может быть нулевой, тогда как ссылки unowned никогда не могут быть нулевыми, поэтому они никогда не будут необязательными. При использовании необязательной ссылки вы всегда должны учитывать вероятность того, что объект будет нулевым. В случае неподтвержденной ссылки вы должны убедиться, что объект никогда не равен нулю. Использование неизвестной ссылки на нулевой объект будет аналогично принудительному развертыванию необязательного nil-объекта.

Тем не менее, можно использовать неизвестную ссылку, если вы уверены, что время жизни объектов больше, чем ссылки. Если это не так, лучше использовать слабую ссылку.

Что касается третьей части вопроса, я не думаю, что ссылка без ссылки похожа на висящий указатель. Когда мы говорим о подсчете ссылок, мы обычно ссылаемся на строгий подсчет ссылок объекта. Точно так же swift поддерживает количество неизвестных и слабых ссылок для объекта (слабые ссылки указывают на то, что называется "боковой таблицей", а не на сам объект). Когда счетчик сильных ссылок достигает нуля, объект деинициализируется, но он не может быть освобожден, если счетчик неиспользованных ссылок больше нуля.

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

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

Ответ 8

Из книги Джона Хоффмана "Освоение Свифта 4.":

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

Ответ 9

Используйте unowned если вы уверены, что self никогда не будет равным nil в той точке, к которой вы обращаетесь к self.

Пример (конечно, вы можете добавить цель непосредственно из MyViewController, но, опять же, это простой пример).:

class MyViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let myButton = MyButton { [unowned self] in
            print("At this point, self can NEVER be nil. You are safe to use unowned.")
            print("This is because myButton can not be referenced without/outside this instance (myViewController)")
        }
    }
}

class MyButton: UIButton {
    var clicked: (() -> ())

    init(clicked: (() -> ())) {
        self.clicked = clicked

        // We use constraints to layout the view. We don't explicitly set the frame.
        super.init(frame: .zero)

        addTarget(self, action: #selector(clicked), for: .touchUpInside)
    }

    @objc private func sendClosure() {
        clicked()
    }
}

Используйте weak когда есть вероятность, что " self может быть nil в той точке, где вы получаете доступ к self.

Пример:

class MyViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        NetworkManager.sharedInstance.receivedData = { [weak self] (data) in
            print("Can you guarentee that self is always available when the network manager received data?")
            print("Nope, you can't. Network manager will be alive, regardless of this particular instance of MyViewController")
            print("You should use weak self here, since you are not sure if this instance is still alive for every")
            print("future callback of network manager")
        }
    }
}

class NetworkManager {

    static let sharedInstance = NetworkManager()

    var receivedData: ((Data) -> ())?

    private func process(_ data: Data) {
        // process the data...

        // ... eventually notify a possible listener.
        receivedData?(data)
    }
}

Недостатки unowned:

  • Эффективнее слабого
  • Вы можете (ну, вы вынуждены) пометить экземпляр как неизменяемый (больше не начиная с Swift 5.0).
  • Указывает читателю вашего кода: этот экземпляр имеет отношение к X и не может жить без него, но если X ушел, я тоже ушел.

Минусы weak:

  • Более безопасный, чем неподходящий (так как он не может разбиться).
  • Может создать отношения с X, которые идут обоими путями, но оба могут жить друг без друга.

Если вы не уверены, используйте weak. Подождите, я имею в виду, спросите здесь, на StackOverflow, что вы должны делать в вашем случае! Использование слабых все время, когда вы не должны, просто сбивает с толку вас и читателя вашего кода.