OC05_内存管理

来源:互联网 发布:淘宝怎么弄全球购图标 编辑:程序博客网 时间:2024/06/18 09:19

(一). 引用计数
main.m

ARC 自动引用计数,Automatic Reference Counting.MRC 手动引用计数,Manual Refernce Counting.内存管理机制:引用计数 retainCount.每个对象都有引用计数.引用计数的作用:标记有多少个指针指向这个内存空间.为什么要标记?为了避免其他指针访问这段内存时出现问题(野指针*访问*).野指针不是问题,野指针的访问才是问题.int main(int argc, const char * argv[]) {引用计数的加法方法.1.alloc.引用计数 +1Person *person = [[Person alloc] init];NSLog(@“%ld”, person.retainCount);

person的引用计数

2. retain.引用计数 +1Person *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