OC 设计模式

         设计模式

         一种或几种被所有程序员广泛认同的,有某些特定功能,或者实现某些特殊作用的编码格式

         单例模式

         键值编码(KVC)

         键值观察(KVO)

         观察者模式()

         工厂模式(工厂方法)

         ps:MVC && MVVM && CVC

一、单例模式

 1 #import <Foundation/Foundation.h>
 2 
 3 /*
 4  单例模式
 5  1.通常情况下,一个工程只有一个单例类。
 6  2.我们将一个类选中,将它作为单例类。
 7  3.在整个工程中这个类所创建的对象是唯一并且不能被释放
 8  
 9  作用:界面传值-在整个工程任意位置对单例对象的属性进行赋值
10               也可以在整个工程的任意位置对单例对象的属性进行访问
11  */
12 @interface Globle : NSObject
13 
14 @property (strong, nonatomic) NSString *userId;
15 
16 // 单例方法
17 // 作用:获取唯一单例对象
18 + (Globle*) shareGloble;//getGloble
19 
20 @end
21 
22 #import "Globle.h"
23 
24 // 创建一个单例对象,用静态修饰符将这个对象的生命周期延长至整个工程
25 static Globle *globle = nil;
26 
27 @implementation Globle
28 
29 +(Globle *)shareGloble
30 {
31     // 第一次执行单例方法,将单例对象初始化
32     if (globle == nil) {
33         globle = [[Globle alloc] init];
34         globle.userId = @"";
35     }
36     // 之后的每次调用,都会直接返回上面的唯一单例对象
37     return globle;
38 }
39 @end
40 
41 
42 #import <Foundation/Foundation.h>
43 #import "Globle.h"
44 
45 @interface People : NSObject
46 
47 +(void) showUserId;
48 
49 @end
50 
51 #import "People.h"
52 
53 @implementation People
54 
55 +(void)showUserId
56 {
57     NSLog(@"userId:%@",[Globle shareGloble].userId);
58 }
59 @end
60 
61 
62 #import <Foundation/Foundation.h>
63 #import "Globle.h"
64 #import "People.h"
65 
66 int main(int argc, const char * argv[]) {
67     @autoreleasepool {
68 
69         [Globle shareGloble].userId = @"1001";
70         [People showUserId];
71 
72     }
73     return 0;
74 }

二、KVC

 1 #import <Foundation/Foundation.h>
 2 
 3 /*
 4  KVC key-value-coding
 5  
 6  作用:能够无视OC中关于私有的设定,直接通过底层赋值方式对属性赋值(和获取);
 7  
 8  */
 9 @interface KVCClass : NSObject
10 
11 -(void) showProperty;
12 
13 @end
14 
15 #import "KVCClass.h"
16 #import "Student.h"
17 
18 @interface KVCClass ()
19 
20 @property (strong, nonatomic) NSString  *kvcProperty;
21 @property (strong, nonatomic) Student *tempStu;
22 
23 @end
24 
25 @implementation KVCClass
26 
27 - (instancetype)init
28 {
29     self = [super init];
30     if (self) {
31         self.tempStu =[[Student alloc] init];
32     }
33     return self;
34 }
35 
36 -(void)showProperty
37 {
38     NSLog(@"property:%@",self.kvcProperty);
39     NSLog(@"property:%@",self.tempStu.name);
40 
41 }
42 @end
43 
44 
45 #import <Foundation/Foundation.h>
46 
47 @interface Student : NSObject
48 
49 @property (strong, nonatomic) NSString *name;
50 
51 @end
52 
53 #import "Student.h"
54 
55 @implementation Student
56 
57 @end
58 
59 
60 #import <Foundation/Foundation.h>
61 
62 #import "KVCClass.h"
63 int main(int argc, const char * argv[]) {
64     @autoreleasepool {
65         KVCClass *kvc = [[KVCClass alloc] init];
66         
67         //表示 在KVC对象中查找名字为[kvcProperty] 的属性,并对这个属性赋值为@“bowen”
68         // 设置
69         [kvc setValue:@"bowen" forKey:@"kvcProperty"];
70         
71         [kvc setValue:@"bowen1" forKeyPath:@"tempStu.name"];
72         
73         [kvc showProperty];
// 取值

             NSLog(@"%@",[kvc valueForKey:@"kvcProperty"]);

74         NSLog(@"%@",[kvc valueForKeyPath:@"tempStu.name"]);
75     }
76     return 0;
77 }

