zoukankan      html  css  js  c++  java
  • iOS ARC内存管理

    iOS的内存管理机制,只要是iOS开发者,不管多长的时间经验,都能说出来一点,但是要深入的理解。还是不简单的。随着ARC(自动管理内存)的流行。iOS开发者告别了手动管理内存的复杂工作。但是自动管理内存也不是万能的,一不小心还是会出现内存泄漏的问题。本文探讨一下iOS下的自动管理内存机制。


    ARC的本质

    ARC是编译器特性,而不是运行时特性,更不是垃圾回收机制(GC)

    ARC是自iOS 5之后增加的新特性,完全消除了手动管理内存的繁琐,编译器会自动在适当的地方插入适当的retain,release,autorelease语句。你不在需要担心内存管理,因为编译器替你处理了一切。ARC是编译器特性,而不是运行时特性(除了weak指针系统)也不是类似于其他语言中的垃圾回收机制。因此ARC和手动内存管理性能是一样的,有时还能更快加速,因为编译器还可以执行某些优化。

    ARC的开启和禁止

    (1).使用Xcode的自动转换工具
    (2).手动设置某些文件支持ARC

    1.Xcode的自动转换工具

    Xcode带了一个自动转换工具,可以将旧的源代码转成ARC模式
    (1).ARC是LLVM 3.0编译器的特性,而现有工程可能使用老的GCC 4.2或LLVM-GCC编译器,因此首先需要设置使用LLVM 3.0编译器:

    201621692751997.jpg (671×555)

    最好也选上Warnings中的Other Warning Flags 为 -Wall,这样编译器就会检查所有可能的警告,有助于我们避免潜在的问题.

    (2).设置"Objective-C Automatic Reference Counting"选项为YES,不过Xcode自动转换工具会自动设置这个选项,这里只是说明一下如何手动设置

    201621692809705.png (453×151)

    2.手动禁制某些文件的ARC -fno-objc-arc

    201621693034360.png (576×243)

    ARC的原理

    ARC的原理非常简单:只要还有一个变量指针指向对象,对象就会保存在内存中。当指针指向新值,或者指针不再存在的时候,相关联的对象就会被自动释放。这条规则对于实例变量。syncthesize属性,局部变量都是适用的。

    Strong指针

    表示引用为强引用。对应在定义property时的"strong"。所有对象只有当没有任何一个强引用指向时,才会被释放。

    注意:如果在声明引用时不加修饰符,那么引用将默认是强引用。当需要释放强引用指向的对象时,需要将强引用置nil。

    @property (nonatomic,strong) UITextField *textField;//1
    
    self.textField.text = @"tian";//2
    
    NSString *name = self.textField.text;//3

    第一行 声明一个Strong指针类型的TextField;

    执行完第二行代码,textField的text属性就是NSString对象的指针,也就是拥有者。该对象保存了文本输入框的内容。也就是说有一个强指针指向了@"tian";

    执行完第三行代码,同时有两个指针指向@"name"对象。一个对象可以拥有多个指针。name变量也指向了@"tian"对象.

    下面是李明杰老师的博客内容 图文并茂。更好理解。我偷过来。哈哈。

    控制器中有个文本输入框框属性

    @property (nonatomic, assign) IBOutlet UITextField *nameField; 

    1.如果用户在文本框中输入mj这个字符串

    那么可以这样说,nameField的text属性是NSString对象的指针,也就是拥有者,该对象保存了文本输入框的内容。

    2.如果执行了如下的代码

    NSString *name = self.nameField.text; 

    一个对象可以有多个拥有者,在上面的代码中,name变量同样也是这个NSString对象的拥有者,也就是有两个指针指向同一个对象

    3.随后用户改变了输入框的内容

    此时nameFeild的text属性就指向了新的NSString对象。但原来的NSString对象仍然还有一个所有者(name变量),因此会继续保留在内存中

     

    4.当name变量获得新值,或者不再存在时(如局部变量方法返回时、实例变量对象释放时),原先的NSString对象就不再拥有任何所有者,retain计数降为0,这时对象会被释放
    如,给name变量赋予一个新值

    name = @"Jake"; 

     

    我们称name和nameField.text指针为"Strong指针",因为它们能够保持对象的生命。默认所有实例变量和局部变量都是Strong指针

    weak

    weak型指针变量仍然可以指向一个对象,但不属于对象的拥有者。

    表示引用为弱引用。对应在定义property时用的"weak"。弱引用不会影响对象的释放,即只要对象没有任何强引用指向,即使有100个弱引用对象指向也没用,该对象依然会被释放。不过好在,对象在被释放的同时,指向它的弱引用会自动被置nil,这个技术叫zeroing weak pointer。这样有效得防止无效指针、野指针的产生。__weak一般用在delegate关系中防止循环引用或者用来修饰指向由Interface Builder编辑与生成的UI控件。

    1.执行下面的代码

    __weak NSString *name = self.nameField.text; 

    name变量和nameField.text属性都指向同一个NSString对象,但name不是拥有者

     2.如果文本框的内容发生变化,则原先的NSString对象就没有拥有者,会被释放,此时name变量会自动变成nil,称为空指针

    3.weak指针主要用于“父-子”关系,父亲拥有一个儿子的strong指针,因此父亲是儿子的所有者;但为了阻止所有权循环,儿子需要使用weak指针指向父亲。典型例子是delegate模式,你的ViewController通过strong指针(self.view)拥有一个UITableView, UITableView的dataSource和delegate都是weak指针,指向你的ViewController

    strong和weak指针的使用注意

    1.下面代码是有问题的:

    __weak NSString *str = [[NSString alloc] initWithFormat:@"1234"];  
    NSLog(@"%@", str); // 打印出来是"(null)"  

    tr是个weak指针,所以NSString对象没有拥有者,在创建之后就会被立即释放。Xcode还会给出警告("Warning: Assigning retained object to weak variable; object will be released after assignment")

    2.一般的指针变量默认就是strong类型的,因此一般我们对于strong变量不加__strong修饰,以下两行代码是等价的:

    NSString *name = self.nameField.text;  
    __strong NSString *name = self.nameField.text;  

    3.属性可以是strong或weak,写法如下

    @property (nonatomic, strong) NSString *name;  
    @property (nonatomic, weak) id delegate;  

    4.以下代码在ARC之前是可能会行不通的,因为在手动内存管理中,从NSArray中移除一个对象时,这个对象会发送一条release消息,可能会被立即释放。随后NSLog()打印该对象就会导致应用崩溃

    id obj = [array objectAtIndex:0];  
    [array removeObjectAtIndex:0];  
    NSLog(@"%@", obj);  

    在ARC中这段代码是完全合法的,因为obj变量是一个strong指针,它成为了对象的拥有者,从NSArray中移除该对象也不会导致对象被释放

    __autoreleasing

    表示在autorelease pool中自动释放对象的引用,和MRC时代autorelease的用法相同。定义property时不能使用这个修饰符,任何一个对象的property都不应该是autorelease型的。

    一个常见的误解是,在ARC中没有autorelease,因为这样一个“自动释放”看起来好像有点多余。这个误解可能源自于将ARC的“自动”和autorelease“自动”的混淆。其实你只要看一下每个iOS App的main.m文件就能知道,autorelease不仅好好的存在着,并且变得更fashion了:不需要再手工被创建,也不需要再显式得调用[drain]方法释放内存池。

    int main(int argc, char * argv[]) {
        @autoreleasepool {
            return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
        }
    }

    以下两行代码的意义是相同的。

    NSString *str = [[[NSString alloc] initWithFormat:@"hehe"] autorelease]; // MRC
    NSString *__autoreleasing str = [[NSString alloc] initWithFormat:@"hehe"]; // ARC

    __autoreleasing在ARC中主要用在参数传递返回值(out-parameters)和引用传递参数(pass-by-reference)的情况下。

    NSError *__autoreleasing error; 
    if (![data writeToFile:filename options:NSDataWritingAtomic error:&error]) 
    { 
      NSLog(@"Error: %@", error); 
    }

    注意,如果你的error定义为了strong型,那么,编译器会帮你隐式地做如下事情,保证最终传入函数的参数依然是个__autoreleasing类型的引用。

    NSError *error; 
    NSError *__autoreleasing tempError = error; // 编译器添加 
    if (![data writeToFile:filename options:NSDataWritingAtomic error:&tempError]) 
    { 
      error = tempError; // 编译器添加 
      NSLog(@"Error: %@", error); 
    }

    所以为了提高效率,避免这种情况,我们一般在定义error的时候将其(老老实实地=。=)声明为__autoreleasing类型的:

    NSError *__autoreleasing error;

    在这里,加上__autoreleasing之后,相当于在MRC中对返回值error做了如下事情:

    *error = [[[NSError alloc] init] autorelease];

    *error指向的对象在创建出来后,被放入到了autoreleasing pool中,等待使用结束后的自动释放,函数外error的使用者并不需要关心*error指向对象的释放。

    另外一点,在ARC中,所有这种指针的指针 (NSError **)的函数参数如果不加修饰符,编译器会默认将他们认定为__autoreleasing类型。

    比如下面的两段代码是等同的:

    - (NSString *)doSomething:(NSNumber **)value
    {
            // do something  
    }
    
    - (NSString *)doSomething:(NSNumber * __autoreleasing *)value
    {
            // do something  
    }

    除非你显式得给value声明了__strong,否则value默认就是__autoreleasing的。

    ARC小结
    1.有了ARC,我们的代码可以清晰很多,你不再需要考虑什么时候retain或release对象。唯一需要考虑的是对象之间的关联,也就是哪个对象拥有哪个对象?
    2.ARC也有一些限制:
    1> 首先ARC只能工作于Objective-C对象,如果应用使用了Core Foundation或malloc()/free(),此时还是需要你来手动管理内存
    2> 此外ARC还有其它一些更为严格的语言规则,以确保ARC能够正常地工作
    3.虽然ARC管理了retain和release,但并不表示你完全不需要关心内存管理的问题。因为strong指针会保持对象的生命,某些情况下你仍然需要手动设置这些指针为nil,否则可能导致应用内存不足。无论何时你创建一个新对象时,都需要考虑谁拥有该对象,以及这个对象需要存活多久
    4.ARC还能很好地结合C++使用,这对游戏开发是非常有帮助的。对于iOS 4,ARC有一点点限制(不支持weak指针),但也没太大关系

  • 相关阅读:
    HDU2027 统计元音 一点点哈希思想
    湖南工业大学第一届ACM竞赛 数字游戏 字符串处理
    湖南工业大学第一届ACM竞赛 我素故我在 DFS
    HDU3293sort
    HDU2082 找单词 母函数
    HDU1018 Big Number 斯特林公式
    湖南工业大学第一届ACM竞赛 分糖果 位操作
    UVA 357 Let Me Count The Ways
    UVA 147 Dollars
    UVA 348 Optimal Array Multiplication Sequence
  • 原文地址:https://www.cnblogs.com/huanying2000/p/6165440.html
Copyright © 2011-2022 走看看