美文网首页
第48周笔记总结(一)

第48周笔记总结(一)

作者: TreasureY_f7a3 | 来源:发表于2018-12-09 12:44 被阅读0次

    一、CFMutableDictionaryRef的使用

    最近在看YYModel的源码,发现其中多次使用了CFMutableDictionaryRef来对类相关信息进行缓存。为此,对CFMutableDictionaryRef进行了一番探讨。

    1. CFMutableDictionaryRef的介绍

    CFMutableDictionaryRef是Core-Foundation框架下的一个集合,它提供C语言接口,与我们常用的Foundation框架的NSMutableDictionary类似,只不过我们使用的NSMutableDictionary的接口对应是OC接口。

    2.CFMutableDictionaryRef的使用

    CFMutableDictionaryRef的使用和我们常用的NSMutableDictionary是非常相似的,唯一要注意的一点就是由于CFMutableDictionaryRef使用的C语言接口,因此我们需要将对象类型进行桥接,转换为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

    两者都是字典的实现类,只不过两者是使用的接口不同,有一个比较重要的区别是NSMutableDictionary要求key必须实现了NSCopying协议,而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的应用场景

    CFMutableDictionaryRef使用比较多的场景是作为cache缓存一些没有实现NSCopying协议的key,比如在YYModel中,作者是使用Class为key进行缓存,显然Class对象并没有实现NSCopying协议。

    + (instancetype)metaWithClass:(Class)cls {
        if (!cls) return nil;
        //定义相关变量
        static CFMutableDictionaryRef cache;
        static dispatch_once_t onceToken;
        static dispatch_semaphore_t lock;
    
        dispatch_once(&onceToken, ^{
            //创建缓存
            cache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
            lock = dispatch_semaphore_create(1); //创建锁
        });
        
        //从缓存中获取内容
        dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); //开启锁
        _YYModelMeta *meta = CFDictionaryGetValue(cache, (__bridge const void *)(cls)); //从缓存中获取
        dispatch_semaphore_signal(lock); //关闭锁
    
        //更新缓存内容
        if (!meta || meta->_classInfo.needUpdate) { //若缓存中不存在或类相关信息需要更新
            meta = [[_YYModelMeta alloc] initWithClass:cls]; //重新获取
            if (meta) {
                dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
                CFDictionarySetValue(cache, (__bridge const void *)(cls), (__bridge const void *)(meta)); //设置缓存
                dispatch_semaphore_signal(lock);
            }
        }
        return meta;
    }
    

    二、class类型的判断

    我们常用的class类型判断的方法有三种:isMemberOfClass、isKindOfClass和isSubclassOfClass.接下来我们使用三个不同的类,来查看三种不同方法的区别.

    @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]
    
    根据上面的输出,1-3行可以判断:
    isMemberOfClass是对象实例的判断方法,它只有在对象为当前类的实例时,才返回true.
    由4-6行,可以判断:
    isKindOfClass是对象实例的判断方法,它在对象为当前类或子类的实例时,都会返回ture.
    由7-9行,可以判断:
    isSubclassOfClass是对象类的判断方法,是一个类方法,它在类为当前类或子类时,返回true.
    

    总结:

    我们比较常用的是isKindOfClass方法,用于判断是否为当前的class或class的子类.

    对于isMemberOfClass方法,是用于判断是否为当前的class,相当于更为严格的isKindOfClass方法.

    而isSubclassOfClass是一个类方法,通常用于类之间判断是否存在继承关系.

    属性(property)和成员变量(ivar)之间的区别

    比较直接理解的方法可以看做:property = ivar + setter + getter.通常来说,我们都是用属性去定义变量,当然对于一些私有变量,如果需要考虑性能,我们可以使用ivar来避免setter和getter带来的性能消耗.

    Core-Foundation集合的遍历

    在Core-Foundation集合中我们比较常用的是CFDictionary和CFArray,这就涉及到集合的遍历问题,CF集合的遍历方式与NS集合的遍历方式有很大的区别.

    CFDictionaryRef的遍历

    CFDictionaryRef的遍历原型:

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

    这里比较重要的是第二个参数,是一个需要定义的遍历函数:

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

    第三个参数是额外的参数,如果需要传入,需要通过__bridge转换为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);
    }
    
    输出结果:
    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遍历函数原型:

    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;
    }
    

    相关文章

      网友评论

          本文标题:第48周笔记总结(一)

          本文链接:https://www.haomeiwen.com/subject/mbihhqtx.html