Search code examples
swift2closurescaptureself

Swift 2.0 - variable copied in closure?


I have an array of dictionaries class instance, outlined below:

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]
    }    
}

why is the address of array is changed (0x000000015cf0ebd0 vs 0x000000015cd10c50) as I just capture it in UITableViewRowAction initialization?

Thanks,


Solution

  • It's a nature of unsafeAddressOf and Swift Arrays.

    A simplified example you can test in the Playground. (No closure, no strongSelf...)

    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)
    

    Tested in Xcode 7.3.1 (Swift 2.2.1) a few times and all printed "false".

    The signature of unsafeAddressOf is:

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

    As you know Swift Arrays are value types and you cannot pass them to AnyObject. So, when "bridging to Objective-C" feature is available, your array is converted to NSArray. This conversion is done in a "hard-to-predict" manner, which means, at any time this conversion is made, Swift may allocate a new NSArray instance.

    In general, you should not expect something "firm" from unsafeAddressOf when applied to Swift Arrays or other value types.