写高质量OC代码52建议总结:49.对自定义其内存管理语义的collection使用无缝桥接

OC系统库包含相当多的collection类,其中各种数组、字典、set。CoreFoundation框架也定义了一套C语言的API,操作这些collection及数据结构。Foundation中的NSArray和CoreFoundation中的CFArray是等价的。两种创建数组的方式可能有区别,“无缝桥接”技术可以在两个类型之间转换。

 CFArray要通过CFArrayRef来引用,而这是指向struct__CFArray的指针。CFArrayGetCount这种函数可以操作此struct,来获取数组大小。

-(void)demo1{
    
    NSArray *anArray = @[@1,@2,@3,@4,@5];
    CFArrayRef aCFArray = (__bridge CFArrayRef)anArray;
    NSLog(@"Size of array = %li", CFArrayGetCount(aCFArray));
}
 __brifge的意思是,ARC依然有这个OC对象的所有权。而__bridge_retained意思是ARC将交出对象的所有权。若用后者,上面代码的后面要加上CFRelease释放内存。返现转换通过__bridge_transfer来实现,想把CFArrayRef转换为NSArray*令ARC获得对象所有权。
 比如,使用Foundation框架中的字典对象时会遇到一个问题,键的语义是“拷贝”,值得语义是“保留”。CoreFoundation框架中的字典类型叫做CFDictionary。可变字典为CFMutableDictionary。通过下列方法指定键和值的内存管理语义。

-(void)demo2{
    CFMutableDictionaryRef CFDictionaryCreateMutable(
        CFAllocatorRef allocator,
        CFIndex capacity,
        const CFDictionaryKeyCallBacks *keyCallBcaks,
        const CFDictionaryValueCallBacks *valueCallBacks
                                                     );
}
 首个参数表示使用的内存分配器,通常传入NULL表示采用默认分配器。
 第二个参数定义了字典的初始大小。
 最后两个参数定义了很多回调函数,指示key和value在各种情况下应该执行的操作。两个参数都是结构体指针。

-(void)demo3{
    struct CFDictionaryKeyCallBacks{
        CFIndex version;
        CFDictionaryRetainCallBack retain;
        CFDictionaryReleaseCallBack release;
        CFDictionaryCopyDescriptionCallBack copyDescription;
        CFDictionaryEqualCallBack equal;
        CFDictionaryHashCallBack hash;
    };
    
    struct CFDictionaryValueCallBacks{
        CFIndex version;
        CFDictionaryRetainCallBack retain;
        CFDictionaryReleaseCallBack release;
        CFDictionaryCopyDescriptionCallBack copyDescription;
        CFDictionaryEqualCallBack equal;
    };
}
如果字典中加入了新的键和值,机会调用retain函数

-(void)demo4{
    typedef const void* (*CFDictionaryRetainCallBack)(
        CFAllocatorRef allocator,
        const void *value
    );
}
 retain是个函数指针,所指向的函数接受两个参数,传入的value表示即将加入字典的键或者值,返回的void*表示加入字典中的最终值。

const void *CustomCallback(CFAllocatorRef allocator, const void *value) {
    return value;
}
 这么写只是把即将加入字典的值原样返回,用它充当retain回调函数创建字典,就不会“保留”键和值了。下面是完整的字典创建过程。

#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>

const void *EOCRetainCallback(CFAllocatorRef allocator, const void *value) {
    return CFRetain(value);
}

void EOCReleaseCallback(CFAllocatorRef allocator, const void *value) {
    CFRelease(value);
}

CFDictionaryKeyCallBacks keyCallbacks = {
    0,
    EOCRetainCallback,
    EOCReleaseCallback,
    NULL,
    CFEqual,
    CFHash
};

CFDictionaryValueCallBacks valueCallbacks = {
    0,
    EOCRetainCallback,
    EOCReleaseCallback,
    NULL,
    CFEqual
};
-(void)demo5{
    CFMutableDictionaryRef aCFDictionary = CFDictionaryCreateMutable(NULL, 0, &keyCallbacks, &valueCallbacks);
    
    NSMutableDictionary *anNSDuctionary = (__bridge_transfer NSMutableDictionary *)aCFDictionary;
}
设置回调函数时,CFDictionaryCopyDescriptionCallBack被设置为null,默认实现就很好。equal和hash回调函数分别是CFEqual和CFHash,这个这和NSMutableDictionary的默认实现相同,CFEqual最终会调用NSObject的isEqual:方法,CFHash会调用hash方法。
 前面说过,在向NSMutableDictionary中加数键和值时,如果用作键的对象不支持拷贝操作,编译器会报错,“所属对象的类不支持NSCopying协议,因为copyWithZone:方法未实现”。可以直接在CoreFoundation创建字典~~
 
 总结:
 1.无缝桥接技术,可以在Foundation框架中的OC对象和CoreFoundation框架中的C语言数据结构之间来回转换。
 2.CoreFoundation创建collection,可以指定很多回调函数,表示在各种情况下的操作,然后无缝桥接转换成OC对象使用。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值