Измените объект после возвращения в Swift

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 не сможет инициализироваться, как яйцо и курица.

Я пытался найти как 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 в Свифте. Любое предложение? Может быть перезапись байтов в указателе объекта будет работать?

0 ответов

Другие вопросы по тегам