zoukankan      html  css  js  c++  java
  • Objective-C----MRC内存管理 、 自动释放池 、 面向对象三大特性及封装 、 继承 、 组合与聚合

    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. }
  • 相关阅读:
    aspjpeg 组件在asp中的使用
    C# 使用 fckeditor 上传文件中文名乱码的问题---转
    我来挑战主页绑定,浏览器被绑架之终极方案!
    nginx简易配置
    树莓派安装中文输入法
    树莓派4超频至2.0GHz
    python3 requests使用连接池
    python3 语言特性5
    git日常使用
    python3 时间格式化
  • 原文地址:https://www.cnblogs.com/52190112cn/p/5049254.html
Copyright © 2011-2022 走看看