简体   繁体   中英

Swift 3.0: “objc_setAssociatedObject” issue

import UIKit
import ObjectiveC

var SubRowObjectKey: String = "subRow"
extension IndexPath {

    var subRow: Int {
        get {
            let subRowObj = objc_getAssociatedObject(self, &SubRowObjectKey)

            if subRowObj != nil {
                return (subRowObj as! Int)
            }

            return 0
        }
        set {
            let subRowObj = (newValue as NSInteger)
            objc_setAssociatedObject(self, &SubRowObjectKey, subRowObj, .OBJC_ASSOCIATION_RETAIN)

        }
    }

    static func indexPathForSubRow(_ subRow: NSInteger, inRow row: NSInteger, inSection section: NSInteger) -> IndexPath {

        var indexPath = IndexPath(row: row, section: section)
        indexPath.subRow = (subRow as Int)
        print(subRow)
        print(indexPath.subRow)
        return indexPath
    }
}

let indexPath = IndexPath.indexPathForSubRow(5, inRow: 1, inSection: 2)
print(indexPath.subRow)

在此输入图像描述

  • In static func indexPathForSubRow -> 'subRow' Count = 5 (line no: 30 in attached image)
  • But after assigning subRow to indexPath.subRow, 'indexPath.subRow' count = 0 instead of 5 (line no 29 & 31 in attached image)
  • Tested in Xcode version 8.2.1 & Swift 3.0

    Any help will be appreciated.

IndexPath is a struct, which don't support associated objects. You can easily check it in the setter by directly trying to read back the set object:

set {
    let subRowObj = (newValue as NSInteger)
    objc_setAssociatedObject(self, &SubRowObjectKey, subRowObj, .OBJC_ASSOCIATION_RETAIN)
    let subRowObj2 = objc_getAssociatedObject(self, &SubRowObjectKey)
    print(subRowObj2 ?? "nil") // prints "nil"
}

Even if the code in the setter would have worked , the whole construct still doesn't hold: Since structs are copied when transferred / assigned (at least when modified via copy on write mechanism), your associated objects won't be included in that copy, so you'll lose that information anyhow, sooner or later.

Nevertheless, instead of extending IndexPath you could extend NSIndexPath which then works fine -- but I guess this is not what you want, because you want to influence the IndexPath that you get from a table view...

Based on maddy's answer this is my IndexPath extension that adds a subRow property.

extension IndexPath {

    init(subRow: Int, row: Int, section: Int) {
        self.init(indexes: [IndexPath.Element(section), IndexPath.Element(row), IndexPath.Element(subRow)])
    }

    var subRow: Int {
        get { return self[index(at: 2)] }
        set { self[index(at: 2)] = newValue }
    }

    var row: Int {
        get { return self[index(at: 1)] }
        set { self[index(at: 1)] = newValue }
    }

    var section: Int {
        get { return self[index(at: 0)] }
        set { self[index(at: 0)] = newValue }
    }

    private func index(at idx: Int) -> IndexPath.Index {
        return self.startIndex.advanced(by: idx)
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM