非ARC开发的内存管理

Posted SSIrreplaceable

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了非ARC开发的内存管理相关的知识,希望对你有一定的参考价值。

一. 内存管理原则

  1. retain和release配对使用;

  2. 只要出现retain、alloc、copy中的其中一个,就要用一次release;

  3. 只要retainCount为0,系统会自动调用dealloc

  4. @property中使用的关键字

    readwrite:属性会被当成读写的,默认
    readonly:属性只可读不可写
    assign:不会使引用计数加1,常用于数值
    retain:会使引用计数加1,只在非ARC中使用
    copy:建立一个索引计数为1的对象,在赋值时使用传入值的一份拷贝
    nonatomic:非原子性访问,多线程并发访问会提高性能
    atomic:原子性访问
    strong:打开ARC时才会使用,相当于retain。
    weak:打开ARC时才会使用,相当于assign,可以把对应的指针变量置为nil。

二. 属性中没有类类型的属性的内存管理

  1. 只要遵循“创建一个对象时,必须有一次release”即可。
  2. 如下面代码
---------- 如下,Dog类中属性的类型只有int,没有类类型的属性

#import <Foundation/Foundation.h>

@interface Dog : NSObject

@property (nonatomic, assign) int age;

@end

@implementation Dog

- (void)dealloc 

    NSLog(@"%s", __func__);

    [super dealloc];


@end


---------- 下面是关于Dog对象的内存管理

    // 方式一
    Dog *dog1 = [[[Dog alloc] init] autorelease];
    // 使用dog
    // 使用dog代码....

    // 方式二
    Dog *dog2 = [[Dog alloc] init];
    // 使用dog
    // 使用dog代码....
    // 使用完后release
    [dog2 release];

提示:
NSArray *arr = [NSArray array]; 和 NSArray *arr = @[]; 等价,内部已经有了一个autorelease,不需要重复写release

三. 属性中有类类型的属性的内存管理

  1. 根据谁使用谁撤销的原则,在dealloc方法中必须设置类类型的属性为空,即给类类型的属性来一次release

  2. 如下代码

A. 下面是不使用@property (nonatomic, retain) 的情况

---------- 关于Dog的类如上代码,这里只写Person类,下面是不使用@property (nonatomic, retain) 的情况 

#import <Foundation/Foundation.h>
#import "Dog.h"

@interface Person : NSObject

    Dog *_dog;


- (void)setDog:(Dog *)dog;
- (Dog *)dog;
@end

@implementation Person

- (void)dealloc 
    // 必须设置为nil,相当于对self.dog一次release
    // 保证Person对象不在的时候,dog的引用计数减一,因为是Person引用了一次
    self.dog = nil;

    [super dealloc];


- (void)setDog:(Dog *)dog 

    if (_dog != dog) 
        [_dog release];
        _dog = [dog retain];
    


- (Dog *)dog 
    return _dog;


@end


---------- 关于使用Person类的内存管理

    Person  *person = [[[Person alloc] init] autorelease];
    Dog *dog = [[[Dog alloc] init] autorelease];
    person.dog = dog;
    person.dog = dog;// 即使有第二次赋值,引用计数器也不会加一

    NSLog(@"person---%ld", person.retainCount);
    NSLog(@"person.dog----%ld", person.dog.retainCount);

运行结果:



B. 下面是使用@property (nonatomic, retain) 的情况
这样的好处是不用手动去写类类型的属性的setter方法
上面的Person类可以改成

#import <Foundation/Foundation.h>
#import "Dog.h"

@interface Person : NSObject

@property (nonatomic, retain) Dog *dog;

@end

@implementation Person

- (void)dealloc 
    // 必须设置为nil,相当于对self.dog一次release
    // 保证Person对象不在的时候,dog的引用计数减一,因为是Person引用了一次
    self.dog = nil;

    [super dealloc];


@end

修改后的运行结果一样:


四. copy属性的作用

  1. copy属性是完全把对象重新拷贝了一份,计数器从新设置为1,和之前拷贝的数据完全脱离关系

  2. 和retain一样,如果不使用@property (nonatomic, copy) 就必须自己写下面的代码

@property (nonatomic, copy) NSString *string;
 
- (NSString *) string 
  return _string;


- (void)setString:(NSString *)newStr 

    if (_string != newStr) 
        [_string release];
        _string = [newStr copy];

以上是关于非ARC开发的内存管理的主要内容,如果未能解决你的问题,请参考以下文章

iOS开发ARC内存管理技术要点

iOS开发ARC内存管理技术要点

内存管理的思考方式2(ARC下)

iOS开发ARC内存管理技术要点

平铺 PDF 视图正在泄漏内存(非 ARC)

iOS之内存管理(ARC)