第48周筆記總結(jié)(一)

一屎鳍、CFMutableDictionaryRef的使用

最近在看YYModel的源碼蝎抽,發(fā)現(xiàn)其中多次使用了CFMutableDictionaryRef來對類相關(guān)信息進行緩存斟赚。為此舍肠,對CFMutableDictionaryRef進行了一番探討侦讨。

1. CFMutableDictionaryRef的介紹

CFMutableDictionaryRef是Core-Foundation框架下的一個集合,它提供C語言接口儒士,與我們常用的Foundation框架的NSMutableDictionary類似的止,只不過我們使用的NSMutableDictionary的接口對應(yīng)是OC接口。

2.CFMutableDictionaryRef的使用

CFMutableDictionaryRef的使用和我們常用的NSMutableDictionary是非常相似的着撩,唯一要注意的一點就是由于CFMutableDictionaryRef使用的C語言接口诅福,因此我們需要將對象類型進行橋接,轉(zhuǎn)換為C類型拖叙。

CFMutableDictionaryRef myDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
NSString *key = @"someKey";
NSNumber *value = [NSNumber numberWithInt: 1];
//set
CFDictionarySetValue(myDict, (__bridge void *)key, (__bridge void *)value);
//get
id dictValue = (__bridge id)CFDictionaryGetValue(myDict, (__bridge void *)key);
//remove
CFDictionaryRemoveValue(myDict, (__bridge void *)key);
3. NSMutableDictionary vs CFMutableDictionaryRef

兩者都是字典的實現(xiàn)類氓润,只不過兩者是使用的接口不同,有一個比較重要的區(qū)別是NSMutableDictionary要求key必須實現(xiàn)了NSCopying協(xié)議薯鳍,而CFMutableDictionaryRef是沒有這個要求的咖气。

//NSMutableDictionary
- (void)setObject:(id)anObject forKey:(id <NSCopying>)aKey;

//CFMutableDictionaryRef
CF_EXPORT
void CFDictionarySetValue(CFMutableDictionaryRef theDict, const void *key, const void *value);

4.CFMutableDictionaryRef的應(yīng)用場景

CFMutableDictionaryRef使用比較多的場景是作為cache緩存一些沒有實現(xiàn)NSCopying協(xié)議的key,比如在YYModel中,作者是使用Class為key進行緩存采章,顯然Class對象并沒有實現(xiàn)NSCopying協(xié)議运嗜。

+ (instancetype)metaWithClass:(Class)cls {
    if (!cls) return nil;
    //定義相關(guān)變量
    static CFMutableDictionaryRef cache;
    static dispatch_once_t onceToken;
    static dispatch_semaphore_t lock;

    dispatch_once(&onceToken, ^{
        //創(chuàng)建緩存
        cache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
        lock = dispatch_semaphore_create(1); //創(chuàng)建鎖
    });
    
    //從緩存中獲取內(nèi)容
    dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); //開啟鎖
    _YYModelMeta *meta = CFDictionaryGetValue(cache, (__bridge const void *)(cls)); //從緩存中獲取
    dispatch_semaphore_signal(lock); //關(guān)閉鎖

    //更新緩存內(nèi)容
    if (!meta || meta->_classInfo.needUpdate) { //若緩存中不存在或類相關(guān)信息需要更新
        meta = [[_YYModelMeta alloc] initWithClass:cls]; //重新獲取
        if (meta) {
            dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
            CFDictionarySetValue(cache, (__bridge const void *)(cls), (__bridge const void *)(meta)); //設(shè)置緩存
            dispatch_semaphore_signal(lock);
        }
    }
    return meta;
}

二、class類型的判斷

我們常用的class類型判斷的方法有三種:isMemberOfClass悯舟、isKindOfClass和isSubclassOfClass.接下來我們使用三個不同的類担租,來查看三種不同方法的區(qū)別.

@interface RootItem : NSObject
@end
@implementation RootItem
@end

@interface SubItem : RootItem
@end
@implementation SubItem
@end