OC中的KVC操作就和Java中使用反射机制去访问类的private权限的变量,很暴力的,这样做就会破坏类的封装性,本来类中的的private权限就是不希望外界去访问的,但是我们这样去操作,就会反其道而行,但是我们有时候真的需要去这样做,哎。所以说有些事不是都是顺其自然的,而是需要的时候自然就诞生了。

下面就来看一下这种技术的使用:

Dog.h

  1. //  
  2. //  Dog.h  
  3. //  42_KVC  
  4. //  
  5. //  Created by jiangwei on 14-10-14.  
  6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
  7. //  
  8.   
  9. #import <Foundation/Foundation.h>  
  10.   
  11. @interface Dog : NSObject  
  12.   
  13. @end  

Dog.m

  1. //  
  2. //  Dog.m  
  3. //  42_KVC  
  4. //  
  5. //  Created by jiangwei on 14-10-14.  
  6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
  7. //  
  8.   
  9. #import "Dog.h"  
  10.   
  11. @implementation Dog  
  12.   
  13. @end  

定义了Dog这个类,但是什么都没有,他只是一个中间类,没什么作用,在这个demo中。

Person.h

  1. //  
  2. //  Person.h  
  3. //  42_KVC  
  4. //  
  5. //  Created by jiangwei on 14-10-14.  
  6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
  7. //  
  8.   
  9. #import <Foundation/Foundation.h>  
  10. #import "Dog.h"  
  11.   
  12. @interface Person : NSObject{  
  13. @private  
  14.     NSString *_name;  
  15.     NSDog *_dog;  
  16.       
  17.     NSInteger *age;  
  18. }  
  19.   
  20. @end  

Person.m

  1. //  
  2. //  Person.m  
  3. //  42_KVC  
  4. //  
  5. //  Created by jiangwei on 14-10-14.  
  6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
  7. //  
  8.   
  9. #import "Person.h"  
  10.   
  11. @implementation Person  
  12.   
  13. - (NSString *)description{  
  14.     NSLog(@"%@",_name);  
  15.     return _name;  
  16. }  
  17.   
  18. @end  

Person类中我们定义了两个属性,但是这两个属性对外是不可访问的,而且也没有对应的get/set方法。我们也实现了description方法,用于打印结果

看一下测试代码

main.m

  1. //  
  2. //  main.m  
  3. //  42_KVC  
  4. //  
  5. //  Created by jiangwei on 14-10-14.  
  6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
  7. //  
  8.   
  9. #import <Foundation/Foundation.h>  
  10. #import "Person.h"  
  11. #import "Dog.h"  
  12.   
  13. //KVC:很暴力,及时一个类的属性是私有的,而且也没有get/set方法,同样可以读写  
  14. //相当于Java中的反射,破坏类的封装性  
  15. int main(int argc, const charchar * argv[]) {  
  16.     @autoreleasepool {  
  17.           
  18.         Person *p = [[Person alloc] init];  
  19.           
  20.         //设置值  
  21.         //这里setValue方法:第一个参数是value,第二个参数是key(就是类的属性名称)  
  22.         [p setValue:@"jiangwei" forKey:@"name"];  
  23.           
  24.         Dog *dog = [[Dog alloc] init];  
  25.         [p setValue:dog forKey:@"dog"];  
  26.           
  27.         //KVC设置值时,如果属性有set方法,则优先调用set方法,如果没有则直接设置上去,get方法类似  
  28.           
  29.         //读取值  
  30.         NSString *name = [p valueForKey:@"name"];  
  31.           
  32.         //设置基本数据类型  
  33.         //这里需要将基本类型转化成NSNumber  
  34.         //在设置值的时候,会有自动解包的过程,NSNumber会解包赋值给age  
  35.         [p setValue:@22 forKey:@"age"];  
  36.           
  37.         NSLog(@"%@",p);  
  38.           
  39.         return 0;  
  40.     }  
  41.     return 0;  
  42. }  

