设为首页 加入收藏

TOP

OC 知识:彻底理解 iOS 内存管理(MRC、ARC)(三)
2019-08-26 07:10:19 】 浏览:135
Tags:知识 彻底 理解 iOS 内存 管理 MRC ARC
家在使用房间
p.room = r; // [p setRoom:r] [r release]; // 释放房间 r

之后的内存表现为:

 

接着执行换房操作而不进行其他操作的话,

        // 3. 换房
        Room *r2 = [[Room alloc] init];
        r2.no = 444;
        p.room = r2;

内存的表现为:

 

最后执行完

        [r2 release];    // 释放房间 r2
        [p release];    // 释放玩家 p

内存的表现为:

 

可以看出房间 r 并没有被释放,这是因为在进行换房的时候,并没有对房间 r 进行释放。所以应在调用setter方法的时候,对之前的变量进行一次release操作。具体setter方法代码如下:

- (void)setRoom:(Room *)room // room = r
{
        // 将以前的房间释放掉 -1
        [_room release];     

        // 对房间的引用计数器+1
        [room retain];

        _room = room;
    }
}

这样在执行完p.room = r2;之后就会将 房间 r 释放掉,最终内存表现为:

 

4. 一个玩家使用一个游戏房间,不再使用游戏房间,将游戏房间释放掉之后,再次使用该游戏房间的情况

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // 1.创建两个对象
        Person *p = [[Person alloc] init];
        Room *r = [[Room alloc] init];
        r.no = 888;

        // 2.将房间赋值给人
        p.room = r; // [p setRoom:r]
        [r release];    // 释放房间 r  
        
        // 3.再次使用房间 r
        p.room = r;
        [r release];    // 释放房间 r  
        [p release];    // 释放玩家 p
    }
    return 0;
}

执行下面代码

        // 1.创建两个对象
        Person *p = [[Person alloc] init];
        Room *r = [[Room alloc] init];
        r.no = 888;

        // 2.将房间赋值给人
        p.room = r; // [p setRoom:r]
        [r release];    // 释放房间 r  

之后的内存表现为:

 

然后再执行p.room = r;,因为setter方法会将之前的Room实例对象先release掉,此时内存表现为:

 

此时_room、r 已经变成了一个野指针。之后再对野指针 r 发出retain消息,程序就会崩溃。所以我们在进行setter方法的时候,要先判断一下是否是重复赋值,如果是同一个实例对象,就不需要重复进行release和retain。换句话说,如果我们使用的还是之前的房间,那换房的时候就不需要对这个房间再进行release和retain。则setter方法具体代码如下:

- (void)setRoom:(Room *)room // room = r
{
    // 只有房间不同才需用release和retain
    if (_room != room) {    // 0ffe1 != 0ffe1
        // 将以前的房间释放掉 -1
        [_room release];

        // 对房间的引用计数器+1
        [room retain];

        _room = room;
    }
}
因为retain不仅仅会对引用计数器+1, 而且还会返回当前对象,所以上述代码可最终简化成:
- (void)setRoom:(Room *)room // room = r
{
    // 只有房间不同才需用release和retain
    if (_room != room) {    // 0ffe1 != 0ffe1
        // 将以前的房间释放掉 -1
        [_room release];      

        _room = [room retain];
    }
}

以上就是setter方法的最终形式。

6. @property参数

  • 在成员变量前加上@property,系统就会自动帮我们生成基本的setter/getter方法
@property (nonatomic) int val;
  • 如果在property后边加上retain,系统就会自动帮我们生成getter/setter方法内存管理的代码,但是仍需要我们自己重写dealloc方法
 @property(nonatomic, retain) Room *room;
  • 如果在property后边加上assign,系统就不会帮我们生成set方法内存管理的代码,仅仅只会生成普通的getter/setter方法,默认什么都不写就是assign
@property(nonatomic, assign) int val;

7. 自动释放池

当我们不再使用一个对象的时候应该将其空间释放,但是有时候我们不知道何时应该将其释放。为了解决这个问题,Objective-C提供了autorelease方法。

  • autorelease是一种支持引用计数的内存管理方式,只要给对象发送一条autorelease消息,会将对象放到一个自动释放池中,当自动释放池被销毁时,会对池子里面的所有对象做一次release操作

    注意,这里只是发送release消息,如果当时的引用计数(reference-counted)依然不为0,则该对象依然不会被释放。

  • autorelease方法会返回对象本身,且调用完autorelease方法后,对象的计数器不变
Person *p = [Person new];
p = [p autorelease];
NSLog(@"count = %lu", [p retainCount]); // 计数还为1

1. 使用autorelease有什么好处呢

  • 不用再关心对象释放的时间
  • 不用再关心什么时候调用release

2. autorelease的原理实质上是什么?

autorelease实际上只是把对release的调用延迟了,对于每一个autorelease,系统只是把该对象放入了当前的autorelease pool中,当该pool被释放时,该pool中的所有对象会被调用release。

3. autorelease的创建方法

  1. 使用NSAutoreleasePool来创建
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // 创建自动释放池
[pool release]; // [pool drain]; 销毁自动释放池
  1. 使用@autoreleasepool创建
@autoreleasepool
{ //开始代表创建自动释放池

} //结束代表销毁自动释放池

4. autorelease的使用方法

NSAutoreleasePool *autoreleasePool = [[NSAutoreleasePool alloc] init];
Person *p = [[[Person alloc] init] autorelease];
[autoreleaseP
首页 上一页 1 2 3 4 5 下一页 尾页 3/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇常用在线软件获取 下一篇BBWebImage 设计思路

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目