在上篇博文中,我們編寫了一個可以輸出不同幾何類型的小程序。通過C語言的struct結構體,給大家感受了下,對象的大概樣子。
如果用Obejctive-C的面向對象的特征來實現。那么,drawShape函數應該修改成這樣:
1 void drawShape(id shapes[], int count) 2 { 3 for(int i=0;i<count; i++) 4 { 5 id shape = shapes[i]; 6 [shape draw]; 7 } 8 }
這里,函數上傳入的id類型,是指泛型(即:可以用來引用任意類型的對象)。這里的指是一個包含struct結構體的對象。循環體中的id是一個指針類型,指針依次指向數組中的各個幾何對象。
[shape draw]:這個寫法比較獨特,這里的方括號不是像C語言中一樣,表示數組。在Objective-C中,方括號表示通知某個對象去做什么操作(類似消息), 括號前第一個參數表示的是:對象,其余部分表示的是需要對象執行的操作。
那么,[shape draw] 就可以很好的理解為:向對象shape發送draw的消息。
通過上面改編例子的引入,接下來,就給大家大概的介紹下Objective-C的面向對象的相關內容。在正式轉入Objective-C編程之前,先給大家普及下面向對象的幾個基本概念。(詳細介紹,可以請教度娘或者相關參考書)
1 @interface Circle: NSObject 2 @end
定義了一個Circle類的接口,“:”表示的是繼承NSObject父類。以@interface開始,@end結束。
注:在Objective-C中,只要看到@符號,就可以將其看中是C的擴展。
2). 方法的定義
1 @interface Circle: NSObject 2 -(void) setFillColor : (ShapeColor)fillColor; 3 -(void) setBounds : (ShapeRect) bounds; 4 -(void) draw; 5 @end
1 @interface NSString : NSObject 2 +(id)string; 3 +(id)stringWithString:(NSString*)aString; 4 +(id)stringWithWithCString:(const char*)cString 5 encoding:(NSStringEncoding)enc; 6 @end
這個可以直接用類名來調用。--> NSString.string;
PS:上面只是對方法進行了聲明,具體的方法還沒實現。在定義方法的時候,前一個括號中的表示返回值的類型,后一個表示調用這個方法要傳入的參數的類型。
3). 方法的實現
一般創建Objective-C項目的時候,會自動創建兩個文件。.h結尾的頭文件和.m結尾的實現文件(這個.m類似C語言中的.c,C++中的.cpp)。
實現方法就寫在.m結尾的實現文件中,方法如下:
1 #import "Shapes.h" 2 @implementation Circle 3 -(void) setFillColor :(ShapeColor)fillColor 4 { 5 ... //具體實現的代碼1 6 } 7 -(void) setBounds :(ShapeRect)bounds 8 { 9 ... //具體實現的代碼2 10 } 11 -(void) draw 12 { 13 ... // 具體實現的代碼3 14 } 15 @end
在Objective-C中,有一種叫中綴符的語法技術。方法的名稱和參數可以合在一起。
例如:
[circle setFillColor: kRedColor];
那么,帶兩個參數的方法如何調用呢?方法如下:
[textThing setStringValue: @"hello there" color: kBlueColor];
好了,那么接下來。我們就將上一篇博文中的代碼修改成用Objective-C的語法的吧。

