1 MRC练习

1.1 问题

引用计数是Objective-C语言采用的一种内存管理技术,当一个对象被创建在堆上后,该对象的引用计数就自动设置为1,如果在其它对象中的对象成员需要持有这个对象时,则该对象的引用计数被加上1,此时如果该对象被释放,内存管理程序将首先把该对象的引用计数减1,然后判断该对象的引用计数是否为0,由于其它对象在持有该对象时将引用计数加了1,所以此时该对象的引用计数减1后不为0,则内存管理程序将不会释放该对象。直到持有该对象的其它对象也被释放时,该对象的引用计数再次减1,变为0时,该对象在堆上所占的存储空间才被释放。

引用计数技术的使用能够实现对资源的自动管理。

iOS5.0开始引入自动引用计数技术,iOS7.0以后则默认使用自动引用计数技术。自动引用计数技术,简称为ARC,由于ARC的出现,相对以前的方式被称为手动引用计数技术,简称为MRC。

1.2 方案

本案例是强制使用MRC(手动引用计数技术)来管理对象的引用计数的一个练习。由于iOS7.0以后使用Xcode创建的工程默认使用ARC(自动引用计数技术),所以需要强制转换回MRC。转换的方法如下步骤:

首先,创建一个工程,然后选择“工程导航”中的“工程项”,如图-1所示:

图-1

然后在右边窗口中选择Build Settings,如图-2所示:

图-2

下一步选择All选项,如图-3所示:

图-3

最后,向下滚动屏幕,找到Apple LLVM 5.1 – Language – Objective C中的Objective-C Automatic Reference Counting,将右边的选项选择为NO。如图-4所示:

1.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:定义Integer类

首先,在Day03工程中新添加Integer.h文件,用于定义新的类Integer。

代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. @interface Integer : NSObject
  3. @property int integer;
  4. -(void)print;
  5. @end

在上述代码中,为Integer类添加一个属性,整型变量integer;然后为Integer类添加一个方法print,用于将属性的值输出到控制台。

然后,在类Integer的实现部分,即在Integer.m文件中,添加print方法的实现。代码如下所示:

  1. #import "Integer.h"
  2. @implementation Integer
  3. -(void)print
  4. {
  5. NSLog(@"%d", self.integer);
  6. }
  7. @end

步骤二: 查看初始引用计数值

在Day03工程中新添加MRC.m文件,用于主程序,在主程序中定义Integer的对象并查看该对象的引用计数。此时对象的引用计数值为1。

代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. #import "Integer.h"
  3. int main(int argc, const char * argv[])
  4. {
  5. @autoreleasepool {
  6. // insert code here...
  7. Integer *int1 = [[Integer alloc] init];
  8. NSLog(@"%ld", [int1 retainCount]);
  9. }
  10. return 0;
  11. }

上述代码中,以下代码:

  1. NSLog(@"%ld", [int1 retainCount]);

retainCount消息将得到对象int1当前的引用计数值。

步骤三:增加引用

在主程序中添加另一个引用,再查看该对象的引用计数。此时对象的引用计数值不会发生变化,仍然为1。

代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. #import "Integer.h"
  3. int main(int argc, const char * argv[])
  4. {
  5. @autoreleasepool {
  6. // insert code here...
  7. Integer *int1 = [[Integer alloc] init];
  8. NSLog(@"%ld", [int1 retainCount]);
  9. Integer *int2 = int1;
  10. NSLog(@"%ld", [int1 retainCount]);
  11. }
  12. return 0;
  13. }

上述代码中,以下代码:

  1. Integer *int2 = int1;

仅仅是定义了一个指针,将其初始化为int1,这将不会改变对象int1的引用计数值。

步骤四:增加引用计数

由于此时有两个指针指向对象int1,int1的引用计数应该变为2。但在MRC下,要想将int1的引用计数值加1,必须手动添加retain消息才能实现。

代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. #import "Integer.h"
  3. int main(int argc, const char * argv[])
  4. {
  5. @autoreleasepool {
  6. // insert code here...
  7. Integer *int1 = [[Integer alloc] init];
  8. NSLog(@"%ld", [int1 retainCount]);
  9. Integer *int2 = int1;
  10. NSLog(@"%ld", [int1 retainCount]);
  11. [int2 retain];
  12. NSLog(@"%ld", [int1 retainCount]);
  13. }
  14. return 0;
  15. }