@implementation ClassDemo

- (void)classTypeTest {
    NSObject *obj = [NSObject new];
    RootItem *root = [RootItem new];
    SubItem *sub = [SubItem new];
    if ([obj isMemberOfClass:[RootItem class]]) {
        NSLog(@"obj isMemberOfClass [RootIem Class]");
    } else {
        NSLog(@"obj isNotMemberOfClass [RootIem Class]");
    }
    if ([root isMemberOfClass:[RootItem class]]) {
        NSLog(@"root isMemberOfClass [RootItem Class]");
    } else {
        NSLog(@"root isNotMemberOfClass [RootItem Class]");
    }
    if ([sub isMemberOfClass:[RootItem class]]) {
        NSLog(@"sub isMemberOfClass [RootItem Class]");
    } else {
        NSLog(@"sub isNotMemberOfClass [RootItem Class]");
    }
    
    if ([obj isKindOfClass:[RootItem class]]) {
        NSLog(@"obj isKindOfClass [RootIem Class]");
    } else {
        NSLog(@"obj isNotKindOfClass [RootIem Class]");
    }
    if ([root isKindOfClass:[RootItem class]]) {
        NSLog(@"root isKindOfClass [RootIem Class]");
    } else {
        NSLog(@"root isNotKindOfClass [RootIem Class]");
    }
    if ([sub isKindOfClass:[RootItem class]]) {
        NSLog(@"sub isKindOfClass [RootIem Class]");
    } else {
        NSLog(@"sub isNotKindOfClass [RootIem Class]");
    }
    
    if ([NSObject isSubclassOfClass:[RootItem class]]) {
        NSLog(@"NSObject isSubclassOfClass [RootIem Class]");
    } else {
        NSLog(@"NSObject isNotSubclassOfClass [RootIem Class]");
    }
    if ([RootItem isSubclassOfClass:[RootItem class]]) {
        NSLog(@"RooItem isSubclassOfClass [RootIem Class]");
    } else {
        NSLog(@"RooItem isNotSubclassOfClass [RootIem Class]");
    }
    if ([SubItem isSubclassOfClass:[RootItem class]]) {
        NSLog(@"SubItem isSubclassOfClass [RootIem Class]");
    } else {
        NSLog(@"SubItem isNotSubclassOfClass [RootIem Class]");
    }
}
@end

輸出:
2018-12-01 16:55:38.599310+0800 Note[5434:3102432] obj isNotMemberOfClass [RootIem Class]
2018-12-01 16:55:38.599434+0800 Note[5434:3102432] root isMemberOfClass [RootItem Class]
2018-12-01 16:55:38.599500+0800 Note[5434:3102432] sub isNotMemberOfClass [RootItem Class]

2018-12-01 16:55:38.599556+0800 Note[5434:3102432] obj isNotKindOfClass [RootIem Class]
2018-12-01 16:55:38.599627+0800 Note[5434:3102432] root isKindOfClass [RootIem Class]
2018-12-01 16:55:38.599713+0800 Note[5434:3102432] sub isKindOfClass [RootIem Class]

2018-12-01 16:55:38.599787+0800 Note[5434:3102432] NSObject isNotSubclassOfClass [RootIem Class]
2018-12-01 16:55:38.599860+0800 Note[5434:3102432] RooItem isSubclassOfClass [RootIem Class]
2018-12-01 16:55:38.599930+0800 Note[5434:3102432] SubItem isSubclassOfClass [RootIem Class]

根據(jù)上面的輸出,1-3行可以判斷:
isMemberOfClass是對象實例的判斷方法抵怎,它只有在對象為當(dāng)前類的實例時奋救,才返回true.
由4-6行,可以判斷:
isKindOfClass是對象實例的判斷方法反惕,它在對象為當(dāng)前類或子類的實例時尝艘,都會返回ture.
由7-9行,可以判斷:
isSubclassOfClass是對象類的判斷方法姿染,是一個類方法背亥,它在類為當(dāng)前類或子類時,返回true.

