Swift 2.0 - переменная скопирована в закрытии?

У меня есть массив экземпляров класса словарей, описанный ниже:

class SomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    private var array = [[String: AnyObject]]()

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    // tableview delegates

    func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
        print(“array address: \(unsafeAddressOf(array))”) // 0x000000015cf0ebd0

        let option = UITableViewRowAction(style: .Default, title: “Option”, handler: { [weak self] (_, _) in
            guard let strongSelf = self else { return }

            print(“array address1: \(unsafeAddressOf(strongSelf.array))” // 0x000000015cd10c50
        })

        return [option]
    }    
}

почему адрес array изменен (0x000000015cf0ebd0 против 0x000000015cd10c50), поскольку я просто фиксирую его при инициализации UITableViewRowAction?

Спасибо,


person quanguyen    schedule 10.07.2016    source источник


Ответы (2)


Это природа unsafeAddressOf и массивов Swift.

Упрощенный пример, который вы можете протестировать на игровой площадке. (Нет замыкания, нет сильного Я...)

import Foundation

var str = "Hello, playground"
class MyClass {
    var array = [[String: AnyObject]]()

}

let obj1 = MyClass()

let ptr1 = unsafeAddressOf(obj1.array)
let ptr2 = unsafeAddressOf(obj1.array)

print(ptr1 == ptr2)

Протестировано в Xcode 7.3.1 (Swift 2.2.1) несколько раз, и все напечатано «false».

Подпись unsafeAddressOf:

func unsafeAddressOf(object: AnyObject) -> UnsafePointer<Void>

Как вы знаете, массивы Swift являются типами значений, и вы не можете передать их в AnyObject. Итак, когда доступна функция «связывания с Objective-C», ваш array преобразуется в NSArray. Это преобразование выполняется «трудно предсказуемым» образом, что означает, что в любой момент этого преобразования Swift может выделить новый экземпляр NSArray.

В общем, вы не должны ожидать чего-то «твердого» от unsafeAddressOf применительно к массивам Swift или другим типам значений.

person OOPer    schedule 10.07.2016
comment
Благодаря вашему вопросу, теперь я знаю, что Array имеет тип значения, я думал, что он должен быть типизирован по ссылке. Моя проблема: я обновляю array, но всегда не могу его обновить. Теперь я знаю, что работал с его копией, а не с настоящим array. Есть ли способ заставить компилятор использовать его в качестве ссылки? - person quanguyen; 10.07.2016
comment
Самый простой и надежный способ — объявить array как NSArray. Он теряет некоторую информацию о типе, но может содержать элементы [String: AnyObject], при необходимости может быть приведен к [[String: AnyObject]] с as!. Кто-то может показать вам больше предложений Swift, но они могут быть немного сложнее. - person OOPer; 10.07.2016

Поскольку вы присваиваете self переменной strongSelf, в результате чего значение self копируется в новую переменную.

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

Вы можете попробовать это, напечатав точно так же, как вы делаете это в первый раз:

print("array address: \(unsafeAddressOf(self.array))")

Вам нужно добавить self, чтобы получить доступ к члену класса array внутри замыкающего блока.

person Vladimir Nul    schedule 10.07.2016