Swift中通過OC運(yùn)行時(shí)給系統(tǒng)類添加閉包屬性

Swift中通過OC的運(yùn)行時(shí)給系統(tǒng)的類添加閉包屬性 | 使用類擴(kuò)展(extension)

Swift中使用typealias定義一個(gè)閉包(無(wú)返回值穗椅,有一個(gè)數(shù)組類型參數(shù))

typealias XYRearrangeNewDataBlock = (_ newData: [Any]) -> Void

OC 使用typedef定義(無(wú)返回值,有一個(gè)數(shù)組類型參數(shù))

typedef void(^XYRollNewDataBlock)(NSArray * newData);

在Swift類擴(kuò)展中聲明閉包屬性
由于Swift擴(kuò)展不接受這些存儲(chǔ)的屬性垂谢,所以可以通過關(guān)聯(lián)屬性存儲(chǔ)屬性,比如下面給UICollectionView的擴(kuò)展增加兩個(gè)閉包屬性
(錯(cuò)誤寫法风钻,如果非閉包屬性可以這么筐高,由于寫習(xí)慣了OC赃阀,由于Swift不熟練,下面這個(gè)錯(cuò)誤我搞了3個(gè)小時(shí)才解決趾痘,記錄是為了自己不再次出錯(cuò))

public extension UICollectionView {

    typealias XYRearrangeNewDataBlock = () -> Void
    typealias XYRearrangeOriginaDataBlock = () -> [String]
    