这里我们生成一个Person对象,然后开始使用KVC技术了:

1、设置属性值

  1. //设置值  
  2. //这里setValue方法:第一个参数是value,第二个参数是key(就是类的属性名称)  
  3. [p setValue:@"jiangwei" forKey:@"name"];  
  4.           
  5. Dog *dog = [[Dog alloc] init];  
  6. [p setValue:dog forKey:@"dog"];  

使用setValue方法,就可以进行对属性进行设置值操作了,同时需要传递这个属性的名称,这个和Java中使用反射机制真的很像。

注:KVC设置值时,如果属性有set方法,则优先调用set方法,如果没有则直接设置上去,get方法一样

 

  1. //设置基本数据类型  
  2. //这里需要将基本类型转化成NSNumber  
  3. //在设置值的时候,会有自动解包的过程,NSNumber会解包赋值给age  
  4. [p setValue:@22 forKey:@"age"];  

还有一个需要注意的地方:当我们在设置基本类型的时候,需要将其转化成NSNumber类型的。

2、取属性的值

 

  1. //读取值  
  2. NSString *name = [p valueForKey:@"name"];  

取值就简单了

 

下面再来看一下KVC中强大的功能:键值路径

键值路径是对于一个类中有数组对象的属性进行便捷操作。

看个场景:

一个作者有多本书

Author.h

 

  1. //  
  2. //  Author.h  
  3. //  43_KeyValuePath  
  4. //  
  5. //  Created by jiangwei on 14-10-15.  
  6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
  7. //  
  8.   
  9. #import <Foundation/Foundation.h>  
  10.   
  11. @interface Author : NSObject{  
  12.     NSString *_name;  
  13.       
  14.     //作者出版的书,一个作者对应多个书籍对象  
  15.     NSArray *_issueBook;  
  16. }  
  17.   
  18. @end  

作者类中定义了名字和一个书籍数组

 

Author.m

 

  1. //  
  2. //  Author.m  
  3. //  43_KeyValuePath  
  4. //  
  5. //  Created by jiangwei on 14-10-15.  
  6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
  7. //  
  8.   
  9. #import "Author.h"  
  10.   
  11. @implementation Author  
  12.   
  13. @end  

 

Book.h

 

  1. //  
  2. //  Book.h  
  3. //  43_KeyValuePath  
  4. //  
  5. //  Created by jiangwei on 14-10-15.  
  6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
  7. //  
  8.   
  9. #import <Foundation/Foundation.h>  
  10. #import "Author.h"  
  11.   
  12. @interface Book : NSObject{  
  13.     Author *_author;  
  14. }  
  15.   
  16. @property NSString *name;  
  17. @property floatfloat *price;  
  18.   
  19. @end  

定义了一个作者属性,书的名字,价格

 

Book.m

 

  1. //  
  2. //  Book.m  
  3. //  43_KeyValuePath  
  4. //  
  5. //  Created by jiangwei on 14-10-15.  
  6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
  7. //  
  8.   
  9. #import "Book.h"  
  10.   
  11. @implementation Book  
  12.   
  13. @end  


看一下测试代码