總結(jié):

我們比較常用的是isKindOfClass方法悬赏,用于判斷是否為當(dāng)前的class或class的子類.

對于isMemberOfClass方法狡汉,是用于判斷是否為當(dāng)前的class,相當(dāng)于更為嚴格的isKindOfClass方法.

而isSubclassOfClass是一個類方法闽颇,通常用于類之間判斷是否存在繼承關(guān)系.

屬性(property)和成員變量(ivar)之間的區(qū)別

比較直接理解的方法可以看做:property = ivar + setter + getter.通常來說盾戴,我們都是用屬性去定義變量,當(dāng)然對于一些私有變量兵多,如果需要考慮性能尖啡,我們可以使用ivar來避免setter和getter帶來的性能消耗.

Core-Foundation集合的遍歷

在Core-Foundation集合中我們比較常用的是CFDictionary和CFArray,這就涉及到集合的遍歷問題剩膘,CF集合的遍歷方式與NS集合的遍歷方式有很大的區(qū)別.

CFDictionaryRef的遍歷

CFDictionaryRef的遍歷原型:

void CFDictionaryApplyFunction(CFDictionaryRef theDict, CFDictionaryApplierFunction CF_NOESCAPE applier, void *context);

這里比較重要的是第二個參數(shù)衅斩,是一個需要定義的遍歷函數(shù):

typedef void (*CFDictionaryApplierFunction)(const void *key, const void *value, void *context);

第三個參數(shù)是額外的參數(shù),如果需要傳入援雇,需要通過__bridge轉(zhuǎn)換為void *類型

@interface CFItem : NSObject
@property (nonatomic, copy) NSString *itemname;
@property (nonatomic, assign) NSInteger itemnum;
+ (instancetype)createCFItemWithname:(NSString *)name num:(NSInteger)num;
@end

@implementation CFItem
+ (instancetype)createCFItemWithname:(NSString *)name num:(NSInteger)num {
    CFItem *item = [CFItem new];
    item.itemname = name;
    item.itemnum = num;
    return item;
}
@end

static void printDict (const void *_key, const void *_value, void *context) {
    NSString *key = (__bridge NSString *)_key;
    CFItem *value = (__bridge CFItem *)_value;
    NSLog(@"dict[%@] = %@", key, @{@"name":value.itemname, @"num":@(value.itemnum)});
}

+ (void)cfDictTest {
    CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    CFDictionarySetValue(dict, (__bridge void *)(@"key1"), (__bridge void *)([CFItem createCFItemWithname:@"item1" num:1]));
    CFDictionarySetValue(dict, (__bridge void *)(@"key2"), (__bridge void *)([CFItem createCFItemWithname:@"item2" num:2]));
    CFDictionarySetValue(dict, (__bridge void *)(@"key3"), (__bridge void *)([CFItem createCFItemWithname:@"item3" num:3]));
    
    CFDictionaryApplyFunction(dict, printDict, NULL);
}

輸出結(jié)果:
2018-12-09 12:17:51.758464+0800 Note[37238:7172086] dict[key1] = {
    name = item1;
    num = 1;
}
2018-12-09 12:17:51.758612+0800 Note[37238:7172086] dict[key3] = {
    name = item3;
    num = 3;
}
2018-12-09 12:17:51.758740+0800 Note[37238:7172086] dict[key2] = {
    name = item2;
    num = 2;
}
CFArrayRef的遍歷

CFArrayRef遍歷函數(shù)原型:

CF_EXPORT
void CFArrayApplyFunction(CFArrayRef theArray, CFRange range, CFArrayApplierFunction CF_NOESCAPE applier, void *context);

typedef void (*CFArrayApplierFunction)(const void *value, void *context);
static void printArr (const void *_value, void *context) {
    CFItem *value = (__bridge CFItem *)_value;
    NSLog(@"CFItem = %@", @{@"name":value.itemname, @"num":@(value.itemnum)});
}

