Странная проблема с адресом памяти в Swift

#swift #rx-swift

Вопрос:

Я не могу понять, как получить правильный адрес памяти для вычисляемой переменной, определенной внутри класса/структуры. Я определил класс следующим образом (аналогично и для структуры):

 class TestClass {
    private var a = "Hello"
    
    var getterSetter: String {
        get {
            return a
        }
        set {
            a = newValue
        }
    }
}
 

Для простоты предположим, что я определяю свой ViewController следующим образом:

 class ViewController: UIViewController {
    private let testClass = TestClass()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        demoMethod()
        
        print("--------")
        print(testClass.getterSetter)    //Prints "I'm here"
        
        /// Address of testClass
        print("Address of testClass: (Unmanaged.passUnretained(self.testClass).toOpaque())")
        
        /// Address of computed variable in testClass
        withUnsafePointer(to: amp;self.testClass.getterSetter) {
            print("Address of computed variable: (String(format: "%p", $0.pointee))")
        }
        print("--------")
        
    }
    
    private func demoMethod() {
        Observable.just(())
            .subscribe(onNext: { [weak self] in
                guard let self = self else { return }
                self.testClass.getterSetter = "I'm here"
                
                print("*****")
                /// Address of testClass
                print("Address of testClass: (Unmanaged.passUnretained(self.testClass).toOpaque())")
                
                /// Address of computed variable in testClass
                withUnsafePointer(to: amp;self.testClass.getterSetter) {
                    print("Address of computed variable: (String(format: "%p", $0.pointee))")
                }
                print("*****")
            })
            .disposed(by: DisposeBag())
    }
}
 

Доступ к значению переменной getterSetter осуществляется и устанавливается внутри функции demoMethod с помощью простого наблюдаемого, которое, в свою очередь, изменяет a на «Я здесь». Я печатаю адреса переменной TestClass и getterSetter внутри функции demoMethod, а также после того, как эта функция вернется.

Пожалуйста, взгляните на ссылку здесь, которая показывает результат.

Вывод здесь

Как мы видим из изображения, адрес экземпляра TestClass остается тем же, что и ожидалось. Но адрес переменной getterSetter отображается по-разному при каждой печати, что не имеет смысла, поскольку закрытая переменная a изменяется на «Я здесь» (можно увидеть в выходной ссылке), подразумевая, что они должны указывать на одну и ту же память.

Если я удалю self.TestClass.getterSetter = «Я здесь» из demoMethod, он начнет выдавать правильные и одинаковые адреса памяти, как это:

Обновленные Выходные данные

  • Я считаю, что это как-то связано с механизмом копирования при записи, но я не могу точно понять, что именно. Если исходный экземпляр копируется в новую память, когда я выполняю self.TestClass.getterSetter = «Я здесь», то как получилось, что значение a изменилось по исходному адресу памяти?
  • Итак, что именно здесь происходит и как распределяется память?

P.S. Кроме того, то же самое наблюдается, когда я использую struct TestClass вместо класса TestClass, с той лишь разницей, что я печатаю с помощью print(«Адрес тестового класса: (Строка(формат: «%p», Небезопасная передача(self.TestClass, в: String.self)))»)

Комментарии:

1. Сможете ли вы воспроизвести его, если исключите rx-swift из уравнения?

2. @de. Да, та же проблема возникает даже без использования rx-swift.

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