    // MARK:- 關(guān)聯(lián)屬性的key
    struct xy_associatedKeys {
        static var originalDataBlockKey = "originalDataBlockKey"
        static var newDataBlockKey = "newDataBlockKey"
    }
     // 聲明閉包屬性慢哈,并通過set函數(shù)與當(dāng)前類產(chǎn)生關(guān)聯(lián),get函數(shù)獲取關(guān)聯(lián)
    var originalDataBlock : XYRearrangeNewDataBlock? {
        get {
            if let originalDataBlock = objc_getAssociatedObject(self, &xy_associatedKeys.originalDataBlockKey) as? XYRearrangeNewDataBlock {
                return originalDataBlock
            }
            return nil
        }
        set(newValue) {
? 總是在set函數(shù)中報(bào)編譯錯(cuò)誤
            objc_setAssociatedObject(self, &xy_associatedKeys.originalDataBlockKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
        }
    }
    var newDataBlock: XYRearrangeNewDataBlock? {
        get {
            if let newDataBlock = objc_getAssociatedObject(self, &xy_associatedKeys.newDataBlockKey) as? XYRearrangeNewDataBlock {
                return newDataBlock
            }
            return nil
        }
        
        set(newValue) {
            objc_setAssociatedObject(self, xy_associatedKeys.newDataBlockKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
        }
  
    }
   
   // 將閉包屬性作為便利構(gòu)造函數(shù)的參數(shù)
    convenience init(collectionVewFlowLayout : UICollectionViewFlowLayout, originalDataBlock: XYRearrangeOriginaDataBlock, newDataBlock: XYRearrangeNewDataBlock) {
        self.init()     
    }
}

錯(cuò)誤信息:
Command failed due to signal: Segmentation fault: 11
在Swift的類擴(kuò)展中關(guān)聯(lián)閉包block屬性時(shí)永票,總是報(bào)編譯失敗錯(cuò)誤卵贱,最終把錯(cuò)誤定義在objc_setAssociatedObject關(guān)聯(lián)閉包屬性時(shí)

Snip20161110_2.png

解決方法:
要先定義一個(gè)類屬性作為閉包容器,專門存放閉包的屬性侣集,以下是正確的在extension中給類添加閉包屬性的方法
注意: 如果便利構(gòu)造函數(shù)中有閉包參數(shù)艰赞,外界調(diào)用這個(gè)方法時(shí),需要自己把閉包參數(shù)改為大括號(hào){}

以下是正確添加關(guān)聯(lián)閉包屬性的方法

import UIKit
public extension UICollectionView {

    typealias XYRearrangeNewDataBlock = () -> Void
    typealias XYRearrangeOriginaDataBlock = () -> [String]

    // MARK:- 關(guān)聯(lián)屬性的key
    private struct xy_associatedKeys {
        static var originalDataBlockKey = "xy_originalDataBlockKey"
        static var newDataBlockKey = "xy_newDataBlockKey"
    }
    
    // 定義一個(gè)類屬性作為閉包的容器肚吏,專門存放閉包的屬性
    private class BlockContainer: NSObject, NSCopying {
          func copy(with zone: NSZone? = nil) -> Any {
                return self
          }
        var rearrangeNewDataBlock: XYRearrangeNewDataBlock?
        var rearrangeOriginaDataBlock: XYRearrangeOriginaDataBlock?
    }
    
    // 定義個(gè)一個(gè)計(jì)算屬性方妖,通過OC的運(yùn)行時(shí)獲取關(guān)聯(lián)對(duì)象和設(shè)置關(guān)聯(lián)對(duì)象
    private var newDataBlock: BlockContainer? {
        get {
            if let newDataBlock = objc_getAssociatedObject(self, &xy_associatedKeys.newDataBlockKey) as? BlockContainer {
                return newDataBlock
            }
            return nil
        }
        
        // 如果計(jì)算屬性的setter沒有定義表示新值的參數(shù)名,則可以用默認(rèn)值newValue
        set(newValue) {
            objc_setAssociatedObject(self, xy_associatedKeys.newDataBlockKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
        }
    }
   
    
    // 通過外界調(diào)用便利構(gòu)造函數(shù)時(shí)罚攀,給閉包屬性賦值
    convenience init(collectionVewFlowLayout : UICollectionViewFlowLayout, originalDataBlock: @escaping XYRearrangeOriginaDataBlock, newDataBlock:  @escaping XYRearrangeNewDataBlock) {
        self.init()
        
        // 創(chuàng)建blockContainer,將外界傳來的閉包賦值給類屬性中的閉包變量
        let blockContainer: BlockContainer = BlockContainer()
        blockContainer.rearrangeNewDataBlock = newDataBlock
        blockContainer.rearrangeOriginaDataBlock = originalDataBlock
        self.newDataBlock = blockContainer
    }
}

以下是與今天遇到的錯(cuò)誤有關(guān)的Swift基礎(chǔ)知識(shí)點(diǎn)

  • 計(jì)算屬性
    1.Swift中的計(jì)算屬性不直接存儲(chǔ)值
    跟存儲(chǔ)屬性不同,沒有任何的”后端存儲(chǔ)與之對(duì)應(yīng)”
    2.計(jì)算屬性用于計(jì)算, 提供一個(gè)getter和一個(gè)可選的setter來間接獲取党觅、設(shè)置其他屬性和變量的值雌澄。如果計(jì)算屬性的setter沒有定義表示新值的參數(shù)名,則可以用默認(rèn)值
    3.枚舉不可以有存儲(chǔ)屬性, 但是允許有計(jì)算屬性
  • 結(jié)構(gòu)體和類常量與存儲(chǔ)屬性的關(guān)系
    結(jié)構(gòu)體和枚舉是值類型 ,因此不能修改結(jié)構(gòu)體常量中的屬性
    不能修改結(jié)構(gòu)體/枚舉常量對(duì)象中的值, 因?yàn)樗赶虻膶?duì)象是一個(gè)常量
    類是引用類型 ,可以修改類常量中屬性的值, 因?yàn)樗赶虻膶?duì)象不是一個(gè)常量
struct Person2 { // 結(jié)構(gòu)體
    var name: String
    var age: Int
}
let p2: Person2 = Person2(name: "cdh", age: 20)
//因?yàn)榻Y(jié)構(gòu)體是值類型, 所以不能修改結(jié)構(gòu)體常量中的屬性
//不能修改結(jié)構(gòu)體/枚舉常量對(duì)象中的值, 因?yàn)樗赶虻膶?duì)象是一個(gè)常量
//以下寫法錯(cuò)誤
//p2.name = "CDH" //不能修改結(jié)構(gòu)體常量對(duì)象的值
//以下寫法錯(cuò)誤
//p2 = Person2(name: "CDH", age: 50)

