内存管理,ARC

1. 要避免两个对象互相retain的问题;


2.  Core Foundation's memory allocation policy is that you need to release values returned by functions with “Copy” or “Create” or "alloc" in their name; 

     这是指在corefoundation.framework中。而NSString等是在foundation.framework中。

 

3.不是alloc出来的对象不要执行 autorelease!!!

   alloc方法将分配的内存初始化为0,BOOL类型变量被初始化为NO,int为0,float为0.0,指针为nil,所有的基地都属于我们了。

  

4.Cocoa过去没有垃圾回收机制,iPhone现在也没有。所以必须自己通过-retain, -release and -autorelease这些命令使用引用计数(reference counting)技术来管理内存。

   Objective-C的内存管理机制与.Net/Java那种全自动的垃圾回收机制不同,它本质上还是C语言中的手动管理方式,只不过加了一些自动方法。

   为什么iOS中没有GC

    •    GC消耗CPU时间,耗电。
    •    GC执行后,会停掉运行时库;
    ◦    GC执行频率高损失性能:耗内存,影响UI动画处理效果;

5.可以不为应用程序委托AppDelegate提供dealloc方法,因为它永远不会被调用。iPhone OS在应用程序拆卸(tear-down)期间会恢复所有应用程序内存。从技术上讲,视图控制器存在泄漏问题。但是在实践中,这不是问题。

 

6. 在objc 中出现了EXE_BAD_ACCESS,经常是因为访问了被释放了的对象。

    在dealloc时,要把[super dealloc]放到 dealloc的最后调用,否则可能会出现问题,可能是因为释放了NSObject,导致继承该类的其它数据成员没有宿主,导致错误。


7.内存使用经验:
(1)使用尽量少使用或使用小尺寸的UIView层
          对于iPad,一个像素需要4Byte来算,一个层的大小就是 4x1024x768 ~ 3M字节, 10个层就是 10x3M = 30M
(2)尽量使用图片pattern,而不是一张大的图片
            与在界面上放一个大底图相比,最佳方案是,设计出一个小的pattern图,然后用这个方案显示成底图。
            UIImage *smallImage = [[UIImage alloc] initWithContentsOfFile:path]; 
            backgroundView.backgroundColor = [UIColor colorWithPatternImage:smallImage];
             [smallImage release];
(3)使用 NSAutoreleasePool 的时候也尽量建议局部使用,比如下面的循环。

         循环中大量生成的自动释放autorelease对象,可以考虑使用autorelease pool封装。代码范例:
    for(UIView *subview in bigView.subviews) {  
        // 使用autorelease pool自动释放对象池  
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
      
        UIImageView *imageView = (UIImageView *)subview;  
          
        // subview处理代码  
        .......  
      
        // 销毁自动释放对象  
        [pool  drain];  
    }
  (4)iOS4.0的multi-tasking特性发布后,程序可以被调入后台运行,苹果工程师的意见是,进入后台运行时,你的应用应该释放掉能释放的对象,尽量保持在16M左右,这样别的程序运行时才不容易把你的应用挤掉。

    (5)生成对象时,使用autorelease; 对象代入时,先autorelease后再retain,Failed Self 的原则;对象在函数中返回时,使用return [[object retain] autorelease];


8.数组和字典的内存管理:

    当NSMutableArray被release时,它将自动release所有索引位置上的对象. 应该同样适用于NSArray及其它容器.

    测试NSMutableArray addObject会对添加进的对象发送retain消息;NSMutableDictionary setObject也会对添加的对象发送retain消息;

    当使用AppKit时,Cocoa定期自动创建和销毁自动释放池.通常是在一个事件循环后执行这些操作.

    <<objective-c基础教程>>中讲,实际上,在编写iPhone程序时,苹果公司建议你不要在自己的代码中使用autorelease方法,同时还要避免使用那些创建了自动释放对象的便利函数.


9.ios6.0内存警告的兼容处理 viewDidUnload 屏蔽

http://www.cocoachina.com/bbs/simple/?t125949.html


判断self.view是否显示在屏幕上

if (self.view.window)

{}  //在iOS程序里面,window是程序视图层次体系的最高层。view要直接或间接加到这个window上才能被看到。即它的window属性值不为nil。


模拟内存警告:

在ios6模拟器中,当前页didReceiveMemoryWarning被调用,前一页didReceiveMemoryWarning被调用,此时前一页self.view.window为nil,这里如果置前一页的self.view=nil,再返回前一页时,前一页loadview被调用。

在ios5模拟器中,当前didReceiveMemoryWarning被调用,前一页的didReceiveMemoryWarning、viewDidUnload被调用。再返回前一页,会调用前一页的loadview。

结论:在ios5中,会自动销毁非当前页的viewController.view。ios6中,要手动销毁非当前页的viewController.view,且不会调用viewDidUnload。只有viewController.view被销毁了,viewController的loadview,viewDidLoad才会被依次调用。在调用loadView前,self.view会被重新创建,它的内容就是空的了。

所以,基于原ios5的viewDidUnload代码,在ios6中处理代码修改如下:

-(void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    
    if([[[UIDevice currentDevice] systemVersion] floatValue] >= 6.0)
    {
        if ([self.view window] == nil)//非当前视图
        {
            [self viewDidUnload];

           

           /*

              下面self.view = nil;目的是再次进入时能够重新加载,

             此操作不能调用两次,如果调用两次会导致此页面在下面时也会被调用loadview;

             且要销毁所有的子view,在loadview时重新创建,这涉及到保存一些view中的数据,防止丢失。

          */

            self.view = nil;
        }
    }
}