上述代码中,以下代码:

  1. [int2 retain];
  2. NSLog(@"%ld", [int1 retainCount]);

是向对象int2发送消息retain,该消息会使int2指向的对象的引用计数加1,由于int2与int1共同指向一个对象,所以向对象int1发送retainCount消息,得到的值为2。

步骤五:减少引用计数

在MRC下,要想将int1的引用计数值减1,必须手动添加release消息才能实现。

代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. #import "Integer.h"
  3. int main(int argc, const char * argv[])
  4. {
  5. @autoreleasepool {
  6. // insert code here...
  7. Integer *int1 = [[Integer alloc] init];
  8. NSLog(@"%ld", [int1 retainCount]);
  9. Integer *int2 = int1;
  10. NSLog(@"%ld", [int1 retainCount]);
  11. [int2 retain];
  12. NSLog(@"%ld", [int1 retainCount]);
  13. [int2 release];
  14. NSLog(@"%ld", [int1 retainCount]);
  15. }
  16. return 0;
  17. }

上述代码中,以下代码:

  1. [int2 release];
  2. NSLog(@"%ld", [int1 retainCount]);

是向对象int2发送消息release,该消息会使int2指向的对象的引用计数减1,由于int2与int1共同指向一个对象,所以向对象int1发送retainCount消息,得到的值为1。

步骤六:释放对象

在MRC下,如果int1的引用计数值减1后值为0,则内存管理程序将把int1所占的内存空间释放掉。

代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. #import "Integer.h"
  3. int main(int argc, const char * argv[])
  4. {
  5. @autoreleasepool {
  6. // insert code here...
  7. Integer *int1 = [[Integer alloc] init];
  8. NSLog(@"%ld", [int1 retainCount]);
  9. Integer *int2 = int1;
  10. NSLog(@"%ld", [int1 retainCount]);
  11. [int2 retain];
  12. NSLog(@"%ld", [int1 retainCount]);
  13. [int2 release];
  14. NSLog(@"%ld", [int1 retainCount]);
  15. [int1 release];
  16. NSLog(@"%ld", [int1 retainCount]);
  17. int1 = nil;
  18. [int1 print];
  19. }
  20. return 0;
  21. }

上述代码中,以下代码:

  1. [int1 release];
  2. NSLog(@"%ld", [int1 retainCount]);

是向对象int1发送消息release,该消息会使int1指向的对象的引用计数减1,由于int1指向的对象的引用计数已经为1,再减1,将会变为0。此时int1所指向的对象被释放了。但是,如果此时向对象int1发送retainCount消息,得到的int1的引用计数值仍然为1,这是因为此时retainCount消息访问的int1的地址空间,是已经释放的空间,在释放前该空间的引用计数变量没有清0的缘故。

1.4 完整代码

本案例中,类Integer声明,即Integer.h文件,完整代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. @interface Integer : NSObject
  3. @property int integer;
  4. -(void)print;
  5. @end

类Integer实现,即Integer.m文件,完整代码如下所示:

  1. #import "Integer.h"
  2. @implementation Integer
  3. -(void)print
  4. {
  5. NSLog(@"%d", self.integer);
  6. }
  7. @end

主程序,即MRC.m,完整代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. #import "Integer.h"
  3. int main(int argc, const char * argv[])
  4. {
  5. @autoreleasepool {
  6. // insert code here...
  7. Integer *int1 = [[Integer alloc] init];
  8. NSLog(@"%ld", [int1 retainCount]);
  9. Integer *int2 = int1;
  10. NSLog(@"%ld", [int1 retainCount]);
  11. [int2 retain];
  12. NSLog(@"%ld", [int1 retainCount]);
  13. [int2 release];
  14. NSLog(@"%ld", [int1 retainCount]);
  15. [int1 release];
  16. NSLog(@"%ld", [int1 retainCount]);
  17. int1 = nil;
  18. [int1 print];
  19. }
  20. return 0;
  21. }

2 编写Student和Book类

2.1 问题