main.m

 

  1. //  
  2. //  main.m  
  3. //  43_KeyValuePath  
  4. //  
  5. //  Created by jiangwei on 14-10-15.  
  6. //  Copyright (c) 2014年 jiangwei. All rights reserved.  
  7. //  
  8.   
  9. #import <Foundation/Foundation.h>  
  10. #import "Book.h"  
  11. #import "Author.h"  
  12.   
  13. int main(int argc, const charchar * argv[]) {  
  14.     @autoreleasepool {  
  15.           
  16.         //------------------KVC键值路径  
  17.         /* 
  18.         Book *book = [[Book alloc] init]; 
  19.         Author *author = [[Author alloc] init]; 
  20.          
  21.         //设置作者 
  22.         [book setValue:author forKey:@"author"]; 
  23.          
  24.         //设置作者的名字 
  25.         //路径为:author.name,中间用点号进行连接 
  26.         [book setValue:@"jiangwei" forKeyPath:@"author.name"]; 
  27.         NSString *name = [author valueForKey:@"name"]; 
  28.         NSLog(@"name is %@",name); 
  29.          */  
  30.           
  31.           
  32.         //--------------------KVC的运算  
  33.         Author *author = [[Author alloc] init];  
  34.         [author setValue:@"莫言" forKeyPath:@"name"];  
  35.           
  36.         Book *book1 = [[Book alloc] init];  
  37.         book1.name = @"红高粱";  
  38.         book1.price = 9;  
  39.         Book *book2 = [[Book alloc] init];  
  40.         book2.name = @"蛙";  
  41.         book2.price = 10;  
  42.         NSArray *array = [NSArray arrayWithObjects:book1,book2, nil nil];  
  43.         [author setValue:array forKeyPath:@"issueBook"];  
  44.           
  45.         //基本数据类型会自动被包装成NSNumber,装到数组中  
  46.         //得到所有书籍的价格  
  47.         NSArray *priceArray = [author valueForKeyPath:@"issueBook.price"];  
  48.         NSLog(@"%@",priceArray);  
  49.           
  50.         //获取数组的大小  
  51.         NSNumber *count = [author valueForKeyPath:@"issueBook.@count"];  
  52.         NSLog(@"count=%@",count);  
  53.           
  54.         //获取书籍价格的总和  
  55.         NSNumber *sum = [author valueForKeyPath:@"issueBook.@sum.price"];  
  56.         NSLog(@"%@",sum);  
  57.           
  58.         //获取书籍的平均值  
  59.         NSNumber *avg = [author valueForKeyPath:@"issueBook.@avg.price"];  
  60.         NSLog(@"%@",avg);  
  61.           
  62.         //获取书籍的价格最大值和最小值  
  63.         NSNumber *max = [author valueForKeyPath:@"issueBook.@max.price"];  
  64.         NSNumber *min = [author valueForKeyPath:@"issueBook.@min.price"];  
  65.           
  66.     }  
  67.     return 0;  
  68. }  

 

1、首先通过前面说到的KVC设置作者的书籍数组

 

  1. //--------------------KVC的运算  
  2. Author *author = [[Author alloc] init];  
  3. [author setValue:@"莫言" forKeyPath:@"name"];  
  4.   
  5. Book *book1 = [[Book alloc] init];  
  6. book1.name = @"红高粱";  
  7. book1.price = 9;  
  8. Book *book2 = [[Book alloc] init];  
  9. book2.name = @"蛙";  
  10. book2.price = 10;  
  11. NSArray *array = [NSArray arrayWithObjects:book1,book2, nil nil];  
  12. [author setValue:array forKeyPath:@"issueBook"];  

添加了两本书籍

 

2、下面就开始用到KVC中键值路径了

1)获取作者类中书籍数组中所有书籍的价格

 

  1. //基本数据类型会自动被包装成NSNumber,装到数组中  
  2. //得到所有书籍的价格  
  3. NSArray *priceArray = [author valueForKeyPath:@"issueBook.price"];  
  4. NSLog(@"%@",priceArray);  

看到了:@"issueBook.price" 这就是键值路径的使用,issueBook是作者类中的书籍数组属性名,price是书籍类的属性,中间用点号进行连接,这样我们就可以获取到了所有书籍的价格了,如果在Java中,我们需要用一个循环操作。但是OC中多么方便。

 

2)获取作者类中书籍数组的大小

 

  1. //获取数组的大小  
  2. NSNumber *count = [author valueForKeyPath:@"issueBook.@count"];  
  3. NSLog(@"count=%@",count);  

使用 @"issueBook.@count" 键值路径获取书籍数组的大小,issueBook是作者类中的书籍数组属性名,@count是特定一个写法,可以把它想象成一个方法,中间任然用点号进行连接

 

3)获取作者类中书籍数组的价格总和

  1. //获取书籍价格的总和  
  2. NSNumber *sum = [author valueForKeyPath:@"issueBook.@sum.price"];  
  3. NSLog(@"%@",sum);  

使用 @"issueBook.@sum.price" 键值路径获取书籍数组中的价格总和,issueBook是作者类中的书籍数组属性名,@sum是特性写法,可以把它想象成一个方法,price是书籍的价格属性名,可以把它看成是@sum的一个参数,中间用点号进行连接