1 // 2 // main.m 3 // ch4_OOP_Shapes_OC 4 // 5 // Created by pcbeta on 14-11-18. 6 // Copyright (c) 2014年 julian. All rights reserved. 7 // 面向對象的基本實例,繪制幾個幾何圖形,修改成Objective-C版本 8 //-------------------------------------修改版,修改Objective_C------------------------------- 9 10 /* 1. enum 枚舉類型 */ 11 //定義繪制圖形的類型: 圓形,矩形,橢圓形 12 typedef enum{ 13 kCircle, 14 kRectangle, 15 kEgg 16 } ShapeType; 17 18 //定義繪制圖形的顏色: 紅色,綠色和藍色 19 typedef enum{ 20 kRedColor, 21 kGreenColor, 22 kBlueColor 23 } ShapeColor; 24 25 /* 2. struct 結構體 */ 26 //定義圖形的基本屬性 27 typedef struct{ 28 int x, y, width, height; 29 } ShapeRect; 30 31 //定義整體描述的形狀 32 typedef struct{ 33 ShapeType type; 34 ShapeColor fillColor; 35 ShapeRect bounds; 36 } Shape; 37 38 /* 3.定義獲取顏色名稱的函數 */ 39 NSString *colorName (ShapeColor fillColor) 40 { 41 switch(fillColor) 42 { 43 case kRedColor: 44 return @"red"; 45 break; 46 case kGreenColor: 47 return @"green"; 48 break; 49 case kBlueColor: 50 return @"blue"; 51 break; 52 } 53 } 54 55 //定義一個圓和實現方法 56 @interface Circle : NSObject 57 { 58 @private ShapeColor fillColor; 59 ShapeRect bounds; 60 } 61 -(void) setFillColor : (ShapeColor)fillColor; 62 -(void) setBounds:(ShapeRect) bounds; 63 -(void) draw; 64 @end 65 66 @implementation Circle 67 -(void) setFillColor:(ShapeColor) c 68 { 69 fillColor = c; //fillColor為實例變量,為了防止同名,傳入的參數要取別名 70 } 71 -(void) setBounds:(ShapeRect)b 72 { 73 bounds = b; 74 } 75 -(void) draw 76 { 77 NSLog(@"drawing a circle at (%d %d %d %d) in %@", 78 bounds.x, 79 bounds.y, 80 bounds.height, 81 bounds.width, 82 colorName(fillColor)); 83 } 84 @end 85 86 //定義一個矩形和實現方法 87 @interface Rectangle : NSObject 88 { 89 @private ShapeColor fillColor; 90 ShapeRect bounds; 91 } 92 -(void) setFillColor : (ShapeColor)fillColor; 93 -(void) setBounds:(ShapeRect) bounds; 94 -(void) draw; 95 @end 96 97 @implementation Rectangle 98 -(void) setFillColor:(ShapeColor) c 99 { 100 fillColor = c; //fillColor為實例變量,為了防止同名,傳入的參數要取別名 101 } 102 -(void) setBounds:(ShapeRect)b 103 { 104 bounds = b; 105 } 106 -(void) draw 107 { 108 NSLog(@"drawing a rectangle at (%d %d %d %d) in %@", 109 bounds.x, 110 bounds.y, 111 bounds.height, 112 bounds.width, 113 colorName(fillColor)); 114 } 115 @end 116 117 //定義一個橢圓和實現方法 118 @interface Egg : NSObject 119 { 120 @private ShapeColor fillColor; 121 ShapeRect bounds; 122 } 123 -(void) setFillColor : (ShapeColor)fillColor; 124 -(void) setBounds:(ShapeRect) bounds; 125 -(void) draw; 126 @end 127 128 @implementation Egg 129 -(void) setFillColor:(ShapeColor) c 130 { 131 fillColor = c; //fillColor為實例變量,為了防止同名,傳入的參數要取別名 132 } 133 -(void) setBounds:(ShapeRect)b 134 { 135 bounds = b; 136 } 137 -(void) draw 138 { 139 NSLog(@"drawing a egg at (%d %d %d %d) in %@", 140 bounds.x, 141 bounds.y, 142 bounds.height, 143 bounds.width, 144 colorName(fillColor)); 145 } 146 @end 147 148 void drawShape(id shapes[], int count) 149 { 150 for(int i=0;i<count;i++) 151 { 152 id shape = shapes[i]; 153 [shape draw]; 154 } 155 } 156 157 int main(int argc, const char * argv[]) 158 { 159 // 定義三個幾何圖形的數組 160 id shapes[3]; 161 // 定義第一個幾何圖形為 紅色的圓形, 162 ShapeRect rect0 ={0,0,10,30}; 163 shapes[0] =[Circle new]; 164 [shapes[0] setBounds: rect0]; 165 [shapes[0] setFillColor: kRedColor]; 166 167 // 定義第二個幾何圖形為 綠色的矩形, 168 ShapeRect rect1 ={30,40,50,60}; 169 shapes[1] =[Rectangle new]; 170 [shapes[1] setBounds: rect1]; 171 [shapes[1] setFillColor: kGreenColor]; 172 173 // 定義第三個幾何圖形為 藍色的橢圓形, 174 ShapeRect rect2 ={15,18,37,29}; 175 shapes[2] = [Egg new]; 176 [shapes[2] setBounds: rect2]; 177 [shapes[2] setFillColor: kBlueColor]; 178 179 drawShape(shapes, 3); 180 181 return 0; 182 }
在運行上面代碼的時候,我發現一個書本上沒有提及的問題。那就是如圖:
有兩個錯誤提示,之前以為是代碼寫的錯誤。但是反復查閱,還是沒有發現問題。
后來,通過查詢錯誤信息(參考:http://blog.csdn.net/wbw1985/article/details/7644815)。
找出了錯誤原因:由於 XCode5.1 中缺省ARC(內存管理的一種模式,后面講內存管理的時候會詳細介紹)就是 ON 的狀態,所以編譯舊代碼的時候往往有"Automatic Reference Counting Issue"的錯誤信息。
解決的方法是:將項目編譯設置中的“Objectice-C Auto Reference Counteting”設為NO。如下所示:
設置完之后點擊保存,錯誤提示就消失了。這個時候點擊運行按鈕,就可以看到運行結果如圖:
但是,通過今天修改過的Objective-C的例子,我們可以看出代碼中了有很多地方都是重復的。
比如定義和實現Circle,Rectangle,Egg的代碼,基本都是重復的,這就很很大的優化空間了。
下篇博文,我們將繼續延續這個例子展開。介紹下Objective-C中繼承方法的使用。