本案例需要创建一个Book类,类中有一个整型price属性,用于记录书的价格。还需要创建一个Student类,类中有两个带参属性,它们是整型的年龄age和类Book类型的book,分别用于存储学生的年龄和学生正在学习的书,并且有一个study方法,用于显示年龄为age的学生学习价格为book.price的书。

在主程序中创建Student类的一个对象和Book类的两个对象,首先让Student类的对象拥有一个Book类的对象,然后让Student类的对象更换了拥有对象,换成另一个Book类对象。

2.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:定义类Book

首先,在Day03工程中新添加Book.h文件,用于定义新的类Book。

代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. @interface Book : NSObject
  3. @property int price;
  4. @end

在上述代码中,定义了类Book,在类中有一个属性,是整型变量price,用于存储书的价格。

然后,在类Book的实现部分,即在Book.m文件中,添加dealloc方法,该方法在本类中实际上没有任何实际意义,只是在类的对象销毁时,在控制台上输出一个提示。

代码如下所示:

  1. #import "Book.h"
  2. @implementation Book
  3. -(void)dealloc{
  4. NSLog(@"书对象销毁了 price:%d",self.price);
  5. [super dealloc];
  6. }
  7. @end

dealloc方法不能在类外直接被调用,它是在一个对象被release并且对象的引用计数为0时,由内存管理程序调用的方法。

步骤二:定义类Student

首先,在Day03工程中新添加Student.h文件,用于定义新的类Student。

代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. #import "Book.h"
  3. @interface Student : NSObject
  4. {
  5. }
  6. @property(nonatomic,assign) int age;
  7. @property(nonatomic,retain) Book* book;
  8. -(void)study;
  9. @end

在上述代码中,定义了类Student,在类中有两个带参属性。

一个属性是整型变量age,如下代码所示:

  1. @property(nonatomic,assign) int age;

用于存储学生的年龄。它有两个参数,一个是nonatomic,它代表对属性赋值的时候不加锁,即在多线程环境下访问时可能会出现数据错误,如果需要在多线程环境下运行,为保证数据不会出现错误,可使用atomic参数,它会在对属性赋值的时候加锁。另一个参数是assign,对于C语言的基本数据类型,只能选取这个参数。

另一个属性是book,如下代码所示:

  1. @property(nonatomic,retain) Book* book;

用于存储学生正在学习的书。它有两个参数,一个是nonatomic,另一个参数是retain,该参数一般用于NSObject类及其子类的对象,这些对象在赋值时需要将引用计数加1,retain参数可以满足这样的需求。

然后,在类Student的实现部分,即在Student.m文件中,添加dealloc方法和study方法的实现。

代码如下所示:

  1. #import "Student.h"
  2. @implementation Student
  3. -(void)dealloc{
  4. //将所有引用类型的属性在此释放掉
  5. [self.book release];
  6. NSLog(@"学生对象销毁了,dealloc方法执行了");
  7. [super dealloc];
  8. }
  9. -(void)study{
  10. NSLog(@"学生 age:%d 学习书 price:%d 中的知识",self.age,self.book.price);
  11. }
  12. @end

dealloc方法在这个类中是必须有的,前面在讲到属性book的retain参数时,指出retain参数会将赋值给属性book的对象的引用计数加1,那么这个对象必须还要减1,其存储空间才能最终得到释放。但是只要Student类对象的存储空间没有释放,属性book的引用计数就不能减1,所以只有在Student类对象的存储空间释放时,通过dealloc将属性book的引用计数减1。

study方法要完成的工作是在控制台上输出学生的年龄和正在学习的书。

步骤三:在主程序中使用Student类和Book类

代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. #import "Student.h"
  3. int main(int argc, const char * argv[])
  4. {
  5. @autoreleasepool {
  6. Student* stu1 = [[Student alloc]init];
  7. stu1.age = 18;
  8. Book* sanguo = [[Book alloc]init];
  9. sanguo.price = 10;
  10. stu1.book = sanguo;//将书对象给学生对象
  11. NSLog(@"%ld", [sanguo retainCount]);
  12. Book* hongloumeng = [[Book alloc]init];
  13. hongloumeng.price = 20;
  14. stu1.book = hongloumeng;
  15. NSLog(@"%ld", [hongloumeng retainCount]);
  16. NSLog(@"%ld", [sanguo retainCount]);
  17. [hongloumeng release];
  18. [sanguo release];
  19. [stu1 study];
  20. [stu1 release];
  21. }
  22. return 0;
  23. }

