【iOS】MRC_AND_ARC

作者: HoyaWhite | 来源:发表于2017-01-11 16:26 被阅读102次

    项目设置


    1. 设置项目为ARC或者为MRC
      在TARGETS -> Build Setting -> Apple LLVM 8.0 - Language - Objective C -> Objective-C Automatic Reference Counting 设置其为YES(ARC)或者NO(MRC)

    2. ARC和MRC混编
      在TARGETS -> Build Phases -> Compile Sources中选择对应文件设置其Compiler Flags

    • ARC项目按照MRC编译 -fno-objc-arc
    • MRC项目按照ARC编译 -fobjc-arc

    MRC


    1. MRC文件一定要有dealloc 并且一定要有[super dealloc] 而且放到最后面

    2. 系统自带的方法里面没有包含alloc,new ,copy说明返回的对象都是autorelease的

    3. autoreleasepool是一种结构,不再是OC对象作用域与普通{ }一样。

    4. 先release后设置为nil 。绝对不可以先nil,在release。

    5. 多对象内存管理原则

      • 你想使用(占用)某个对象,就应该让对象的计数器+1 (让对象做一次retain操作)
    • 你不想再使用(占用)某个对象,就应该让对象的计数器-1 (让对象做一次release操作)
    • 谁retain,谁release
    • 谁alloc,谁release
    1. 代码规范
    • Foundation对象(OC对象) : 只要方法中包含了alloc \ new \ copy \ mutableCopy \ retain等关键字, 那么这些方法产生的对象, 就必须在不再使用的时候调用1次release或者1次autorelease
    • CoreFoundation对象(C对象) : 只要函数中包含了create \ new \ copy \ retain等关键字, 那么这些方法产生的对象, 就必须在不再使用的时候调用1次CFRelease或者其他release函数
    1. 在MRC Block使用WeakSelf防止循环引用,但是此时有延时操作的话 可以用 malloc_zone_from_ptr(weakObj) 判断weakSelf是否存在

    ARC


    1. 使用Core Foundationmalloc(size_t __size)开辟空间之后,你仍然对其内存管理负有责任需要在适当时候使用free(void *)以释放内存防止泄露
        void *p = malloc(3);
        free(p);//需要free()
    
    1. 因为ARC只对 objective-c 有效,而Core 开头的底层C语言库是没有使用编译器的特性ARC的,需要开发者手动进行内存管理(只要函数中包含了create \ new \ copy \ retain等关键字, 那么这些方法产生的对象, 就必须在不再使用的时候调用1次CFRelease或者其他release函数);并且在ARC中Core 开头的底层C语言库和OC中的库互相转换的时候需要使用(__bridge type)进行桥接,以Core Foundation为例进行说明。

      • 如果要使用Core Foundation,需要把数据类型进行转换,添加(__bridge type);但是(__bridge type)不对程序的内存管理做任何事情,不会更换对象的所有权,原来是ARC管理的对象还继续ARC管理,MRC的还继续MRC管理
        注意:(__bridge type)只存在于ARC中,(__bridge type)Core FoundationFoundation转换的桥梁,既可以Foundation -> Core Foundation,同样也能达到Core Foundation -> Foundation的效果
        //Foundation -> Core Foundation
        id a = [[NSObject alloc] init];
        void *p = a;//void *是属于Core Foundation,ARC中会报错“Implicit conversion of Objective-C pointer type 'id' to C pointer type 'void *' requires a bridged cast” void *p = (__bridge void *)(i);
        void *p = (__bridge void *)(a);//正确写法
        //Core Foundation -> Foundation
        void * q = 0;
        id b = (__bridge id)q;
    
    + `Foundation` **->** `Core Foundation` 解除 ARC 的所有权
        `__bridge_retained`和`CFBridgingRetain`:桥接的基础上对相关数据进行一次retained操作,防止被释放而Crash(EXC_BAD_ACCESS) 。
    

    注意:最后一定要对p进行一次release操作(因为进行了一次retain) 否则内存泄漏

        void *p;
        {
            id obj = [[NSObject alloc] init];
    //        p = (__bridge void *)obj;//错误写法 导致EXC_BAD_ACCESS
            p = (__bridge_retained void *)obj;//正确写法 
            //或者使用下面一种写法 效果是一样的 都相当于[p retain] 对p进行一次retain操作
            p = (void*)CFBridgingRetain(obj);//正确写法
        }   
        NSLog(@"class=%@", [(__bridge id)p class]);//如果使用错误写法 这里访问的是僵尸对象
       CFRelease(p);//切记最后一定要进行一次release操作  否则内存泄漏
    
     +  `Core Foundation` **->** `Foundation` 给予 ARC 所有权
    `__bridge_transfer`和`CFBridgingRelease`:桥接的接触上对相关数据进行了一次release操作,就不用再显式地对`Core Foundation` 数据进行`CFRelease(CFTypeRef cf)`操作了
    
        const char *bytes;
        CFStringRef coreStr;
        bytes = CFAllocatorAllocate(CFAllocatorGetDefault(),6,0);
        strcpy(bytes,"wp");
        coreStr = CFStringCreateWithCStringNoCopy(NULL,bytes,kCFStringEncodingMacRoman,NULL);
        //NSString *str = CFBridgingRelease(coreStr);
        NSString *str = (__bridge_transfer NSString *)coreStr;//不用再release操作了
    

    总结:

    1. Core Foundation 对象类型不在 ARC 管理范畴内,需要自己管理
    2. __bridge只做类型转换,但是不修改对象(内存)管理权,原来是ARC管理的还用ARC,原来MRC管理的继续用MRC
    3. __bridge_retained(也可以使用CFBridgingRetain)将Objective-C的对象转换为Core Foundation的对象,同时将对象(内存)的管理权交给我们,后续需要使用CFRelease或者相关方法来释放对象;
    4. __bridge_transfer(也可以使用CFBridgingRelease)将Core Foundation的对象转换为Objective-C的对象,同时将对象(内存)的管理权交给ARC。

    END

    相关文章

      网友评论

        本文标题:【iOS】MRC_AND_ARC

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