+ (void)cfArrTest {
    CFMutableArrayRef arr = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
    CFArrayAppendValue(arr, (__bridge void *)([CFItem createCFItemWithname:@"item1" num:1]));
    CFArrayAppendValue(arr, (__bridge void *)([CFItem createCFItemWithname:@"item2" num:2]));
    CFArrayAppendValue(arr, (__bridge void *)([CFItem createCFItemWithname:@"item3" num:3]));
    CFArrayApplyFunction(arr, CFRangeMake(0, CFArrayGetCount(arr)), printArr, NULL);
}

輸出:
2018-12-09 12:17:51.758871+0800 Note[37238:7172086] CFItem = {
    name = item1;
    num = 1;
}
2018-12-09 12:17:51.758981+0800 Note[37238:7172086] CFItem = {
    name = item2;
    num = 2;
}
2018-12-09 12:17:51.759112+0800 Note[37238:7172086] CFItem = {
    name = item3;
    num = 3;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末矛渴,一起剝皮案震驚了整個濱河市椎扬,隨后出現(xiàn)的幾起案子惫搏,更是在濱河造成了極大的恐慌,老刑警劉巖蚕涤,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件筐赔,死亡現(xiàn)場離奇詭異,居然都是意外死亡揖铜,警方通過查閱死者的電腦和手機茴丰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人贿肩,你說我怎么就攤上這事峦椰。” “怎么了汰规?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵汤功,是天一觀的道長。 經(jīng)常有香客問我溜哮,道長滔金,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任茂嗓,我火速辦了婚禮餐茵,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘述吸。我一直安慰自己忿族,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布蝌矛。 她就那樣靜靜地躺著肠阱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪朴读。 梳的紋絲不亂的頭發(fā)上屹徘,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天,我揣著相機與錄音衅金,去河邊找鬼噪伊。 笑死,一個胖子當(dāng)著我的面吹牛氮唯,可吹牛的內(nèi)容都是我干的鉴吹。 我是一名探鬼主播,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼惩琉,長吁一口氣:“原來是場噩夢啊……” “哼豆励!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起瞒渠,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤良蒸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后伍玖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嫩痰,經(jīng)...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年窍箍,在試婚紗的時候發(fā)現(xiàn)自己被綠了串纺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丽旅。...
    茶點故事閱讀 38,768評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖纺棺,靈堂內(nèi)的尸體忽然破棺而出榄笙,到底是詐尸還是另有隱情,我是刑警寧澤祷蝌,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布办斑,位于F島的核電站,受9級特大地震影響杆逗,放射性物質(zhì)發(fā)生泄漏乡翅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一罪郊、第九天 我趴在偏房一處隱蔽的房頂上張望蠕蚜。 院中可真熱鬧,春花似錦悔橄、人聲如沸靶累。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挣柬。三九已至,卻和暖如春睛挚,著一層夾襖步出監(jiān)牢的瞬間邪蛔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工扎狱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留侧到,地道東北人。 一個月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓淤击,卻偏偏與公主長得像匠抗,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子污抬,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,666評論 2 350

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

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,093評論 1 32
  • 1.設(shè)計模式是什么印机? 你知道哪些設(shè)計模式矢腻,并簡要敘述?設(shè)計模式是一種編碼經(jīng)驗耳贬,就是用比較成熟的邏輯去處理某一種類型...
    龍飝閱讀 2,140評論 0 12
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉踏堡,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,690評論 0 9
  • 強化學(xué)習(xí)的作用在于通過當(dāng)前的環(huán)境做出相應(yīng)的action猎唁,得到最大的value如TensorFlow實戰(zhàn)中的例子: ...
    碧影江白閱讀 12,377評論 0 1
  • 百日目標(biāo)檢視(0406-0715)孫-鄭州 百日目標(biāo)檢視(目標(biāo)/實現(xiàn)狀況) 1.每天堅持夏說晨讀咒劲,大約2小時顷蟆,努力...
    泊韌知行合一閱讀 299評論 1 6