在上述代码中,以下代码:

  1. Student* stu1 = [[Student alloc]init];
  2. stu1.age = 18;

定义了一个Student类的对象stu1,并将stu1的age属性赋值为18。

在上述代码中,以下代码:

  1. Book* sanguo = [[Book alloc]init];
  2. sanguo.price = 10;
  3. stu1.book = sanguo;//将书对象给学生对象
  4. NSLog(@"%ld", [sanguo retainCount]);

首先,定义了一个Book类的对象sanguo,并将sanguo的price属性赋值为10。然后,将stu1的book属性赋值为sanguo。我们知道book属性有一个参数是retain,它会将赋值给它的对象的引用计数加1,那么现在将sanguo赋值给stu1的book属性,sanguo的引用计数会加1,所以当我们查看sanguo的引用计数值时会发现是2。

在上述代码中,以下代码:

  1. Book* hongloumeng = [[Book alloc]init];
  2. hongloumeng.price = 20;
  3. stu1.book = hongloumeng;
  4. NSLog(@"%ld", [hongloumeng retainCount]);
  5. NSLog(@"%ld", [sanguo retainCount]);

首先,定义了一个Book类的对象hongloumeng,并将hongloumeng的price属性赋值为20。然后,将stu1的book属性重新赋值为hongloumeng。我们知道book属性有一个参数是retain,它会将赋值给它的对象的引用计数加1,那么现在将hongloumeng赋值给stu1的book属性,hongloumeng的引用计数会加1,所以当我们查看hongloumeng的引用计数值时会发现是2。但如果此时再查看sanguo的引用计数值时会发现变成了1,这是为什么呢?原因是Student类的book属性参数retain,除了会将赋值给它的对象的引用计数加1外,在加1之前,还会将先前赋值给它的对象的引用计数减1。如本案例中,先将stu1的book属性赋值为sanguo,然后重新赋值为hongloumeng,那么在给hongloumeng引用计数加1之前,先将sanguo的引用计数减了一个1。

在上述代码中,以下代码:

  1. [hongloumeng release];
  2. [sanguo release];

对hongloumeng对象进行释放,它不会被从存储空间中删除,因为release只会将hongloumeng的引用计数由2减为1。但是,对sanguo对象进行释放,就会被从存储空间中删除,因为release只会将sanguo的引用计数由1减为0。

在上述代码中,以下代码:

  1. [stu1 study];

是向对象stu1发送study消息时,因为hongloumeng的引用计数为1,所以它能显示出hongloumeng的价格。

在上述代码中,以下代码:

  1. [stu1 release];

是释放对象stu1,在stu1的存储空间被释放之前,还会先调用Student类的dealloc方法,在dealloc方法中,hongloumeng的引用计数由1减为0,所以hongloumeng的对象存储空间被释放。而stu1的引用计数一直为1,此时对其进行release,将减为0,stu1的存储空间被释放。

2.3 完整代码

本案例中,类Book声明,即Book.h文件,完整代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. @interface Book : NSObject
  3. @property int price;
  4. @end

类Book实现,即Book.m文件,完整代码如下所示:

  1. #import "Book.h"
  2. @implementation Book
  3. -(void)dealloc{
  4. NSLog(@"书对象销毁了 price:%d",self.price);
  5. [super dealloc];
  6. }
  7. @end

本案例中,类Student声明,即Student.h文件,完整代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. #import "Book.h"
  3. @interface Student : NSObject
  4. {
  5. }
  6. @property(nonatomic,assign) int age;
  7. @property(nonatomic,retain) Book* book;
  8. -(void)study;
  9. @end

类Student实现,即Student.m文件,完整代码如下所示:

  1. #import "Student.h"
  2. @implementation Student
  3. -(void)dealloc{
  4. //将所有引用类型的属性在此释放掉
  5. [self.book release];
  6. NSLog(@"学生对象销毁了,dealloc方法执行了");
  7. [super dealloc];
  8. }
  9. -(void)study{
  10. NSLog(@"学生 age:%d 学习书 price:%d 中的知识",self.age,self.book.price);
  11. }
  12. @end

