Связанные объекты в Swift, действительно ли глобальный ключ создает определенные экземпляры?

Чтобы иметь связанный объект в Swift, вы просто используете адрес памяти в качестве дескриптора, а затем используете вызовы objc.

Обычный пример кода, который вы можете найти везде:

var keyA:UInt8 = 0
var keyB:UInt8 = 0
extension UIViewController {

    var aoAA: String? {
        get { return objc_getAssociatedObject(self, &keyA) as? String }
        set { objc_setAssociatedObject(self, &keyA, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) }
    }
    var aoBB: String? {
        get { return objc_getAssociatedObject(self, &keyB) as? String }
        set { objc_setAssociatedObject(self, &keyB, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) }
    }
}

это отлично работает,

class Thing: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        aoAA = "this is a"
        print("...... \(aoAA)")
        aoBB = "this is b"
        print("...... \(aoBB)")
        aoAA = "changed A"
        print("...... \(aoAA) \(aoBB)")
        aoBB = "changed B"
        print("...... \(aoAA) \(aoBB)")
        aoAA = aoBB
        print("...... \(aoAA) \(aoBB)")
        }

Но подождите...

Дескрипторы, keyA и keyB, являются глобальными для всего проекта.

Когда вы используете aoAA и aoBB в разных UIViewController, как может быть, что aoAA и aoBB действуют как свойства, специфичные для этого экземпляра?

Неужели везде в проекте только "один" аоАА?

т. е., aoAA является глобальным — точно так же, как дескриптор keyA является глобальным?

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

Как каждый экземпляр aoAA может быть другим - он использует один и тот же глобальный дескриптор?


person Fattie    schedule 24.01.2017    source источник
comment
вы передаете ссылку на себя в каждом вызове, поэтому он устанавливает связанный объект с вашим экземпляром UIViewController   -  person Orest Savchak    schedule 24.01.2017
comment
привет @orest ... спасибо ... но тогда он использует &keyA в вызове. Во всей сборке приложения есть только один ключ &keyA. ?   -  person Fattie    schedule 24.01.2017
comment
Да, он использует адрес ключа A, адрес должен быть уникальным для ключа A во время работы приложения.   -  person Orest Savchak    schedule 24.01.2017
comment
Ах, скажем, значение ключа равно 1234. Вы имеете в виду, что оно использует ОБА значение объекта в качестве ключа (я для нас) И ключ в качестве ключа (1234) каждый раз, когда он вызывается? Таким образом, ключ, который он использует, представляет собой некоторую комбинацию ОБА ключа (1234) и объекта (в нашем примере это различные личности). Это правильно?   -  person Fattie    schedule 24.01.2017
comment
Привет, @JoeBlow, кажется, я всегда меняю ваши теги [swift3] на теги [swift] — обратите внимание, что тег [swift3] предназначен только для вопросов, непосредственно связанных с изменениями в языке в результате Swift 3, тогда как [swift] предназначен для общих языковых вопросов (согласно их соответствующим вики-тегам). Этот вопрос будет столь же актуален, когда появится Swift 4 :)   -  person Hamish    schedule 24.01.2017


Ответы (1)


Концепция «связанных объектов» в Objective-C позволяет соединить один «целевой» экземпляр объекта с одним «исходным» экземпляром объекта. Это однонаправленная ассоциация, в которой только источник знает цель:

Связанные объекты с исходными и целевыми экземплярами

objc_setAssociatedObject(source, key, target, ...)

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

Поскольку для извлечения связанного объекта необходимо предоставить как ключ, так и исходный экземпляр, нет необходимости использовать действительно уникальные ключи. Реализация objc_***AssociatedObject может формировать уникальный для процесса ключ, комбинируя указатель экземпляра и ключ.

Итак, для вашего примера да, и aoAA, и aoBB будут возвращать отдельные значения для каждого экземпляра UIViewController, даже если keyA и keyB являются глобальными.

Чтобы быть абсолютно ясным, вам нужны нужны разные ключи для каждого связанного объекта в данном расширении. Итак, для aoAA и aoBB нужен свой ключ, как показано в примере кода (а именно, указатели на keyA и keyB). Но, как указано в вопросе, правильно иметь только один ключ для каждого связанного объекта, независимо от того, в скольких соответствующих классах используется расширение.

person Nikolai Ruhe    schedule 24.01.2017
comment
скажите @NikolaiRuhe, я добавил один уточняющий момент к вашему идеальному ответу - не стесняйтесь расслабляться, редактировать и т. д., как всегда - person Fattie; 24.01.2017
comment
Не за что, мне нравится :) - person Nikolai Ruhe; 24.01.2017