如果在java中,这个需要用一个循环来计算总和,OC中很方便的

 

4)获取作者类中书籍数组的价格平均值、最小值、最大值

  1. //获取书籍的平均值  
  2. NSNumber *avg = [author valueForKeyPath:@"issueBook.@avg.price"];  
  3. NSLog(@"%@",avg);  
  4.   
  5. //获取书籍的价格最大值和最小值  
  6. NSNumber *max = [author valueForKeyPath:@"issueBook.@max.price"];  
  7. NSNumber *min = [author valueForKeyPath:@"issueBook.@min.price"];  

操作和上面类似,这里就不解释了

 

我们看到上面返回来的数据都是NSNumber类型的

三、观察者模式

 1 #import <Foundation/Foundation.h>
 2 
 3 /*
 4  观察者模式(通知模式)NSNotification
 5  观察者中心          NSNotificationCenter
 6  
 7  注册观察者必需在[发出通知]之前
 8  
 9  */
10 
11 @interface House : NSObject
12 
13 -(void) burn;
14 
15 @end
16 
17 #import "House.h"
18 
19 @implementation House
20 
21 -(void)burn
22 {
23     NSLog(@"房子着火了");
24     // 发出通知
25     [[NSNotificationCenter defaultCenter] postNotificationName:@"PlanB" object:nil];
26 }
27 @end
28 
29 #import <Foundation/Foundation.h>
30 
31 @interface Child : NSObject
32 
33 -(void) loudSay;
34 
35 -(void) toBeAGuanChazhe;
36 
37 @end
38 
39 #import "Child.h"
40 
41 @implementation Child
42 
43 -(void) loudSay
44 {
45     NSLog(@"报告:房子着火了");
46 }
47 
48 -(void)toBeAGuanChazhe
49 {
50     // 创建观察者
51     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loudSay) name:@"PlanB" object:nil];
52 }
53 @end
54 
55 #import <Foundation/Foundation.h>
56 
57 #import "House.h"
58 #import "Child.h"
59 
60 
61 int main(int argc, const char * argv[]) {
62     @autoreleasepool {
63 
64         House *myhouse = [[House alloc] init];
65         
66         Child *mychild = [[Child alloc] init];
67         
68         // 让mychild 成为观察者
69         [mychild toBeAGuanChazhe];
70         
71         // 让房子着火,发出PlanB现象
72         [myhouse burn];
73     }
74     return 0;
75 }

