美文网首页
iOS中结合代码看内存管理(一)

iOS中结合代码看内存管理(一)

作者: Nlinger | 来源:发表于2017-06-07 15:51 被阅读81次

    阅读本文前,建议移步先去了解下内存管理相关知识。

    1: iOS内存管理机制(百度goole大法可以获得很多推荐)。

    2: iOS中的动态内存分配

    3: 堆栈的原理:堆栈 百科

    1:自动释放池的常见问题:

    较大的循环时如果不及时释放,可能会导致内存暴涨。

    for (int i = 0; i < 100000; i ++) {

    @autoreleasepool {  //解决方案:逐条释放,避免暴涨

    NSString * log  = [NSString stringWithFormat:@"%d", i];

    NSLog(@"%@", log); }

    }

    2: 修饰符的常见问题:

    ARC提供四种修饰符,分别是strong, weak, autoreleasing, unsafe_unretained

    __strong:强引用,持有所指向对象的所有权,无修饰符情况下的默认值。如需强制释放,可置nil。

    比如我们常用的定时器:

    NSTimer * timer = [NSTimer timerWith...];

    相当于

    NSTimer * __strong timer = [NSTimer timerWith...];

    当不需要使用时,强制销毁定时器

    [timer invalidate];

    timer = nil;

    __weak:弱引用,不持有所指向对象的所有权,引用指向的对象内存被回收之后,引用本身会置nil,避免野指针。

    比如避免循环引用的弱引用声明:

    __weak __typeof(self) weakSelf = self;

    ps: 诸如网络请求的时候避免弱指针丢掉,往往需要在block内部从新strong下该指针。

    __strong __typeof(weakSelf) strongSelf = weakSelf;

    __autoreleasing:自动释放对象的引用,一般用于传递参数

    比如一个读取数据的方法

    - (void)loadData:(NSError **)error;

    当你调用时会发现这样的提示

    NSError * error;

    [dataTool loadData:(NSError *__autoreleasing *)]

    这是编译器自动帮我们插入以下代码

    NSError * error;

    NSError * __autoreleasing tmpErr = error;

    [dataTool loadData:&tmpErr];

    __unsafe_unretained:为兼容iOS5以下版本的产物,可以理解成MRC下的weak,现在基本用不到,这里不作描述。

    3.  属性的内存管理

    ObjC2.0引入了@property,提供成员变量访问方法、权限、环境、内存管理类型的声明,下面主要说明ARC中属性的内存管理。

    属性的参数分为三类,基本数据类型默认为(atomic,readwrite,assign),对象类型默认为(atomic,readwrite,strong),其中第三个参数就是该属性的内存管理方式修饰,修饰词可以是以下之一:

    1)assign:直接赋值

    assign一般用来修饰基本数据类型

    @property (nonatomic, assign) NSInteger count;

    当然也可以修饰ObjC对象,但是不推荐,因为被assign修饰的对象释放后,指针还是指向释放前的内存,在后续操作中可能会导致内存问题引发崩溃。(!!!!!bug预警)

    2)retain:release旧值,再retain新值(引用计数+1)

    retain和strong一样,都用来修饰ObjC对象。

    使用set方法赋值时,实质上是会先保留新值,再释放旧值,再设置新值,避免新旧值一样时导致对象被释放的的问题。

    MRC写法如下

    - (void)setCount:(NSObject *)count {

    [count retain];

    [_count release];

    _count = count;

    }

    ARC对应写法

    - (void)setCount:(NSObject *)count {

    _count = count;

    }

    3)copy:release旧值,再copy新值(拷贝内容)

    一般用来修饰String、Dict、Array等需要保护其封装性的对象,尤其是在其内容可变的情况下,因此会拷贝(深拷贝)一份内容給属性使用,避免可能造成的对源内容进行改动。

    使用set方法赋值时,实质上是会先拷贝新值,再释放旧值,再设置新值。

    实际上,遵守NSCopying的对象都可以使用copy,当然,如果你确定是要共用同一份可变内容,你也可以使用strong或retain。

    @property (nonatomic, copy) NSString * name;

    4)weak:ARC新引入修饰词,可代替assign,比assign多增加一个特性(置nil,见上文)。  weak和strong一样用来修饰ObjC对象。

    使用set方法赋值时,实质上不保留新值,也不释放旧值,只设置新值。

    比如常用的代理的声明    

     @property (weak) id delegate;

    Xib控件的引用

    @property (weak, nonatomic) IBOutlet UIImageView *productImage;

    5)strong:ARC新引入修饰词,可代替retain

    可参照retain,这里不再作描述。

    4. block的内存管理

    iOS中使用block必须自己管理内存,错误的内存管理将导致循环引用等内存泄漏问题,这里主要说明在ARC下block声明和使用的时候需要注意的两点:

    1)如果你使用@property去声明一个block的时候,一般使用copy来进行修饰(当然也可以不写,编译器自动进行copy操作),尽量不要使用retain。

    @property (nonatomic, copy) void(^block)(NSData * data);

    2)block会对内部使用的对象进行强引用,因此在使用的时候应该确定不会引起循环引用,当然保险的做法就是添加弱引用标记。

    __weak typeof(self) weakSelf = self;

    相关文章

      网友评论

          本文标题:iOS中结合代码看内存管理(一)

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