一、MRC——手动内存管理复习 1.例如,我这儿有一个Car类,当然要先关掉ARC——自动内存管理,否则手动内存管理的方法不能调用,关闭的方法前面已经讲过,在Target的Building Setting里面找到Automatic Reference Count 设置为NO 在Car.h文件中 #import <Foundation/Foundation.h> @interface Car : NSObject { NSString *_name; int _speed; } - (void)setName:(NSString *)name; - (NSString *)name; - (void)setSpeed:(int)speed; - (int)speed; - (void)run; @end 2.在Car.m文件中 #import “Car.h” @implementation Car - (void)setName:(NSString *)name { _name = name; } - (NSString *)name { return _name; } - (void)setSpeed:(int)speed { _speed = speed; } - (int)speed { return _speed; } - (void)run { NSLog(@“速度为%d的车,在行驶”,_speed); } - (void)dealloc { NSLog(@“名字为%@的车挂了。。。”,_name); [super dealloc]; } @end 3.我这儿还有一个Person类,在Person.h文件中 #import <Foundation/Foundation.h> #import “Car.h” @interface Person : NSObject { NSString *_name; Car *_car; } - (void)setName:(NSString *)name; - (NSString *)name; - (void)setCar:(Car *)car; - (Car *)car; - (void)drive; @end 4.在Person.m文件中 #import “Person.h” @implementation Person - (void)setName:(NSString *)name { _name = name; } - (NSString *)name { return _name; } - (void)setCar:(Car *)car { [_car release]; _car = [car retain]; } - (Car *)car { return _car; } - (void)drive { [_car run]; } - (void)dealloc { [_car release]; NSLog(@“人挂了。。。”); [super dealloc]; } @end 5.在main.m文件中 #import <Foundation/Foundation.h> #import “Person.h” int main(int argc, const char * argv[]) { void (^myBlock1)(void); myBlock1 = ^void(void){ @autoreleasepool { Person *fj = [[Person new] autorelease];//1 NSLog(@“fj = %lu”,fj.retainCount); fj.name = @“凤姐”; Car *bmw = [[Car new] autorelease];//1 bmw.name = @“bmw”; NSLog(@“bmw = %lu”,bmw.retainCount); bmw.speed = 100; fj.car = bmw;//2 NSLog(@“fj = %lu”,fj.retainCount); NSLog(@“bmw = %lu”,bmw.retainCount); [fj drive]; NSLog(@“fj = %lu”,fj.retainCount); NSLog(@“bmw = %lu”,bmw.retainCount); [fj drive]; NSLog(@“fj = %lu”,fj.retainCount); NSLog(@“bmw = %lu”,bmw.retainCount); Car *benz = [[Car new] autorelease]; benz.name = @“benz”; NSLog(@“fj = %lu”,fj.retainCount); NSLog(@“bmw = %lu”,bmw.retainCount); NSLog(@“benz = %lu”,benz.retainCount); benz.speed = 400; fj.car = benz; NSLog(@“fj = %lu”,fj.retainCount); NSLog(@“bmw = %lu”,bmw.retainCount); NSLog(@“benz = %lu”,benz.retainCount); [fj drive]; NSLog(@“fj = %lu”,fj.retainCount); NSLog(@“bmw = %lu”,bmw.retainCount); NSLog(@“benz = %lu”,benz.retainCount); } }; myBlock1(); return 0; } 7.输出: fj = 1 bmw = 1 fj = 1 bmw = 2 速度为100的车,在行驶 fj = 1 bmw = 2 速度为100的车,在行驶 fj = 1 bmw = 2 fj = 1 bmw = 2 benz = 1 fj = 1 bmw = 1 benz = 2 速度为400的车,在行驶 fj = 1 bmw = 1 benz = 2 名字为bmw的车挂了。。。 名字为benz的车挂了。。。 人挂了。。。 二、总结 1.这里主要是复习MRC:手动内存管理 2.MRC模式下,setter方法要写为release旧的,retain新的 - (void)setCar:(Car *)car { [_car release]; _car = [car retain]; } 3.MRC模式下,dealloc方法,要releaseOC对象类型的所有属性 - (void)dealloc { [_car release]; NSLog(@“人挂了。”); [super dealloc]; } 3.dealloc方法最后,需要调用父类的dealloc方法 4.这里还顺便复习了一下block的声明,和赋值 block的声明 void (^myBlock1)(void); block的赋值 myBlock1 = ^void(void){ //代码块 }; 5.这里还顺便复习了一下@autoreleasepool{ Person *fj = [[Person new] autorelease]; } 大括号结束时,会对所有加入到自动释放池的对象发送一个release消息 怎么加入自动释放池 Person *fj = [[Person new] autorelease]; 即可 三、还有一个问题,如果旧对象与新对象是同一个对象,会出现什么样的情况 1.例如,Person对象的_car属性的setter方法如下: - (void)setCar:(Car *)car { [_car release]; _car = [car retain]; } 这样确实可以保证在从宝马换车换到奔驰时,宝马可以顺利释放,但如果是从宝马换成宝马呢,也就是说凤姐不是真正的换车,而是还用宝马这辆车呢,例如 Person *fj = [Person new]; fj.name = @“凤姐”; Car *bmw = [Car new]; bmw.name = @“宝马”; bmw.speed = 100; fj.car = bmw; [fj drive]; [bmw release]; fj.car = bmw; [fj drive]; [fj release]; 这时候,执行到[bmw release]; fj.car = bmw;这两句话的时候,会报僵尸对象错误,因为在bmw被创建的时候,bmw的引用计数器是1,在第一次fj.car = bmw;的时候,bmw的引用计数器被设为2了,在[bmw release];的时候,bmw的引用计数器又为1了,在第二次fj.car = bmw;的时候,是怎么执行的,是不是如下这样执行的: [_car release]; _car = [car retain]; 这时候,在[_car release];的时候,bmw的引用计数器就为0了,还能执行下面的_car = [car retain];吗,不能了,因为car指向的对象是bmw,它已经被释放了,这时候就会报僵尸对象错误, 好了,怎么解决, 是不是我先判断一下_car 和 car是不是都指向bmw啊,如果都指向bmw,那我还用做任何事情吗,不用,如果不都指向bmw,那我怎么样,是不是release旧的,retain新的啊,所以,我这么写 - (void)setCar : (Car *)car{ if(_car != car) { [_car release]; _car = [car retain]; } } 这才是属性是OC对象的时候,setter方法的最终写法,如果属性不是OC对象,例如是int _age;那setter方法就直接赋值就可以了,_age = age;