Измените объект после возвращения в Swift - PullRequest
0 голосов
/ 12 июня 2018

NSKeyedUnarchiver, который является конкретным подклассом NSCoder, работает как магия.

Пожалуйста, посмотрите на этот пример:

У меня есть 2 класса,Person и CreditCard

class Person: NSObject, NSCoding {
    var creditCard: CreditCard

    init(coder aDecoder: NSCoder) {
        aDecoder.decodeObject(forKey: "creditCard") as? CreditCard            
    }
}

class CreditCard: NSObject, NSCoding {
    weak var person: Person

    init(coder aDecoder: NSCoder) {
        aDecoder.decodeObject(forKey: "person") as? Person
    }
}

Как видите, объекты связаны друг с другом.Что удивительно в NSKeyedUnarchiver, так это то, как он может обрабатывать бесконечные циклы.Если кодер следует за каждой ссылкой и слепо кодирует каждый объект, с которым он сталкивается, эта циклическая ссылка сгенерирует бесконечный цикл:

Person -> CreditCard -> Person -> CreditCard -> ....infinite loop

Ниже приведены шаги:

  1. При инициализации класса Person вызывается aDecoder.decodeObject(forKey: "creditCard") as? CreditCard.
    Этот метод вызывает init(coder aDecoder: NSCoder) в классе CreditCard.

  2. Но класс CreditCard нельзя инициализировать, поскольку в инициализаторе aDecoder.decodeObject(forKey: "person").И этот метод вызовет init(coder aDecoder: NSCoder) в классе Person.

  3. Он будет повторяться бесконечно, и оба Person и CreditCard не смогут быть инициализированы, как eggи курица.

Я пытался найти, как NSKeyedArchiver может предотвратить эту петлю.

В соответствии с этим:
https://github.com/gnustep/libs-base/blob/master/Source/NSKeyedUnarchiver.m

Хитрость заключается в том, чтобы использовать o = [className allocWithZone: _zone]; (строка 237) без init и сохранять его в массиве.В следующий раз, когда мы вызовем aDecoder.decodeObject(forKey:), вместо вызова init (кодер aDecoder: NSCoder) он вернет этот объект в массиве (строка 174).

Я попытался воспроизвести это поведение в Swift длямоя библиотека.Но я не смог найти способ сделать это в Swift, потому что мы не можем сделать alloc без init в Swift.Любое предложение?Может, перезапись байтов в указателе объекта будет работать?

...