OC05_内存管理

(一). 引用计数
main.m

ARC 自动引用计数,Automatic Reference Counting.

MRC 手动引用计数,Manual Refernce Counting.

内存管理机制:引用计数 retainCount.
每个对象都有引用计数.
引用计数的作用:标记有多少个指针指向这个内存空间.

为什么要标记?
为了避免其他指针访问这段内存时出现问题(野指针*访问*).
野指针不是问题,野指针的访问才是问题.

int main(int argc, const char * argv[]) {

引用计数的加法方法.
1.alloc.引用计数 +1
Person *person = [[Person alloc] init];
NSLog(@“%ld”, person.retainCount);

person的引用计数

2. retain.引用计数 +1
Person *newPerson = person;   // 把person的地址给newPerson,此时的引用计数依然为1,如果此时释放内存,就会造成其中一个指针为野指针,为了解决这个问题,用retain.

Person *newPerson = [person retain];
NSLog(@"%ld, %ld”, newPerson.retainCount, person.retainCount);   // 此时newPerson的引用计数为2,因为我们把person的引用计数变成了2,然后用newPerson去指向这个地址,这个地址背后所对应的引用计数为2,注意与下面的copy区分.

newPerson和person的引用计数

3. release.引用计数 -1
[person release];
[person release];   // 如果内存的引用计数为0,系统会自动调用”.m”文件中的dealloc方法--触发内存销毁的方法(如下,次方法,是默认不写的).

调用dealloc方法
Person.m

#import "Person.h"

@implementation Person

内存销毁法
dealloc(销毁) 和 alloc(开辟) 对应.
当引用计数变为0时,自动调用dealloc方法.
- (void)dealloc {
    NSLog(@"对象所在的内存销毁");
    [super dealloc];
}

@end

main.m

此时person已经release了两次(此时release两次newPerson和release两次person是等同效果),我们打印newPerson和person的引用计数.
NSLog(@“%ld, %ld”, newPerson.retainCount, person.retainCount);
    return 0;
}

触发dealloc之后,newPerson和person的引用计数
其实此时newPerson和person的引用计数已经为0,但是计算机取不到0,它只好打印最接近0之前的状态.
main.m

3.copy.
Person *ppp = [[Person alloc] init];
NSLog(@"ppp的引用计数为:%ld", ppp.retainCount);
Person *newPPP = [ppp copy];   // 复制ppp的内容,然后用一个newPPP来接受ppp的内容,但此时程序会崩溃,所以要在”.m”文件中写入一个拷贝缓冲池来解决拷贝之后:"-[Person copyWithZone:]: unrecognized selector sent to instance 0x10011486"的问题.
NSLog(@"再次打印ppp的引用计数为:%ld", ppp.retainCount);   // 此时再打印ppp的引用计数,结果并未改变,仍然为1,说明,copy的作用只是复制内容.
NSLog(@"newPPP的引用计数为:%ld", newPPP.retainCount);   // 此时打印newPPP的引用计数,结果为1,说明,copy之后的内容被newPPP接受了.
[ppp retain];
NSLog(@"再次打印ppp的引用计数为:%ld", ppp.retainCount);   // 将ppp的引用计数再次retain,然后打印.

打印结果
Person.m

- (id)copyWithZone:(NSZone *)zone {
    // zone 拷贝缓冲池.
    // 作用: 确保两个对象的信息除地址之外其它都一样.
    Person *p = [[Person allocWithZone:zone] init];
    p.name = self.name;
    p.age = self.age;
    return p;  
}

(二). 自动释放
main.m

自动释放池,autoReleasePool
@autorelease {
    Person *ppp = [[Person alloc] init];
    [ppp retain];
    [ppp retain];

相当于给ppp做了一个标记,延迟了它的释放时间.
    [ppp autorelease];
        NSLog(@"%ld", ppp.retainCount);
        [ppp autorelease];
        NSLog(@"%ld", ppp.retainCount);
        [ppp autorelease];
        NSLog(@"%ld", ppp.retainCount);
    }
    return 0;
}

延迟释放结果
当程序运行至autoreleasepool时,必须等程序执行到括号外面之后,ppp才释放内存.

(三). 内存管理的原则
main.m

int main(int argc, const char * argv[]) {

1.当看到alloc, retain, copy的时候, 需要对应的内存管理,哪个对象对应+1,就对哪个对象进行release(autorelease);
2.看不到,则不管.

Person *person1 = [[Person alloc] init];   // 创建一个person1对象.
Person *person2 = [person1 retain];   // 使person1的引用计数加一,用person2来接收它.
Person *person3 = [person2 retain];   // 使person2的引用计数加一,用person3来接收它.
Person *person4 = [person3 copy];   // 复制person3的内容,用person4来接收它.
Person *person5 = person4;   // 将person4的内容给person5.
NSLog(@"person1的引用计数为:%ld", person1.retainCount);
NSLog(@"person4的引用计数为:%ld", person4.retainCount);
NSLog(@"person5的引用计数为:%ld", person5.retainCount);

引用计数打印结果

[person1 release];
[person2 release];
[person3 release];
[person4 release];
    return 0;
}

触发dealloc方法
第一次触发dealloc方法是将person1内存释放.
第二次触发dealloc方法是将person4内存释放.
剩下的person5,变成了野指针.

(四). 如何用自动释放池,管理便利构造器.
在Person.h文件中添加两个属性,自定义初始化,便利构造器.

#import <Foundation/Foundation.h>

@interface Person : NSObject<NSCopying>


@property(nonatomic, retain)NSString *name;
@property(nonatomic, assign)NSInteger age;


- (instancetype)initWithName:(NSString *)name
                         age:(NSInteger)age;


+ (instancetype)personWithName:(NSString *)name age:(NSInteger)age;

@end

Person.m

#import "Person.h"

@implementation Person

- (instancetype)initWithName:(NSString *)name
                         age:(NSInteger)age {
    self = [super init];
    if (self) {
        _name = name;
        _age = age;
    }
    return self;
}


+ (instancetype)personWithName:(NSString *)name age:(NSInteger)age {

// 在便利构造器中创建一个person对象,并加入自动释放池(以下是三种释放内存的写法.)
(1).
Person *person = [[Person alloc] initWithName:name age:age];   
[person autorelease];
return person;

(2).  
Person *person = [[Person alloc] initWithName:name age:age];
return [person autorelease];

(3).    
    return [[[Person alloc] initWithName:name age:age] autorelease];

}

@end

main.m

@autoreleasepool {
        // 在自动释放池中用一个Person类调用便利构造器方法,并打印对象p的name属性.
        Person *p = [Person personWithName:@"哈哈" age:100 ];
        NSLog(@"%@", p.name);
}

Person.m

#import "Person.h"

@implementation Person

没有在".h"中声明,直接在".m"中写的方法实现,此方法为私有方法,只能在".m"中使用.
- (void)sayHi {
    NSLog(@"你好!~");
}

用一个方法A,在A方法中调用该私有方法 - (void)sayHi 方法(此A方法省略在”.h”中的声明过程,只写在”.m”中的实现过程).
-(void)A {
    [self sayHi]   // 该私有方法为对象方法,所以在便利构造器中调用该私有方法的时候,要先创建一个对象,因为便利构造器是类方法.
}
@end
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值