主程序,即StudentBook.m,完整代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. #import "Student.h"
  3. int main(int argc, const char * argv[])
  4. {
  5. @autoreleasepool {
  6. Student* stu1 = [[Student alloc]init];
  7. stu1.age = 18;
  8. Book* sanguo = [[Book alloc]init];
  9. sanguo.price = 10;
  10. stu1.book = sanguo;//将书对象给学生对象
  11. NSLog(@"%ld", [sanguo retainCount]);
  12. Book* hongloumeng = [[Book alloc]init];
  13. hongloumeng.price = 20;
  14. stu1.book = hongloumeng;
  15. NSLog(@"%ld", [hongloumeng retainCount]);
  16. NSLog(@"%ld", [sanguo retainCount]);
  17. [hongloumeng release];
  18. [sanguo release];
  19. [stu1 study];
  20. [stu1 release];
  21. }
  22. return 0;
  23. }

3 编写父类Animal和子类Cat、Dog

3.1 问题

本案例需要创建一个Animal类,类中有一个方法叫shout的方法,该方法默认输出 "动物会叫",这个类作为父类,派生出两个子类Cat类和Dog类。

Cat类没有覆盖父类的shout方法,而Dog覆盖了父类的shout方法,改成自己的输出,"汪汪汪"。

分别调用cat、dog对象的shout方法。

3.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:定义类Animal

首先,在Day03-2工程中新添加Animal.h文件,用于定义新的类Animal。

代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. @interface Animal : NSObject
  3. @property int age;
  4. -(void)shout;
  5. @end

在上述代码中,定义了类Animal,在类中有一个属性,是整型变量age,用于存储动物的年龄。类中还有一个eat方法的声明。

然后,在类Animal的实现部分,即在Animal.m文件中,添加shout方法的实现,该方法在控制台上输出“动物会叫”。

代码如下所示:

  1. #import "Animal.h"
  2. @implementation Animal
  3. -(void)shout{
  4. NSLog(@"动物会叫");
  5. }
  6. @end

步骤二:定义类Cat

首先,在Day03-2工程中新添加Cat.h文件,用于定义新的类Cat。

代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. #import "Animal.h"
  3. @interface Cat : Animal
  4. @end

在上述代码中,以下代码:

  1. @interface Cat : Animal

是定义一个类Cat,继承父类Animal。

然后,在类Cat的实现部分,即在Cat.m文件中,什么都不做。

代码如下所示:

  1. #import "Cat.h"
  2. @implementation Cat
  3. @end

步骤三:定义类Dog

首先,在Day03-2工程中新添加Dog.h文件,用于定义新的类Dog。

代码如下所示:

  1. #import "Animal.h"
  2. @interface Dog : Animal
  3. @end

上述代码中,类Dog继承与父类Animal。

然后,在类Dog的实现部分,即在Dog.m文件中,覆盖父类Animal中的shout方法。该方法在控制台上输出“汪汪汪”。

代码如下所示:

  1. #import "Dog.h"
  2. @implementation Dog
  3. -(void)shout
  4. {
  5. NSLog(@"汪汪汪");
  6. }
  7. @end

Dog类中覆盖了Animal类中的方法后, Dog类中有两个shout方法,一个继承自Animal类的shout方法,另一个是是自定义的shout方法。

步骤四:在主程序中使用Animal类、Cat类和Dog类

代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. #import "Dog.h"
  3. #import "Cat.h"
  4. int main(int argc, const char * argv[])
  5. {
  6. @autoreleasepool {
  7. Animal* animal = [[Animal alloc]init];
  8. animal.age = 30;
  9. //Cat继承于Animal
  10. Cat* cat = [[Cat alloc]init];
  11. NSLog(@"cat age:%d",cat.age);
  12. [cat shout];
  13. //Dog继承于Animal
  14. Dog* dog = [[Dog alloc]init];
  15. dog.age = 18;//可以得到父类属性
  16. NSLog(@"dog age:%d",dog.age);
  17. [dog shout];
  18. }
  19. return 0;
  20. }

