【iOS】MRC_AND_ARC

项目设置


  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)