Objective-C Beginner's Guide
08-9-1 下午8:56
Translations: English | Chinese
大綱大綱
開始吧
下載這篇教學
設定環境
前言
編譯 hello world
創建 Classes
@interface
@implementation
把它們湊在一起
詳細說明...
繼承、多型(Inheritance, Polymorphism)以及其他物件導向功能
多重參數
建構子(Constructors)
存取權限
Class level access
異常情況(Exceptions)處理
id 型別
繼承(Inheritance)
動態識別(Dynamic types)
Categories
Posing
Protocols
記憶體管理
Retain and Release(保留與釋放)
Dealloc
Autorelease Pool
NSArray
NSDictionary
Foundation Framework Classes
優點與缺點
更多資訊
開始吧開始吧
下載這篇教學
下載這篇教學
所有這篇初學者指南的原始碼都可以由 objc.tar.gz 下載。這篇教學中的許多範例
都是由 Steve Kochan 在 Programming in Objective-C. 一書中撰寫。如果你想得到
更多詳細資訊及範例,請直接參考該書。這個網站上登載的所有範例皆經過他的
允許,所以請勿複製轉載。
設定環境
設定環境
Linux/FreeBSD: 安裝 GNUStep
為了編譯 GNUstep 應用程式,必須先執行位於
/usr/GNUstep/System/Makefiles/GNUstep.sh 的 GNUstep.sh 這個檔案。這個
路徑取決於你的系統環境,有些是在 /usr, some /usr/lib,有些是 /usr/local。
http://www.otierney.net/objective-c.html.zh-tw.big5#downloading
第 1 页(共 34 页)
Objective-C Beginner's Guide
08-9-1 下午8:56
如果你的 shell 是以 csh/tcsh 為基礎的 shell,則應該改用 GNUStep.csh。建
議把這個指令放在 .bashrc 或 .cshrc 中。
Mac OS X: 安裝 XCode
Windows NT 5.X: 安裝 cygwin 或 mingw,然後安裝 GNUStep
前言前言
這篇教學假設你已經有一些基本的 C 語言知識,包括 C 資料型別、什麼是函
式、什麼是回傳值、關於指標的知識以及基本的 C 語言記憶體管理。如果您沒有
這些背景知識,我非常建議你讀一讀 K&R 的書:The C Programming Language
(譯注:台灣出版書名為 C 程式語言第二版)這是 C 語言的設計者所寫的書。
Objective-C,是 C 的衍生語言,繼承了所有 C 語言的特性。是有一些例外,但
是它們不是繼承於 C 的語言特性本身。
nil:在 C/C++ 你或許曾使用過 NULL,而在 Objective-C 中則是 nil。不同之處是
你可以傳遞訊息給 nil(例如 [nil message];),這是完全合法的,然而你卻不能
對 NULL 如法炮製。
BOOL:C 沒有正式的布林型別,而在 Objective-C 中也不是「真的」有。它是包
含在 Foundation classes(基本類別庫)中(即 import NSObject.h;nil 也是包括在
這個標頭檔內)。BOOL 在 Objective-C 中有兩種型態:YES 或 NO,而不是
TRUE 或 FALSE。
#import vs #include:就如同你在 hello world 範例中看到的,我們使用了
#import。#import 由 gcc 編譯器支援。我並不建議使用 #include,#import 基本上
跟 .h 檔頭尾的 #ifndef #define #endif 相同。許多程式員們都同意,使用這些東西
這是十分愚蠢的。無論如何,使用 #import 就對了。這樣不但可以避免麻煩,而
且萬一有一天 gcc 把它拿掉了,將會有足夠的 Objective-C 程式員可以堅持保留
它或是將它放回來。偷偷告訴你,Apple 在它們官方的程式碼中也使用了
#import。所以萬一有一天這種事真的發生,不難預料 Apple 將會提供一個支援
#import 的 gcc 分支版本。
在 Objective-C 中, method 及 message 這兩個字是可以互換的。不過 messages
擁有特別的特性,一個 message 可以動態的轉送給另一個物件。在 Objective-C
中,呼叫物件上的一個訊息並不一定表示物件真的會實作這個訊息,而是物件知
道如何以某種方式去實作它,或是轉送給知道如何實作的物件。
編譯編譯 hello world
hello.m
#import
int main( int argc, const char *argv[] ) {
printf( "hello world\n" );
return 0;
}
輸出
hello world
在 Objective-C 中使用 #import 代替 #include
Objective-C 的預設副檔名是 .m
創建創建 classes
@interface
http://www.otierney.net/objective-c.html.zh-tw.big5#downloading
第 2 页(共 34 页)
Objective-C Beginner's Guide
08-9-1 下午8:56
基於 "Programming in Objective-C," Copyright © 2004 by Sams Publishing 一書中
的範例,並經過允許而刊載。
Fraction.h
#import
@interface Fraction: NSObject {
int numerator;
int denominator;
}
-(void) print;
-(void) setNumerator: (int) d;
-(void) setDenominator: (int) d;
-(int) numerator;
-(int) denominator;
@end
NSObject:NeXTStep Object 的縮寫。因為它已經改名為 OpenStep,所以這在今
天已經不是那麼有意義了。
繼承(inheritance)以 Class: Parent 表示,就像上面的 Fraction: NSObject。
夾在 @interface Class: Parent { .... } 中的稱為 instance variables。
沒有設定存取權限(protected, public, private)時,預設的存取權限為 protected。
設定權限的方式將在稍後說明。
Instance methods 跟在成員變數(即 instance variables)後。格式為:scope
(returnType) methodName: (parameter1Type) parameter1Name;
scope 有class 或 instance 兩種。instance methods 以 - 開頭,class level
methods 以 + 開頭。
Interface 以一個 @end 作為結束。
@implementation
基於 "Programming in Objective-C," Copyright © 2004 by Sams Publishing 一書中
的範例,並經過允許而刊載。
Fraction.m
#import "Fraction.h"
#import
@implementation Fraction
-(void) print {
printf( "%i/%i", numerator, denominator );
}
-(void) setNumerator: (int) n {
numerator = n;
}
-(void) setDenominator: (int) d {
denominator = d;
}
-(int) denominator {
return denominator;
}
-(int) numerator {
return numerator;
}
@end
Implementation 以 @implementation ClassName 開始,以 @end 結束。
http://www.otierney.net/objective-c.html.zh-tw.big5#downloading
第 3 页(共 34 页)
Objective-C Beginner's Guide
08-9-1 下午8:56
Implement 定義好的 methods 的方式,跟在 interface 中宣告時很近似。
把它們湊在一起
把它們湊在一起
基於 "Programming in Objective-C," Copyright © 2004 by Sams Publishing 一書中
的範例,並經過允許而刊載。
main.m
#import
#import "Fraction.h"
int main( int argc, const char *argv[] ) {
// create a new instance
Fraction *frac = [[Fraction alloc] init];
// set the values
[frac setNumerator: 1];
[frac setDenominator: 3];
// print it
printf( "The fraction is: " );
[frac print];
printf( "\n" );
// free memory
[frac release];
return 0;
}
output
The fraction is: 1/3
Fraction *frac = [[Fraction alloc] init];
這行程式碼中有很多重要的東西。
在 Objective-C 中呼叫 methods 的方法是 [object method],就像 C++ 的
object->method()。
Objective-C 沒有 value 型別。所以沒有像 C++ 的 Fraction frac; frac.print();
這類的東西。在 Objective-C 中完全使用指標來處理物件。
這行程式碼實際上做了兩件事: [Fraction alloc] 呼叫了 Fraction class 的
alloc method。這就像 malloc 記憶體,這個動作也做了一樣的事情。
[object init] 是一個建構子(constructor)呼叫,負責初始化物件中的所有變
數。它呼叫了 [Fraction alloc] 傳回的 instance 上的 init method。這個動作非
常普遍,所以通常以一行程式完成:Object *var = [[Object alloc] init];
[frac setNumerator: 1] 非常簡單。它呼叫了 frac 上的 setNumerator method 並傳入
1 為參數。
如同每個 C 的變體,Objective-C 也有一個用以釋放記憶體的方式: release。它
繼承自 NSObject,這個 method 在之後會有詳盡的解說。
詳細說明...
詳細說明
多重參數
多重參數
目前為止我還沒展示如何傳遞多個參數。這個語法乍看之下不是很直覺,不過它
卻是來自一個十分受歡迎的 Smalltalk 版本。
基於 "Programming in Objective-C," Copyright © 2004 by Sams Publishing一書中的
http://www.otierney.net/objective-c.html.zh-tw.big5#downloading
第 4 页(共 34 页)
Objective-C Beginner's Guide
08-9-1 下午8:56
範例,並經過允許而刊載。
Fraction.h
...
-(void) setNumerator: (int) n andDenominator: (int) d;
...
Fraction.m
...
-(void) setNumerator: (int) n andDenominator: (int) d {
numerator = n;
denominator = d;
}
...
main.m
#import
#import "Fraction.h"
int main( int argc, const char *argv[] ) {
// create a new instance
Fraction *frac = [[Fraction alloc] init];
Fraction *frac2 = [[Fraction alloc] init];
// set the values
[frac setNumerator: 1];
[frac setDenominator: 3];
// combined set
[frac2 setNumerator: 1 andDenominator: 5];
// print it
printf( "The fraction is: " );
[frac print];
printf( "\n" );
// print it
printf( "Fraction 2 is: " );
[frac2 print];
printf( "\n" );
// free memory
[frac release];
[frac2 release];
return 0;
}
output
The fraction is: 1/3
Fraction 2 is: 1/5
這個 method 實際上叫做 setNumerator:andDenominator:
加入其他參數的方法就跟加入第二個時一樣,即 method:label1:label2:label3: ,而
呼叫的方法是 [obj method: param1 label1: param2 label2: param3 label3: param4]
Labels 是非必要的,所以可以有一個像這樣的 method:method:::,簡單的省略
label 名稱,但以 : 區隔參數。並不建議這樣使用。
建構子(Constructors))
建構子(
http://www.otierney.net/objective-c.html.zh-tw.big5#downloading
第 5 页(共 34 页)
Objective-C Beginner's Guide
08-9-1 下午8:56
基於 "Programming in Objective-C," Copyright © 2004 by Sams Publishing一書中的
範例,並經過允許而刊載。
Fraction.h
...
-(Fraction*) initWithNumerator: (int) n denominator: (int) d;
...
Fraction.m
...
-(Fraction*) initWithNumerator: (int) n denominator: (int) d {
self = [super init];
if ( self ) {
[self setNumerator: n andDenominator: d];
}
return self;
}
...
main.m
#import
#import "Fraction.h"
int main( int argc, const char *argv[] ) {
// create a new instance
Fraction *frac = [[Fraction alloc] init];
Fraction *frac2 = [[Fraction alloc] init];
Fraction *frac3 = [[Fraction alloc] initWithNumerator: 3 denominator: 10];
// set the values
[frac setNumerator: 1];
[frac setDenominator: 3];
// combined set
[frac2 setNumerator: 1 andDenominator: 5];
// print it
printf( "The fraction is: " );
[frac print];
printf( "\n" );
printf( "Fraction 2 is: " );
[frac2 print];
printf( "\n" );
printf( "Fraction 3 is: " );
[frac3 print];
printf( "\n" );
// free memory
[frac release];
[frac2 release];
[frac3 release];
return 0;
}
output
The fraction is: 1/3
Fraction 2 is: 1/5
http://www.otierney.net/objective-c.html.zh-tw.big5#downloading
第 6 页(共 34 页)
Objective-C Beginner's Guide
08-9-1 下午8:56
Fraction 3 is: 3/10
@interface 裡的宣告就如同正常的函式。
@implementation 使用了一個新的關鍵字:super
如同 Java,Objective-C 只有一個 parent class(父類別)。
使用 [super init] 來存取 Super constructor,這個動作需要適當的繼承設計。
你將這個動作回傳的 instance 指派給另一新個關鍵字:self。Self 很像 C++
與 Java 的 this 指標。
if ( self ) 跟 ( self != nil ) 一樣,是為了確定 super constructor 成功傳回了一個新物
件。nil 是 Objective-C 用來表達 C/C++ 中 NULL 的方式,可以引入 NSObject 來
取得。
當你初始化變數以後,你用傳回 self 的方式來傳回自己的位址。
預設的建構子是 -(id) init。
技術上來說,Objective-C 中的建構子就是一個 "init" method,而不像 C++ 與
Java 有特殊的結構。
存取權限
存取權限
預設的權限是 @protected
Java 實作的方式是在 methods 與變數前面加上 public/private/protected 修飾語,而
Objective-C 的作法則更像 C++ 對於 instance variable(譯注:C++ 術語一般稱為
data members)的方式。
Access.h
#import
@interface Access: NSObject {
@public
int publicVar;
@private
int privateVar;
int privateVar2;
@protected
int protectedVar;
}
@end
Access.m
#import "Access.h"
@implementation Access
@end
main.m
#import "Access.h"
#import
int main( int argc, const char *argv[] ) {
Access *a = [[Access alloc] init];
// works
a->publicVar = 5;
printf( "public var: %i\n", a->publicVar );
// doesn't compile
//a->privateVar = 10;
//printf( "private var: %i\n", a->privateVar );
[a release];
http://www.otierney.net/objective-c.html.zh-tw.big5#downloading
第 7 页(共 34 页)
Objective-C Beginner's Guide
08-9-1 下午8:56
return 0;
}
output
public var: 5
如同你所看到的,就像 C++ 中 private: [list of vars] public: [list of vars] 的格式,
它只是改成了@private, @protected, 等等。
Class level access
當你想計算一個物件被 instance 幾次時,通常有 class level variables 以及 class
level functions 是件方便的事。
ClassA.h
#import
static int count;
@interface ClassA: NSObject
+(int) initCount;
+(void) initialize;
@end
ClassA.m
#import "ClassA.h"
@implementation ClassA
-(id) init {
self = [super init];
count++;
return self;
}
+(int) initCount {
return count;
}
+(void) initialize {
count = 0;
}
@end
main.m
#import "ClassA.h"
#import
int main( int argc, const char *argv[] ) {
ClassA *c1 = [[ClassA alloc] init];
ClassA *c2 = [[ClassA alloc] init];
// print count
printf( "ClassA count: %i\n", [ClassA initCount] );
ClassA *c3 = [[ClassA alloc] init];
// print count again
printf( "ClassA count: %i\n", [ClassA initCount] );
[c1 release];
http://www.otierney.net/objective-c.html.zh-tw.big5#downloading
第 8 页(共 34 页)