在上述代码中,以下代码:

  1. Animal* animal = [[Animal alloc]init];
  2. animal.age = 30;

定义了一个Animal类的对象animal,并将animal的age属性赋值为30。

在上述代码中,以下代码:

  1. //Cat继承于Animal
  2. Cat* cat = [[Cat alloc]init];

定义了一个Cat类的对象cat。

在上述代码中,以下代码:

  1. NSLog(@"cat age:%d",cat.age);

由于定义Cat类的对象cat后,没有为从Animal类继承过来的属性age赋值,所以输出的猫的年龄为0。

在上述代码中,以下代码:

  1. [cat shout];

对cat对象发送的shout消息,调用的是父类Animal中shout。因为定义Cat类时没有覆盖父类Animal类中的方法shout,所以在Cat类中只有从父类Cat中继承的shout方法。

在上述代码中,以下代码:

  1. //Dog继承于Animal
  2. Dog* dog = [[Dog alloc]init];
  3. dog.age = 18;//可以得到父类属性

定义了一个Dog类的对象dog,并对从Animal类继承过来的属性age赋值为18。

在上述代码中,以下代码:

  1. NSLog(@"dog age:%d",dog.age);

由于定义Dog类的对象dog后,已经为从Animal类继承过来的属性age赋值为18,所以输出的狗的年龄为18。

在上述代码中,以下代码:

  1. [dog shout];

对dog对象发送的shout消息,调用的是Dog类中shout。因为定义Dog类时已经覆盖父类Animal类中的方法shout,即在Dog类中有两个shout方法,一个是从父类Animal中继承的shout方法,另一个是自定义的shout。按照继承的语法规则,当向Dog类的对象dog发送shout消息时,优先调用自定义的shout方法。

3.3 完整代码

本案例中,类Animal声明,即Animal.h文件,完整代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. @interface Animal : NSObject
  3. @property int age;
  4. -(void)shout;
  5. @end

类Animal实现,即Animal.m文件,完整代码如下所示:

  1. #import "Animal.h"
  2. @implementation Animal
  3. -(void)shout{
  4. NSLog(@"动物会叫");
  5. }
  6. @end

本案例中,类Cat声明,即Cat.h文件,完整代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. #import "Animal.h"
  3. @interface Cat : Animal
  4. @end

类Cat实现,即Cat.m文件,完整代码如下所示:

  1. #import "Cat.h"
  2. @implementation Cat
  3. @end

本案例中,类Dog声明,即Dog.h文件,完整代码如下所示:

  1. #import "Animal.h"
  2. @interface Dog : Animal
  3. @end

类Dog实现,即Dog.m文件,完整代码如下所示:

  1. #import "Dog.h"
  2. @implementation Dog
  3. -(void)shout
  4. {
  5. NSLog(@"汪汪汪");
  6. }
  7. @end

主程序,即AnimalCatDog.m,完整代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. #import "Dog.h"
  3. #import "Cat.h"
  4. int main(int argc, const char * argv[])
  5. {
  6. @autoreleasepool {
  7. Animal* animal = [[Animal alloc]init];
  8. animal.age = 30;
  9. //Cat继承于Animal
  10. Cat* cat = [[Cat alloc]init];
  11. NSLog(@"cat age:%d",cat.age);
  12. [cat shout];
  13. //Dog继承于Animal
  14. Dog* dog = [[Dog alloc]init];
  15. dog.age = 18;//可以得到父类属性
  16. NSLog(@"dog age:%d",dog.age);
  17. [dog shout];
  18. }
  19. return 0;
  20. }

