`
sofire
  • 浏览: 143819 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

内存管理MRR/ARC,property和内存泄露

阅读更多

MRR:Manual retain-release

推荐:《iPhone/Mac Objective-C内存管理教程和原理剖析》

http://www.cnblogs.com/VinceYuan/archive/2010/03/08/1680488.html

  • 生成的对象,有一个引用计数:retainCount,当retainCount = 0,内存就会被释放
  • 用alloc/new/copy生成对象时,其 retainCount = 1
  • retain 让retainCount + 1,release让retainCount - 1,成对出现:[obj retain]  [obj release]
  • 用autorelease能让retainCount的管理简单些,涉及到autorelease pool
  • 在生成新的RunLoop时,系统自动创建新的autorelease pool

property的修饰符:

  • assign
  • copy
  • retain:参考默认实现,很重要

  • 如:@property (retain) objA* obj;

retain、copy的默认实现:

-(void) setObjB:(ClassB*) value

{

         if (objB != value)

         {

                   [objB release]; //原来的对象会先release

                   objB = [value retain]; //copy类似

         }

}  

 

assign针对简单数据类型(scalar types) ,如int,float, CGRect, NSInteger等,它只是简单的赋值操作

 

 

 

copy/mutableCopy 浅拷贝和深拷贝

参考:《浅析ObjectiveC 深浅拷贝学习 》http://www.cocoachina.com/bbs/read.php?tid=80463

  • 不可改变对象的copy,才是浅拷贝;其他都是深拷贝
  • copy 返回的对象都是不可改变的
  • 容器类(如NSArray等) 的内容都是浅拷贝的

内存泄露

参考:《Presentation: Finding & Fixing Mem Leaks》

http://www.streamingcolour.com/blog/2010/09/21/presentation-finding-fixing-mem-leaks/

 

常见情况1:

// @property (nonatomic, retain) MyClass* objA;

 

- (void)foo{

  //retainCount = 2

  self.objA = [[MyClass alloc] init];

}

 

- (void)dealloc{

  //retainCount = 1

  [objA release];

  [super dealloc];

}

 

修复方法:

// @property (nonatomic, retain) MyClass* objA;

<!-- ^ Position is not set to relative / absolute here because of Mozilla -->

 

- (void)foo{

  //retainCount = 1

  MyClass *obj = [[MyClass alloc] init];

  //retainCount = 2

  self.objA = obj;

  //retainCount = 1

  [obj release]

}

 

- (void)dealloc{

  //retainCount = 0

  [objA release];

  [super dealloc];

}     

 

常见情况2:

 

<!-- ^ Position is not set to relative / absolute here because of Mozilla -->

       // @property (nonatomic, retain) MyClass* objA;

 

- (void)foo{

  MyClass *obj = [[MyClass alloc] init];

  self.objA = obj;

  [obj release];

  //retainCount = 1

}

 

- (void)dealloc{

  //retainCount = 1

  [super dealloc];

}

 

<!-- ^ Position is not set to relative / absolute here because of Mozilla -->

修复方法:

// @property (nonatomic, retain) MyClass* objA;

 

- (void)foo{

  MyClass *obj = [[MyClass alloc] init];

  self.objA = obj;

  [obj release];

  //retainCount = 1

}

 

- (void)dealloc{

  //retainCount = 0

  [objA release];

  [super dealloc];

}

 

self.abc = nil 与 _abc = nil的区别

@property (retain) classA *abc;

@synthesize abc = _abc;

 

需要明白 self.abc 的默认实现,它相当于:

[_abc release];

_abc = nil;

前者会发送release消息,而后者可能有内存泄露。

 

<!-- ^ Position is not set to relative / absolute here because of Mozilla -->

Tools

  • Build & Analyze
  • Leaks Instument  

<!-- ^ Position is not set to relative / absolute here because of Mozilla -->

Automatic Reference Counting

  • “Automatic Reference Counting (ARC) is a compiler-level feature that simplifies the process of managing object lifetimes (memory management) in Cocoa applications.”
  • ARC is a pre-compilation step that adds retain/release/autorelease statements to your code for you
  • 需要Xcode 4.2+, Apple LLVM 3.0+ compiler 
<!-- ^ Position is not set to relative / absolute here because of Mozilla -->

简化了编程(本周上和MRR是一样的),不需要/不能使用下面这些方法

  • retain /release
  • autorelease
  • retainCount
  • NSAllocateObject / NSDeallocateObject  

property的修饰符:

  • strong:相当于retain
  • weak:相当于assign

变量修饰符:

  • __strong
    • This means any object created usingalloc/init is retained for the lifetime of its current scope.
    • is the default so you don’t need to type it.
    • #相当于retain,在不再使用的时候被释放 (默认)
  • __weak
    • means the object can be destroyed at anytime.
    • This is only useful if the object is somehow strongly referenced somewhere else.
    • When destroyed, a variable with __weak is set to nil.
    • #与assign很像,不同在于如果指向的数据被释放了,那么这个指向nil
  • __unsafe_unretained
    • is just like __weak but the poiner is not set to nil when the object is deallocated.
    • Instead the pointer is left dangling (i.e. it no longer points to anything useful).
    • #相当于assign,指向的数据如果被释放,这个指向原来的地址
  • __autoreleasing
    • not to be confused with calling autorelease on an object before returning it from a method, this is used for passing objects by reference, for example when passing NSError objects by reference such as [myObject performOperationWithError:&tmp];
    • #标明传给函数的(id*)型参数是自动释放的,(函数中(id*)型参数默认的也是这种类型)  
<!-- ^ Position is not set to relative / absolute here because of Mozilla -->

Toll-Free Bridging/CF和ObjC转换

  • 在没有开启ARC时,可以进行强制转换.
    • CFStringRef aCFString = (CFStringRef)aNSString;
    • NSString *aNSString = (NSString *)aCFString;
  • __bridge
    • 简单赋值,不会影响两边对象的retain count.

      id my_id;

      CFStringRef my_cfref;

      NSString *a = (__bridge NSString*)my_cfref;

      CFStringRef b = (__bridge CFStringRef)my_id;

  • __bridge_retained or CFBridgingRetain
    • 保留赋值,赋值后也保留不释放右边的对象
  • __bridge_transfer or CFBridgingRelease
    • 释放赋值,赋值后释放右边的对象
  • 例子
    • -(void)test

      {

          CFStringRef coreFoundationString = CFStringCreateWithCString(CFAllocatorGetDefault(),"C String", kCFStringEncodingUTF8);    // 创建 retainCount = 1

          id unknownObjectType = (__bridge  id)coreFoundationString; // 简单赋值,不变,retainCount = 1

          CFStringRef anotherString = (__bridge_retained  CFStringRef)unknownObjectType; // 保留赋值,加一,retainCount = 2

          NSString *objCString = (__bridge_transfer  NSString *)coreFoundationString; // 释放赋值,减一,retainCount =1;由于NSString*默认strong,加一,retainCount = 2

          NSLog(@"String = %@", objCString);

          objCString = nil;   // 不再指向原内存,原内存减一,retainCount = 1

          CFRelease(anotherString);   // 释放,减一,retainCount = 0

      }

  • 转换宏
    • #if __has_feature(objc_arc)

      #   define objc_retainedObject(o) ((__bridge_transfer id)(objc_objectptr_t)(o))

      #   define objc_unretainedObject(o) ((__bridge id)(objc_objectptr_t)(o))

      #   define objc_unretainedPointer(o) ((__bridge objc_objectptr_t)(id)(o))

      #else

      #   define objc_retainedObject(o) ((id)(objc_objectptr_t)(o))

      #   define objc_unretainedObject(o) ((id)(objc_objectptr_t)(o))

      #   define objc_unretainedPointer(o) ((objc_objectptr_t)(id)(o))

      #endif     

@synthesize 和Dynamic ivars

@interface ClassA {

  //NSObject _objB; // instance varible or ivar,可以不写,编译器会自动生成

}

@property (retain) NSObject *objB; 

@end

 

@implement ClassA

@synthesize objB = _objB;

@end

 

<!-- ^ Position is not set to relative / absolute here because of Mozilla -->

@synthesize myProperty = myIvar; // a dynamic ivar named myIvar  will be generated

@synthesize anotherProperty;   // a dynamic ivar named anotherProperty  will be generated

<!-- ^ Position is not set to relative / absolute here because of Mozilla -->

  1. @synthesize是新特征,简化setter/getter方法;
  2. 能用retain/copy/assing,strong/wak管理内存
  3. 在init和dealloc函数中,不建议用synthesized accessors,它会trigger KVO notifications;它本质上是setter/getter,在不需要调用setter/getter的时候,就不要用

  4. 32bit Mac OS X不支持Dynamic ivar,必须手动什么iVar,否则无法编译
  5. 调试原因(我还不清楚这是什么意思,因为在self变量里可以找到ivar):For some reason the XCode debugger doesn't show properties that don't have corresponding ivars explicitly declared.       

self.abc = nil 与 _abc = nil的本质区别

 

    分享到:
    评论

    相关推荐

    Global site tag (gtag.js) - Google Analytics