如果不主动执行[self viewDidUnload]或相关函数,则必须要在loadView和viewDidLoad中对一些成员的创建做空建判断。空建即为空是才创建。但[self.view addSubview:xxx];要在空建判断外添加,因为此时self.view内容是空的。


参考 http://www.cnblogs.com/thefeelingofsimple/archive/2012/12/03/2799145.html


10.



9.ARC

http://onevcat.com/2012/06/arc-hand-by-hand/

http://www.yifeiyang.net/development-of-the-iphone-simply-1/

  

   在Building Setting中,Apple LLVM compiler 3.1 language 中 “Objectice-C Auto Reference Counteting” 项设置是否启用ARC。

   如果只想对某个.m文件不适应ARC,可以只针对该文件加上 -fno-objc-arc 编译FLAGS。而启用arc使用 -fobjc-arc编译选项。

  ARC的一个基本规则即是,只要某个对象被任一strong指针指向,那么它将不会被销毁。如果对象没有被任何strong指针指向,那么就将被销毁。成员对象指针和局部指针默认就是strong的,即ARC中默认的指针类型就是strong

  当对象被销毁后,在ARC机制作用下,所有指向这个对象的weak指针将被置为nil。这个特性相当有用,使用ARC以后,不论是strong还是weak类型的指针,都不再会指向一个dealloced的对象,不会出现EXCBADACCESS错误,从根源上解决了意外释放导致的crash

strong和retain相似,weak比assign更聪明一些。

    ARC基本规则

  • retain, release, autorelease, dealloc由编译器自动插入,不能在代码中调用
  • 可以重写dealloc,但不能调用[super dealloc];
引用关键字

ARC中关于对象的引用参照,主要有下面几关键字。使用strong, weak, autoreleasing限定的变量会被隐式初始化为nil。

__strong 强参照,变量声明缺省都带有__strong关键字。
__weak  弱参照,该类型不影响对象的生命周期,如果对象之前就没有持有者,那么会出现刚创建就被破弃的情况。弱参照还有一个特征,即当参数对象失去所有者之后,变量会被自动付上nil (Zeroing)。
__unsafe_unretained 即MRC的assign

__autoreleasing 该关键字使对像延迟释放。用在函数返回新对象或函数的参数会接管新对象。可以理解为暂只保存对象内存不检查强弱情况,待有指针接管后再检查判断。

- (void) generateErrorInVariable:(__autoreleasing NSError **)paramError {
    ....
    *paramError = [[NSError alloc] initWithDomain:@"MyApp" code:1 userInfo:errorDictionary];
}
    NSError *error = nil;
    [self generateErrorInVariable:&error];
    NSLog(@"Error = %@", error);

 
-(NSString *)stringTest
{
    __autoreleasing NSString *retStr = [NSString alloc] initWithString:@"test"];

    return retStr;
}

当方法的参数是id*,或希望方法返回时对象被autoreleased,那么使用该关键字。


伴随ARC的导入,还有一系列函数的定义也被严格定义了,那就是以 init 开头的函数。init 函数作为alloc生成对象的初期化函数,需要按原样直接传递对象给调用段,所以下面的声明是OK的。
-(id)initWithObject:(id)obj;

而下面的是NG的。
-(void)initWithObject;
不过声明为 -(void) initialize; 是没有问题的。


只能将ARC用在objective-c对象上(也即继承自NSObject的对象),但是如果涉及到较为底层的东西,比如Core Foundation中的malloc()或者free()等,ARC就鞭长莫及了,这时候还是需要自己手动进行内存管理。另外为了确保ARC能正确的工作,有些语法规则也会因为ARC而变得稍微严格一些。

ARC确实可以在适当的地方为代码添加retain或者release,但是这并不意味着你可以完全忘记内存管理,因为你必须在合适的地方把strong指针手动设置到nil,否则app很可能会oom。简单说还是那句话,你必须时刻清醒谁持有了哪些对象,而这些持有者在什么时候应该变为指向nil

使用ARC之后,由于内存问题造成的crash基本就是过去式了,OOM除外。

iOS 5.1 Xcode 4.3版本中,ARC 有效时的属性(@property) 定义的时候,如果不明确指定所有权关键字,那么缺省的就是 strong。但是在 Xcode4.2 中,即使 strong 也要显示指定。


property也可以用strongweak来标记,简单地把原来写retainassign的地方替换成strong或者weak就可以了。


代码示例:

__weak NSString *weakName = self.textField.text;


首先,ARC是LLVM3.0编译器的特性,而老的工程默认编译器可能是GCC或者LLVM-GCC,因此第一步就是确认编译器是否正确。在Project设置面板,选择target,在Build Settings中将Compiler for C/C++/Objective-C选为Apple LLVM compiler 3.0或以上。为了确保之后转换的顺利,最好把Treat Warnings as Errors和 Run Static Analyzer都打开,确保在改变编译器后代码依旧没有警告或者内存问题。

Build Settings页面,把Objective-C Automatic Reference Counting改成YES(如果找不到的话请看一看搜索栏前面的小标签是不是调成All了..这个选项在Basic里是不出现的),这样工程就将在所有源代码中启用ARC了。

Edit->Refactor下的Convert to Objective-C ARC,点击后会让选择要转换哪几个文件。

readonly的@property声明要显示声明strong

@property (nonatomic, strong, readonly) NSString *name;


对于强引用的成员view,在出现内存警告时,要在unload中置为nil,

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值