四、KVO

 1 #import <Foundation/Foundation.h>
 2 #import "JieCao.h"
 3 
 4 /*
 5  KVO key-value-observer(键值观察)
 6  
 7  作用:能够在被观察的某个属性发生变化的时候,自动执行某些方法
 8  
 9  当被观察的某个属性发生变化的时候,这个方法被自动回调
10  
11  -(void) observer...
12  
13  pss:当键值观察的观察者被使用完毕之后必须注销
14  psss:键值观察是在[某个类中]给[某个属性] 注册观察者,当这个属性的值发生变化后作出响应模式
15  
16  */
17 
18 @interface Bowen : NSObject
19 
20 @property (strong,nonatomic) JieCao *my_jieCao;
21 
22 @end
23 
24 
25 #import "Bowen.h"
26 
27 @implementation Bowen
28 
29 -(void) setMy_jieCao:(JieCao *)my_jieCao
30 {
31     _my_jieCao = my_jieCao;
32     
33     //注册观察者,观察_my_jieCao属性的值的变化
34     [_my_jieCao addObserver:self forKeyPath:@"jieCaoValue" options:NSKeyValueObservingOptionNew context:nil];
35     
36 }
37 // 不管在一个类当中注册一个多少KVO的观察者,本方法只能写一个
38 -(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
39 {
40     if ([keyPath isEqualToString:@"jieCaoValue"]) {
41         
42         if ([[change objectForKey:@"new"] integerValue]<10) {
43             NSLog(@"我要吐了,受不了老师了");
44         }
45 //        NSLog(@"keyPath:%@",keyPath);
46 //        NSLog(@"Object:%@",keyPath);
47 //        NSLog(@"change:%@",[change objectForKey:@"new"]);
48 
49     }
50 }
51 - (void)dealloc
52 {
53     [_my_jieCao removeObserver:self forKeyPath:@"jieCaoValue"];
54 }
55 
56 @end
57 
58 #import <Foundation/Foundation.h>
59 
60 @interface JieCao : NSObject
61 
62 @property (assign, nonatomic) NSInteger jieCaoValue;
63 
64 @end
65 
66 #import "JieCao.h"
67 
68 @implementation JieCao
69 
70 @end
71 
72 #import <Foundation/Foundation.h>
73 
74 #import "Bowen.h"
75 #import "JieCao.h"
76 
77 int main(int argc, const char * argv[]) {
78     @autoreleasepool {
79         // 创建被观察属性
80         JieCao *jieCao = [[JieCao alloc] init];
81         jieCao.jieCaoValue = 100;
82         // 创建观察对象
83         Bowen *bowen = [[Bowen alloc] init];
84         // 让观察对象开始观察[被观察属性]
85         bowen.my_jieCao = jieCao;
86         // 让被观察属性发生变化
87         bowen.my_jieCao.jieCaoValue = 9;
88     }
89     return 0;
90 }

五、工厂模式

  1 #import <Foundation/Foundation.h>
  2 #import "Fruit.h"
  3 
  4 /*
  5  
  6  工厂模式:(工厂方法)
  7  
  8  个人理解:实际上就是用来快速大批量生产对象的
  9  
 10  优点:能够将原本在本类初始化的对象,延时到子类中去初始化。实现了一个开放封闭原则。
 11  
 12  */
 13 
 14 @interface FruitFactory : NSObject
 15 
 16 // 通过外部输入的名字,创建[名字对应的类] 的对象
 17 + (Fruit *)createFruitByName:(NSString *) name;
 18 
 19 @end
 20 
 21 #import "FruitFactory.h"
 22 
 23 @implementation FruitFactory
 24 
 25 +(Fruit *)createFruitByName:(NSString *)name
 26 {
 27     //需要知道名字对应的类
 28     Class class = NSClassFromString(name);
 29     // 创建想要的类对象
 30     Fruit *fruit = [[class alloc] init];
 31     // 返回新建的[想要的类]的对象
 32     return fruit;
 33 }
 34 @end
 35 
 36 
 37 #import <Foundation/Foundation.h>
 38 
 39 @interface Fruit : NSObject
 40 
 41 -(void) show;
 42 
 43 @end
 44 
 45 #import "Fruit.h"
 46 
 47 @implementation Fruit
 48 
 49 -(void)show
 50 {
 51     NSLog(@"I'm fruit");
 52 }
 53 @end
 54 
 55 #import "Fruit.h"
 56 
 57 @interface Apple : Fruit
 58 
 59 @end
 60 
 61 
 62 #import "Apple.h"
 63 
 64 @implementation Apple
 65 
 66 -(void)show
 67 {
 68     NSLog(@"I'm apple");
 69 }
 70 
 71 
 72 #import "Fruit.h"
 73 
 74 @interface Banana : Fruit
 75 
 76 @end
 77 
 78 #import "Banana.h"
 79 
 80 @implementation Banana
 81 
 82 -(void)show
 83 {
 84     NSLog(@"I'm banana");
 85 }
 86 
 87 @end
 88 
 89 #import "Fruit.h"
 90 
 91 @interface Pear : Fruit
 92 
 93 @end
 94 
 95 #import "Pear.h"
 96 
 97 @implementation Pear
 98 
 99 -(void)show
100 {
101     NSLog(@"I'm pear");
102 }
103 
104 @end
105 
106 #import <Foundation/Foundation.h>
107 #import "FruitFactory.h"
108 
109 int main(int argc, const char * argv[]) {
110     @autoreleasepool {
111         Fruit *fruit = [FruitFactory createFruitByName:@"Apple"];
112         [fruit show];
113         Fruit *fruit1 = [FruitFactory createFruitByName:@"Banana"];
114         [fruit1 show];
115         Fruit *fruit2 = [FruitFactory createFruitByName:@"Pear"];
116         [fruit2 show];
117     }
118     return 0;
119 }
原文地址:https://www.cnblogs.com/oc-bowen/p/5063807.html