美文网首页iOS 开发者的日常iOS开发程序员
iOS中内存管理问题之: Core Foundation 和 C

iOS中内存管理问题之: Core Foundation 和 C

作者: KenZhangCn | 来源:发表于2016-12-16 19:08 被阅读123次

    Cocoa Foundation是iOS中的一个重要框架, 我们大量的使用了里面封装好的接口. 但是还有许多我们需要的接口并不包含在Cocoa框架中, 比如RSA算法, MD5算法, SHA1算法, AES加密算法等, Cocoa对象库里并没有相应的实现. 这时候我们可以在Core Foundation框架里面去寻找. 包括NSString类里没有的字符串编码GBK, GB2312, GB18030等, 在Core Foundation里, 都能找到相应的编码. 建立Socket连接, 获得输入流和输出流时, 也需要使用Core Foundation里的CFNetwork Api等等.

    Cocoa Foundation和Core Foundation的一个重要区别是: Cocoa Foundation是面向对象的, Core Foundation是非面向对象的. 这是造成内存管理方式区别的原因. Cocoa Foundation中的对象使用ARC自动管理内存, 而对于Core Foundation中的对象则需要进行手动管理内存, 使用完之后都需要手动Release.

    然后又涉及到另一个问题, 就是Cocoa Foundation和Core Foundation相互转换时内存管理问题. Cocoa Foundation和Core Foundation对象相互转换时我们使用__bridge, __bridge_transfer, __bridge_retained关键字.

    • 1.__bridge: Cocoa Foundation和Core Foundation对象转化时只涉及对象类型不涉及对象所有权的转化;
    • 2.__bridge_transfer: Cocoa Foundation对象转换成Core Foundation对象时,将Cocoa Foundation对象的所有权交给Core Foundation对象, 此时ARC就能自动管理该内存;
    • 3.__bridge_retained: (与__bridge_transfer相反)常用在将Cocoa Foundation对象转换成Core Foundation对象时, 将Cocoa Foundation对象的所有权交给Core Foundation对象来管理;

    当使用_bridge_retained标识符以后, 代表Cocoa Foundation要将对象所有权交给Core Foundation对象自己来管理, 所以我们要在各种Ref使用完成以后用Release将其手动释放.

    举个栗子, FMDB中的一个大家都知道的一个方法:

    - (void)inDatabase:(void (^)(FMDatabase *db))block {
        /* Get the currently executing queue (which should probably be nil, but in theory could be another DB queue
         * and then check it against self to make sure we're not about to deadlock. */
        FMDatabaseQueue *currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey);
        assert(currentSyncQueue != self && "inDatabase: was called reentrantly on the same queue, which would lead to a deadlock");
        
        FMDBRetain(self);
        
        dispatch_sync(_queue, ^() {
            
            FMDatabase *db = [self database];
            block(db);
            
            if ([db hasOpenResultSets]) {
                NSLog(@"Warning: there is at least one open result set around after performing [FMDatabaseQueue inDatabase:]");
                
    #if defined(DEBUG) && DEBUG
                NSSet *openSetCopy = FMDBReturnAutoreleased([[db valueForKey:@"_openResultSets"] copy]);
                for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) {
                    FMResultSet *rs = (FMResultSet *)[rsInWrappedInATastyValueMeal pointerValue];
                    NSLog(@"query: '%@'", [rs query]);
                }
    #endif
            }
        });
        
        FMDBRelease(self);
    }
    

    MDatabaseQueue *currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey); 这句代码中使用了__bridge关键字. MDatabaseQueue继承自NSObject, NSObject是Cocoa的根类. 而dispatch_get_specific(const void *key);则返回"the current subsystem-specific context", 因而__bridge在代码中的作用便是把Core Foundation对象转换成Cocoa Foundation对象, 但是由于只涉及对象类型的转换而没有涉及对象控制权的转换, 所有还需要手动的进行Retain和Release. 在代码中体现为:
    FMDBRetain(self);
    FMDBRelease(self);


    文章有参考网络文章,如有错误,欢迎讨论指出。

    相关文章

      网友评论

        本文标题:iOS中内存管理问题之: Core Foundation 和 C

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