Swift快速爲類擴展屬性

在程序編寫過程當中,咱們經常須要爲已有的類擴展新的屬性。一般咱們的解決辦法是先聲明一個Key,而後使用 objc_getAssociatedObjectobjc_setAssociatedObject來設置屬性。相對來講比較麻煩,由於擴展屬性的需求比較大,因此筆者對這兩個方法作了一些封裝,減小了不少代碼。

使用

首先咱們來看看封裝後如何使用。swift

  • 把Property.swift拖到你的項目中
  • 讓類/Protocol 繼承 Property
  • 聲明你的屬性,get/set參照以下代碼
extension View:Property{
    var margin : Int{
        get{ return get0() }
        set{ set0(newValue)}
    }
}

是否是很是簡單?不過在使用這個Property以前,必定要看清楚注意事項哦。
Property裏面默認封裝了設置三個屬性的方法。
擴展前三個屬性的時候分別是 get0() & set0()、get1() & set1()、get2() & set2()
那麼超過三個屬性應該如何設置呢?數組

  • 方案1:擴展Property的方法。
  • 方案2:使用Property默認的get() set(),而且須要傳入一個變量指針,參考以下代碼:
var test : String{
        get{ return get(&keyPoint) }
        set{ set(&keyPoint, newValue)}
    }

也仍是比較簡單的,畢竟爲一個類擴展超過三個以上的屬性的需求仍是比較小的。測試

封裝過程

首先咱們看看,擴展屬性一般使用的代碼指針

struct XKeys {
    static var common : String = "common"
}
extension AbstractProtocol{
    var common : String{
        get{
            return objc_getAssociatedObject(self, &XKeys.common) as! String
        }
        set{
            objc_setAssociatedObject(self, &XKeys.common, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }

在複製粘貼了屢次這樣的代碼以後,我實在厭倦了這樣擴展屬性的方式,而後開始了本身的封裝。
首先我發現聲明一個Key以後,能夠給多個類共用,沒有任何影響,可是若是同一個類的不一樣屬性,使用了相同的Key,就會有問題了。因此首先要保證同一個類,擴展出來的不一樣屬性的key值必需要不一樣。
因此我想到用一個數組來保存key,不過很惋惜失敗了。code

最開始封裝Property的時候是直接聲明瞭一個類,寫了一些靜態方法。而後在get set中調用。對象

class Property2 {
    static func get<T : Any>(_ key: UnsafeRawPointer) -> T{
        return objc_getAssociatedObject(self, key) as! T
    }
    static func set<T : Any>(_ key: UnsafeRawPointer,_ newValue : T) {
        objc_setAssociatedObject(self, key, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
}

不過測試過程當中發現一些問題,這個self實際應該使用被擴展的對象的類的self,因此通過修改後,代碼以下:繼承

class Property2 {
    static func get<T : Any>(_ o : Any, _ key: UnsafeRawPointer) -> T{
        return objc_getAssociatedObject(o, key) as! T
    }
    static func set<T : Any>(_ o : Any, _ key: UnsafeRawPointer,_ newValue : T) {
        objc_setAssociatedObject(o, key, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
}

調用的時候:ci

var common : String{
    get{
        return Property2.get(self, &XKeys.common)
    }
    set{
        Property2.set(self, &XKeys.common, newValue)
    }
}

感受封裝了跟沒封裝基本差很少啊。
有沒有辦法能省略Property和self呢,因而我想到了Protocol,而後讓類去繼承個人Property,這樣就能夠省略掉這兩項了。不過Key仍是要傳遞,因此我默認聲明瞭三個key,再提供一個須要傳遞key的方法。最後封裝好的代碼爲:get

//  Property.swift
//
//  Created by Fancy on 26/1/18.
//  Copyright © 2018年 Artifex Software, Inc. All rights reserved.

import UIKit
struct PropertyKey{
    static var key0 : Void?
    static var key1 : Void?
    static var key2 : Void?
}

protocol Property{}
extension Property{
    func get<T : Any>(_ key: UnsafeRawPointer) -> T{
        return objc_getAssociatedObject(self, key) as! T
    }
    func set<T : Any>(_ key: UnsafeRawPointer,_ newValue : T) {
        objc_setAssociatedObject(self, key, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
    func get0<T : Any>() -> T{
        return objc_getAssociatedObject(self, &PropertyKey.key0) as! T
    }
    func set0<T : Any>(_ newValue : T) {
        objc_setAssociatedObject(self, &PropertyKey.key0, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
    func get1<T : Any>() -> T{
        return objc_getAssociatedObject(self, &PropertyKey.key1) as! T
    }
    func set1<T : Any>(_ newValue : T) {
        objc_setAssociatedObject(self, &PropertyKey.key1, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
    func get2<T : Any>() -> T{
        return objc_getAssociatedObject(self, &PropertyKey.key2) as! T
    }
    func set2<T : Any>(_ newValue : T) {
        objc_setAssociatedObject(self, &PropertyKey.key2, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
}

結語

整個封裝過程沒有什麼高科技含量的操做,寫文章作點記錄,但願能給到須要的人幫助。it

相關文章
相關標籤/搜索