Objective - C基础: 第五天 - 3.set方法内存管理
在前面, 我们对OC的内存管理基本上有了一个认识, 也知道了多个对象的内存管理是如何处理, 虽然在前面的多对象内存管理符合内存管理的原则, 其实还有一定的小bug, 今天我们就来看看如何解决这个bug.
例子:
#import <Foundation/Foundation.h> #import "Car.h" @interface Person : NSObject { int _age; Car *_car; } - (void)setAge:(int)age; - (int)age; - (void)setCar:(Car *)car; - (Car *)car; @end @implementation Person - (void)setAge:(int)age { _age = age; } - (int)age { return _age; } - (void)setCar:(Car *)car { _car = [car retain]; } - (Car *)car { return _car; } - (void)dealloc { NSLog(@"%d岁的Person被释放.", _age); [super dealloc]; } @end
#import <Foundation/Foundation.h> @interface Car : NSObject { int _speed; } - (void)setSpeed:(int)speed; - (int)speed; @end @implementation Car - (void)setSpeed:(int)speed { _speed = speed; } - (int)speed { return _speed; } - (void)dealloc { NSLog(@"速度为%d的Car对象被回收了.", _speed); [super dealloc]; } @end
#import <Foundation/Foundation.h> #import "Car.h" #import "Person.h" int main(int argc, const char * argv[]) { Car *c1 = [[Car alloc]init]; c1.speed = 250; Person *p = [[Person alloc]init]; p.age = 20; [p release]; [c1 release]; return 0; }
这个例子和我们之前所看的多对象内存管理是一个原理, 有增有减, 一旦release之后, 所有对象都会被释放, 但如果改一下:
int main(int argc, const char * argv[]) { Car *c1 = [[Car alloc]init]; c1.speed = 250; Person *p = [[Person alloc]init]; p.age = 20; p.car = c1; [p release]; [c1 release]; return 0; }
问题1. 经过了p.car = c1; 这句代码之后, 那么car的引用计数就是2, 打印的结果也就只有Person被释放.
2015-01-26 14:38:43.066 2.set方法的内存管理[4557:447362] 20岁的Person被释放.
问题2. 如果p这个对象有钱了, 需要换车:
int main(int argc, const char * argv[]) { Car *c1 = [[Car alloc]init]; c1.speed = 250; Person *p = [[Person alloc]init]; p.age = 20; p.car = c1; Car *c2 = [[Car alloc]init]; c2.speed = 300; p.car = c2; [p release]; [c1 release]; return 0; }
那么c1呢? c1并没有被释放, 看看下面的示意图:
虽然在现实生活中是可以一个人拥有多部车, 但在OC中, 一旦你不用一个对象就必须的释放, 否则就会引起内存泄漏的问题.
问题3. 一旦p这个对象换车了, 如果它不用新车, 也必须得对新车进行一次release, 否则也会引起内存泄漏.
针对上面的三个问题, 其实我们可以添加两句代码解决, 比如:
#import "Person.h" @implementation Person - (void)setAge:(int)age { _age = age; } - (int)age { return _age; } - (void)setCar:(Car *)car { [_car release]; //对当前正在使用的车(旧车)进行release. _car = [car retain]; } - (Car *)car { return _car; } - (void)dealloc { // 当人被释放了, 那么车也要被释放 [_car release]; NSLog(@"%d岁的Person被释放.", _age); [super dealloc]; } @end
三个对象同时释放, 打印出来的结果:
2015-01-26 14:57:42.084 2.set方法的内存管理[4688:455689] 20岁的Person被释放. 2015-01-26 14:57:42.085 2.set方法的内存管理[4688:455689] 速度为250的Car对象被回收了. 2015-01-26 14:57:42.085 2.set方法的内存管理[4688:455689] 速度为300的Car对象被回收了.
但在这里还可以稍微进行一点优化, 免得以后引起一些不必要的问题:
#import "Person.h" @implementation Person - (void)setAge:(int)age { _age = age; } - (int)age { return _age; } - (void)setCar:(Car *)car { if (car != _car) { [_car release]; //对当前正在使用的车(旧车)进行release. _car = [car retain]; // 对新车进行一次retain } }
只有加上这个判断, 那么当你存入的对象如果和之前一样, 那么就不用做重复的操作, 不会引起不必要的问题, 比如:
int main(int argc, const char * argv[]) { Car *c1 = [[Car alloc]init]; c1.speed = 250; Person *p = [[Person alloc]init]; p.age = 20; p.car = c1; Car *c2 = [[Car alloc]init]; c2.speed = 300; p.car = c2; [c1 release]; p.car = c1; [p release]; [c2 release]; return 0; }
好了, 这次我们就讲到这里, 下次我们继续~~
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步