沒想到Swift裡KVC還能有坑

沒故事的卓同學發表於2019-02-24

沒想到Swift裡KVC還能有坑

#起因
最近看了@南峰子_老驢寫的ViewStyle。利用KVC的來簡化抽取出控制元件設定style的程式碼,想達到一個css的效果。這個庫用swift編寫,使用起來大概這樣:

class ViewController: UIViewController {

    var tableView: UITableView?

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView = UITableView(frame: self.view.bounds)

        tableView!.mi_styles = self.tableViewStyle

        self.view.addSubview(tableView!)
    }
}

// MARK: - Table View Style

extension ViewController {
    var tableViewStyle: [Property: Any] {
        return [
            .rowHeight: 60.0,
            .separatorStyle: UITableViewCellSeparatorStyle.singleLine,
            .separatorColor: UIColor.lightGray,
            .backgroundView: UIView(),
            .separatorInset: UIEdgeInsets(top: 10.0, left: 5.0, bottom: 3.0, right: 10.0),
            .cellLayoutMarginsFollowReadableWidth: true
        ]
    }
}複製程式碼

閱讀原始碼後發現有些屬性在swift是不能直接KVC的,和OC有些區別。

#Bool值:isHidden
先來看下正常的在swift中kvc的套路:

let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
view.setValue(UIColor.blue, forKey: #keyPath(UIView.backgroundColor))複製程式碼

在swift 3中提供了#keypath()來省去開發者直接輸入字串的尷尬。
然而,如果這個屬性是isHidden的話執行起來就會報錯。

沒想到Swift裡KVC還能有坑

控制檯會輸出錯誤:

`[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key isHidden.`

提示我們沒有isHidden這個屬性。
那為什麼我們平時沒有注意到這個問題呢?

view.isHidden = true複製程式碼

這麼寫程式碼是沒問題的。
其實就是Swift團隊在升級3.0的時候keypath忘記做這個功能了。。。

沒想到Swift裡KVC還能有坑

你可以安慰自己這個功能在swift 2.0的時候還是好好的。

如果讀者寫過OC這個原因很容易猜到。有些單獨宣告過getter的bool值直接kvc會報錯。比如isHidden這樣:

@property (nonatomic, getter=isHidden) BOOL hidden;複製程式碼

UIView上確實沒有isHidden屬性,那麼怎麼解決呢?只能回到老路上了:

view.setValue(true, forKey: "Hidden")複製程式碼

Enum

KVC在設定列舉的時候也會報錯。

沒想到Swift裡KVC還能有坑

錯誤提示的無效的引數型別。
因為setValue的引數型別是Any,所以這裡引數可以是任意型別,沒有型別檢查。但是這畢竟是一個OC的方法,所以無法直接使用swift的型別(其實String到NSString也是有轉換的,只是編譯器幫我們做了這層轉換)。
前面直接賦值的時候是正常的,但是呼叫KVC方法的時候編譯器沒有幫我們轉。所以這裡報錯了。
那就只能自己手動轉換了:

view.setValue(UIViewTintAdjustmentMode.automatic.rawValue, forKey: "tintAdjustmentMode")複製程式碼

在OC中的列舉其實就是對應幾個數值,這裡直接取出rawValue的值就可以正常使用了。

最後我有一句話想對swift說:

沒想到Swift裡KVC還能有坑

歡迎關注我的微博:@沒故事的卓同學

相關文章