class Person3 { // 類屬性
    var name: String = "cdh"
    var age: Int = 20
}
let p3:Person3 = Person3()
//可以修改類常量中屬性的值, 因?yàn)樗赶虻膶?duì)象不是一個(gè)常量
p3.name = "CDH"
//不可以修改類常量的指向
//以下寫法是錯(cuò)誤的
//p3 = Person4()

  • 類屬性

在結(jié)構(gòu)體和枚舉中用static
在類中使用class, 并且類中不允許將存儲(chǔ)屬性設(shè)置為類屬性

struct Person4 {
//    普通的屬性是每個(gè)對(duì)象一份
    var name: String = "cdh"
//    類屬性是所有相同類對(duì)象共用一份
    static var gender:String = "man"
    static var age:Int{
        return 20
    }
    func show()
    {
        print("gender = \(Person4.gender) name = \(name)")
    }
}
var p4 = Person4()
print("gender = \(Person4.gender)")
//輸出結(jié)果: gender = man
var p5 = Person4()
//類屬性是所有對(duì)象共用一份
print("gender = \(Person4.gender)")
p5.show()
//輸出結(jié)果:
//gender = man
//gender = man name = cdh
//可以將計(jì)算屬性設(shè)置為類屬性
print("age = \(Person4.age)")
//輸出結(jié)果:age = 20
class Person5 {
//    普通的屬性是每個(gè)對(duì)象一份
    var name: String = "cdh"
//    類中不允許將存儲(chǔ)屬性定義為類屬性
//    下面為錯(cuò)誤寫法
//    class var gender:String = "man"
//    類中只能將計(jì)算屬性定義為類屬性
    class var age:Int{
        return 20
    }
    func show()
    {
        print("age = \(Person5.age)")
    }
}
var p6 = Person5()
print("age = \(Person5.age)")
p6.show()
//輸出結(jié)果:
//age = 20
//age = 20
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末杯瞻,一起剝皮案震驚了整個(gè)濱河市镐牺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌魁莉,老刑警劉巖睬涧,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異旗唁,居然都是意外死亡畦浓,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門检疫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來讶请,“玉大人,你說我怎么就攤上這事屎媳《嵋纾” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵烛谊,是天一觀的道長(zhǎng)风响。 經(jīng)常有香客問我,道長(zhǎng)丹禀,這世上最難降的妖魔是什么钞诡? 我笑而不...
    開封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮湃崩,結(jié)果婚禮上荧降,老公的妹妹穿的比我還像新娘。我一直安慰自己攒读,他們只是感情好朵诫,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著薄扁,像睡著了一般剪返。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上邓梅,一...
    開封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天脱盲,我揣著相機(jī)與錄音,去河邊找鬼日缨。 笑死钱反,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播面哥,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼哎壳,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了尚卫?” 一聲冷哼從身側(cè)響起归榕,我...
    開封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎吱涉,沒想到半個(gè)月后刹泄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡怎爵,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年特石,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疙咸。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖风科,靈堂內(nèi)的尸體忽然破棺而出撒轮,到底是詐尸還是另有隱情,我是刑警寧澤贼穆,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布题山,位于F島的核電站,受9級(jí)特大地震影響故痊,放射性物質(zhì)發(fā)生泄漏顶瞳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一愕秫、第九天 我趴在偏房一處隱蔽的房頂上張望慨菱。 院中可真熱鬧,春花似錦戴甩、人聲如沸符喝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)协饲。三九已至,卻和暖如春缴川,著一層夾襖步出監(jiān)牢的瞬間茉稠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工把夸, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留而线,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像吞获,于是被迫代替她去往敵國(guó)和親况凉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容