Objective-C----MRC内存管理 、 自动释放池 、 面向对象三大特性及封装 、 继承 、 组合与聚合的更多相关文章

  1. OC 内存泄露 自动释放池

    花絮:看到下面的代码就想起这么一个调侃: 一个老程序员,功成名就,金盆洗手不在写代码后,决定练练书法.提笔思索良久后在纸上写下:Hello world! /********************** ...

  2. objective-C 的内存管理之-自动释放池(autorelease pool)

    如果一个对象的生命周期显而易见,很容易就知道什么时候该new一个对象,什么时候不再需要使用,这种情况下,直接用手动的retain和release来判定其生死足矣.但是有些时候,想知道某个对象在什么时候 ...

  3. OC_内存管理(二)对象复制、循环引用问题、自动释放池

      循环调用: 1.循环引用的问题 两个对象A.B,有可能会出现特殊情况:A中包含B的实例变量:B中也包含A的实例变量,如果这两个实例变量都是强引用(A有着B的实例变量所有权,B也有A的实例变量所有权 ...

  4. Objective c 自动释放池

    学IOS 的大家都知道,IOS 一共有三种内存管理方式:MRC .ARC.自动释放池.我按照我个人的理解简述一下自动释放池,希望能给大家一点帮助,如有错误请大家及时批评指正. 自动释放池有几个特点:1 ...

  5. iOS阶段学习第20天笔记(MRC内存管理)

    iOS学习(OC语言)知识点整理 一.OC中的内存管理 1)概念:内存管理的对象为所有继承了NSObject的对象,对基本数据(如:int .float.double...)无效      OC中采用 ...

  6. 63 (OC)* NSAutoreleasePool 自动释放池

    目录 0:ARC 1: 自动释放池 2:NSAutoreleasePool实现原理 3:autorelease 方法 4: Runloop和Autorelease的关系 5: Using Autore ...

  7. iOS进阶四-自动释放池原理

    概述 AutoreleasePool(自动释放池)是OC中的一种内存自动回收机制,它可以延迟加入AutoreleasePool中的变量release的时机.在正常情况下,创建的变量会在超出其作用域的时 ...

  8. Autorelease自动释放池的使用

    Autorelease自动释放池的使用 使用ARC开发,只是在编译时,编译器会根据代码结构自动添加了retain.release和autorelease. MRC内存管理原则:谁申请,谁释放 遇到al ...

  9. autoreleasepool自动释放池

     示例: @autoreleasepool { ; i[largeNumber; i++) { (因识别问题,该行代码中尖括号改为方括号代替) Person *per = [[Person alloc ...

随机推荐

  1. mysql str_to_date字符串转换为日期

    mysql内置函数,在mysql里面利用str_to_date()把字符串转换为日期. 示例:分隔符一致,年月日要一致 select str_to_date('2008-4-2 15:3:28','% ...

  2. weblogic被锁解决方案

    weblogic被锁,无法启动. 解决方案:http://blog.csdn.net/zhengqiqiqinqin/article/details/17025741

  3. Oracle内置函数内容整理

    --绝对值select abs(-100) from dual; --取余select mod(8,3) from dual; --取整,大于该数的最小整数(上限值)select ceil(12.0) ...

  4. 从QQ网站中提取的纯JS省市区三级联动

    在 http://ip.qq.com/ 的网站中有QQ自己的JS省市区三级联动 QQ是使用引用外部JS来实现三级联动的.JS如下:http://ip.qq.com/js/geo.js <!DOC ...

  5. CSS 水平居中

    一.水平居中:行内元素解决方案 居中元素:文字.链接以及其它行内元素(inline或inline-*类型的元素,如inline-block,inline-table,inline-flex)解决方案: ...

  6. iOS 下如果存在UIScrollerView 使用UIScreenEdgePanGestureRecognizer实现侧滑效果失效的问题

    当你在使用UIScreenEdgePanGestureRecognizer手势实现侧滑的时候,如果后期你导航控制器push出的界面中包含UIScrollerView,这个时候你会发现,侧滑效果无法实现 ...

  7. java基础之 http

    HTTP(HyperText Transfer Protocol)是一套计算机通过网络进行通信的规则.计算机专家设计出HTTP,使HTTP客户(如Web浏览器)能够从HTTP服务器(Web服务器)请求 ...

  8. php可变变量

    例子: <?php $a = "b"; $$a = "c"; echo $$a; echo "<br>"; echo $b ...

  9. navtab方法参数以及事件

    参数(options) DOM方式初始化navtab的,推荐使用集合属性data-options定义参数,如果使用data属性定义参数,注意转换成对应的名称. 名称 类型 默认值 描述 id stri ...

  10. Python开发入门与实战1-开发环境

    1.搭建Python Django开发环境 1.1.Python运行环境安装 Python官网:http://www.python.org/ Python最新源码,二进制文档,新闻资讯等可以在Pyth ...