文章目录持有的定义持有的方式通过创建持有 (alloc, new, copy, mutablecopy)通过retain 主动持有不持有通过非创建方法拿到的对象通过 autorelease 转移所有权属性关键字与引用计数的关系strongweakassigndealloc 完整写法copyretainMRC自动释放池对象的生命周期由 **引用计数(retain count)**决定当对象的引用计数大于 0 的时候, 该对象可以存活, 当引用计数等于 0 的时候, 对象就需要被销毁影响引用计数的操作操作结果alloc/new/copy1retain1release-1autorelease延迟 -1 0调用 dealloc释放内存retainCount: 查看计数当对象的引用计数为 0 的时候, 程序会自动调用该对象的 dealloc 方法来销毁它核心法则:谁alloc/new/copy/mutableCopy - 谁 release谁 retain - 谁 release不是你创建的, 不是你 retain 的 - 不要 release准确来说, OC 内存管理的真正核心是一套所有权Ownership契约, 谁持有对象, 谁就有责任释放它, 引用计数只是这套契约的实现手段持有的定义代码让对象的引用计数 1, 并且有义务在不需要的时候让它 - 1, 不是所有拿到对象的指针的地方都持有它一个对象可以被多个持有者同时持有, 只有所有持有者都放弃后才能真正销毁持有的方式通过创建持有 (alloc, new, copy, mutablecopy)通过这四种方式创建的对象,返回的对象由你持有, 必须负责 releaseNSObject*a[[NSobject alloc]init];NSObject*b[NSobject new];NSString*c[somestr copy];NSMutableString*d[someStr mutableCopy];用完必须 release[a release]; [b release]; [c release]; [d release];通过retain 主动持有拿到了别人的对象, 想让它活的久一点 ,就需要 retain-(void)setChild:(Person*)child{[_child release];// 先舍弃旧的对象_chile[child retain];// 持有新对象}不持有通过非创建方法拿到的对象方法名不以alloc/new/copy/mutableCopy开头返回的是 autorelease 对象你不持有它不能 releaseobjc// 以下对象你不持有不要 releaseNSString*s[NSString stringWithFormat:hello %d,42];NSArray*a[NSArray arrayWithObjects:x,y,nil];NSDate*d[NSDate date];// 这里直接用没有问题NSLog(% % %,s,a,d);// 不要这样做// [s release]; // 错误没有持有它多余的 release 导致崩溃这些对象被放进了 autorelease pool会在 pool drain 时自动释放。通过 autorelease 转移所有权autorelease的语义是“我现在放弃所有权但不立刻 -1等 pool drain 时再 -1”。常用于从方法返回对象时objc// 工厂方法的标准写法(instancetype)personWithName:(NSString*)name{Person*p[[Person alloc]initWithName:name];return[p autorelease];// alloc 让 count1autorelease 把释放权交给 pool// 调用者收到的是一个不归你管的对象}属性关键字与引用计数的关系strong赋值时引用计数1持有者销毁或属性被重新赋值时-1对应 MRC 下的retainweak赋值时引用计数不变不持有对象当对象被销毁时weak 指针自动置 nil常用于解决循环引用delegate、block 中的 selfassign引用计数不变纯粹的指针赋值对象销毁后不会自动置 nil野指针风险一般只用于基本数据类型int、float、BOOL 等assign 只用于基本数据类型当一个属性被assign修饰时它仅仅是简单地记录了内存地址。释放时不置空当该对象因为引用计数归零被销毁时assign修饰的指针依然指向那块已经被回收的内存区域。造成野指针// delegate 对象销毁后_delegatesomeObj;// assign直接指针赋值不 retain// someObj 在外部被 release销毁[_delegate doSomething];// 崩溃_delegate 是野指针dealloc 完整写法-(void)dealloc{// retain/copy 属性release 并置 nil[_name release],_namenil;[_title release],_titlenil;[_children release],_childrennil;// assign 属性对象只置 nil不 release你没持有_delegatenil;// assign 属性基本类型不需要任何操作// _count、_flag 等不用管[superdealloc];// 必须最后调用释放父类持有的成员}copy赋值时对原对象调用copy创建一个新对象新对象引用计数为1原对象引用计数不变常用于 NSString、Block防止外部修改影响内部状态-(void)setName:(NSString*)name{if(_name!name){[_name release];_name[name copy];// copy 出一个新对象引用计数1}}retainMRC赋值时引用计数1即 ARC 下strong的前身retain —- setter持有新值, 释放旧值-(void)setName:(NSString*)name{if(_name!name){// 必须判断自赋值[_name release];// 如果不判断self.name _name 时_name[name retain];// 先 release 让 count0对象被销毁}// 再 retain 访问已销毁对象 → 崩溃}在上面的 setter 方法中先判断 _item 与被传入的 FKItem 对象是否相等也是很有必要的。如果不进行这个判断当程序多次将同一个 FKItem 对象传给该 setter 方法时将会导致每执行一次 setter 方法被传入的 FKItem 对象的引用计数都加 1这显然不是希望看到的结果。自动释放池自动释放池就是一个存放对象的容器, 自动释放池会保证延迟释放池中所有的对象. 、- (id)autorelease:该方法不会改变对象的引用计数, 只是将对象添加到自动释放池中自动释放池预设了在将来某一个时间将要调用relese方法, 将对象的引用计数减一, 当自动释放池释放时 ,自动释放池中所有的对象都会执行 release 方法
Objective- C学习: 手动内存管理
发布时间:2026/6/6 15:16:21
文章目录持有的定义持有的方式通过创建持有 (alloc, new, copy, mutablecopy)通过retain 主动持有不持有通过非创建方法拿到的对象通过 autorelease 转移所有权属性关键字与引用计数的关系strongweakassigndealloc 完整写法copyretainMRC自动释放池对象的生命周期由 **引用计数(retain count)**决定当对象的引用计数大于 0 的时候, 该对象可以存活, 当引用计数等于 0 的时候, 对象就需要被销毁影响引用计数的操作操作结果alloc/new/copy1retain1release-1autorelease延迟 -1 0调用 dealloc释放内存retainCount: 查看计数当对象的引用计数为 0 的时候, 程序会自动调用该对象的 dealloc 方法来销毁它核心法则:谁alloc/new/copy/mutableCopy - 谁 release谁 retain - 谁 release不是你创建的, 不是你 retain 的 - 不要 release准确来说, OC 内存管理的真正核心是一套所有权Ownership契约, 谁持有对象, 谁就有责任释放它, 引用计数只是这套契约的实现手段持有的定义代码让对象的引用计数 1, 并且有义务在不需要的时候让它 - 1, 不是所有拿到对象的指针的地方都持有它一个对象可以被多个持有者同时持有, 只有所有持有者都放弃后才能真正销毁持有的方式通过创建持有 (alloc, new, copy, mutablecopy)通过这四种方式创建的对象,返回的对象由你持有, 必须负责 releaseNSObject*a[[NSobject alloc]init];NSObject*b[NSobject new];NSString*c[somestr copy];NSMutableString*d[someStr mutableCopy];用完必须 release[a release]; [b release]; [c release]; [d release];通过retain 主动持有拿到了别人的对象, 想让它活的久一点 ,就需要 retain-(void)setChild:(Person*)child{[_child release];// 先舍弃旧的对象_chile[child retain];// 持有新对象}不持有通过非创建方法拿到的对象方法名不以alloc/new/copy/mutableCopy开头返回的是 autorelease 对象你不持有它不能 releaseobjc// 以下对象你不持有不要 releaseNSString*s[NSString stringWithFormat:hello %d,42];NSArray*a[NSArray arrayWithObjects:x,y,nil];NSDate*d[NSDate date];// 这里直接用没有问题NSLog(% % %,s,a,d);// 不要这样做// [s release]; // 错误没有持有它多余的 release 导致崩溃这些对象被放进了 autorelease pool会在 pool drain 时自动释放。通过 autorelease 转移所有权autorelease的语义是“我现在放弃所有权但不立刻 -1等 pool drain 时再 -1”。常用于从方法返回对象时objc// 工厂方法的标准写法(instancetype)personWithName:(NSString*)name{Person*p[[Person alloc]initWithName:name];return[p autorelease];// alloc 让 count1autorelease 把释放权交给 pool// 调用者收到的是一个不归你管的对象}属性关键字与引用计数的关系strong赋值时引用计数1持有者销毁或属性被重新赋值时-1对应 MRC 下的retainweak赋值时引用计数不变不持有对象当对象被销毁时weak 指针自动置 nil常用于解决循环引用delegate、block 中的 selfassign引用计数不变纯粹的指针赋值对象销毁后不会自动置 nil野指针风险一般只用于基本数据类型int、float、BOOL 等assign 只用于基本数据类型当一个属性被assign修饰时它仅仅是简单地记录了内存地址。释放时不置空当该对象因为引用计数归零被销毁时assign修饰的指针依然指向那块已经被回收的内存区域。造成野指针// delegate 对象销毁后_delegatesomeObj;// assign直接指针赋值不 retain// someObj 在外部被 release销毁[_delegate doSomething];// 崩溃_delegate 是野指针dealloc 完整写法-(void)dealloc{// retain/copy 属性release 并置 nil[_name release],_namenil;[_title release],_titlenil;[_children release],_childrennil;// assign 属性对象只置 nil不 release你没持有_delegatenil;// assign 属性基本类型不需要任何操作// _count、_flag 等不用管[superdealloc];// 必须最后调用释放父类持有的成员}copy赋值时对原对象调用copy创建一个新对象新对象引用计数为1原对象引用计数不变常用于 NSString、Block防止外部修改影响内部状态-(void)setName:(NSString*)name{if(_name!name){[_name release];_name[name copy];// copy 出一个新对象引用计数1}}retainMRC赋值时引用计数1即 ARC 下strong的前身retain —- setter持有新值, 释放旧值-(void)setName:(NSString*)name{if(_name!name){// 必须判断自赋值[_name release];// 如果不判断self.name _name 时_name[name retain];// 先 release 让 count0对象被销毁}// 再 retain 访问已销毁对象 → 崩溃}在上面的 setter 方法中先判断 _item 与被传入的 FKItem 对象是否相等也是很有必要的。如果不进行这个判断当程序多次将同一个 FKItem 对象传给该 setter 方法时将会导致每执行一次 setter 方法被传入的 FKItem 对象的引用计数都加 1这显然不是希望看到的结果。自动释放池自动释放池就是一个存放对象的容器, 自动释放池会保证延迟释放池中所有的对象. 、- (id)autorelease:该方法不会改变对象的引用计数, 只是将对象添加到自动释放池中自动释放池预设了在将来某一个时间将要调用relese方法, 将对象的引用计数减一, 当自动释放池释放时 ,自动释放池中所有的对象都会执行 release 方法