天天看點

【IOS 開發】Objective - C 面向對象進階特性 - 包裝類 | 類處理 | 類别 | 擴充 | 協定 | 委托 | 異常處理 | 反射一. Objective-C 對象簡單處理二. 類别 與 擴充三. 協定 與 委托四. 異常處理五. Objective-C 反射

一. Objective-C 對象簡單處理

1. 包裝類

(1) 包裝類簡介

NSValue 和 NSNumber : 

-- 通用包裝類 NSValue : NSValue 包裝單個 short, int, long, float, char, id, 指針 等資料;

-- NSNumber 包裝類 : 用于包裝 C 語言資料類型;

NSNumber 方法 : 

-- "+ numberWithXxx :" : 将特定類型的值包裝成 NSNumber;

-- "- initWithXxx :" : 先建立一個 NSNumber 對象, 再用一個基本類型的值來初始化 NSNumber;

-- "- xxxValue :" : 傳回 NSNumber 對象包裝的基本類型的值;

(2) 包裝類代碼示例

代碼示例 : 

/*************************************************************************
    > File Name: OCNSNumberDemo.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 六 10/ 3 12:50:15 2015
 ************************************************************************/

#import <Foundation/Foundation.h>

int main(int argc, char * argv[])
{
	@autoreleasepool {
		NSNumber * num_int = [NSNumber numberWithInt : 10];
		NSNumber * num_double = [NSNumber numberWithDouble : 10];
		NSNumber * num_char = [NSNumber numberWithChar : 'A'];

		NSLog(@"number_int : %d, number_double : %g, num_char : %c", 
			[num_int intValue], [num_double doubleValue], [num_char charValue]);
		
		NSNumber * num_int1 = [[NSNumber alloc] initWithInt : 10];
		NSNumber * num_double1 = [[NSNumber alloc] initWithDouble : 10];
		NSNumber * num_char1 = [[NSNumber alloc] initWithChar : 'A'];

		NSLog(@"number_int1 : %d, number_double1 : %g, num_char1 : %c",
			[num_int1 intValue], [num_double1 doubleValue], [num_char1 charValue]);
	}
}
           

-- 執行結果 : 

localhost:oc_object octopus$ clang -fobjc-arc -framework Foundation OCNSNumberDemo.m
localhost:oc_object octopus$ ./a.out 
2015-10-03 13:00:46.465 a.out[887:507] number_int : 10, number_double : 10, num_char : A
2015-10-03 13:00:46.468 a.out[887:507] number_int1 : 10, number_double1 : 10, num_char1 : A
           

2. description 方法

(1) description 方法簡介

description 方法簡介 : 類似于 Java 中 Object 的 toString() 方法;

-- 方法來源 : description 是 NSObject 中定義的, 所有的方法都有該方法;

-- 預設方法 : description 預設方法傳回 <類名: 位址>;

-- 輸出對象 : NSLog() 函數輸出一個對象, 其實輸出的是該對象的 description 方法;

-- 示例 : OCPerson * person, 列印 [person description] 和 person 輸出結果是一樣的;

(2) description 示例代碼

示例代碼 : 

/*************************************************************************
    > File Name: OCDescriptionDemo.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 六 10/ 3 14:25:28 2015
 ************************************************************************/
#import <Foundation/Foundation.h>

@interface OCDescriptionDemo : NSObject
@property (nonatomic, copy) NSString * name;
@property (nonatomic, assign) int age;
- (id) initWithNameAndAge : (NSString *) set_name setAge : (int) set_age;
@end

@implementation OCDescriptionDemo
@synthesize name;
@synthesize age;
- (id) initWithNameAndAge : (NSString *) set_name setAge : (int) set_age
{
	self.name = set_name;
	self.age = set_age;
	return self;
}
- (NSString *) description
{
	NSString * des = [NSString stringWithFormat : 
		@"<OCDescription[name = %@, age = %d]>", self.name, self.age];
	return des;
}
@end

int main(int argc, char * argv[])
{
	@autoreleasepool {
		OCDescriptionDemo * description = [[OCDescriptionDemo alloc] initWithNameAndAge : @"Tom" setAge : 18];
		NSLog(@"%@", description);
	}
}
           

-- 執行結果 : 

localhost:oc_object octopus$ clang -fobjc-arc -framework Foundation OCDescriptionDemo.m 
localhost:oc_object octopus$ ./a.out 
2015-10-03 14:50:18.665 a.out[970:507] <OCDescription[name = Tom, age = 18]>
           

3. == 或 isEqual : 方法

(1) "==" 運算符

"==" 簡介 : 

-- 作用 : 判斷兩個變量是否相等;

-- 前提 : 兩個變量都是基本類型, 兩個變量相等傳回 true; 指針類型變量比較位址沒有任何意義;

(2) 常量池

常量池 : 

-- 作用 : 保證相同的字元串常量至右一個, 不能出現多個相同的副本;

-- 例外 : 使用 [NSString stringWithFormat] 方法建立的字元串不會放入常量池;

(3) isEqual 方法

"isEqual" 方法簡介 : 

-- 來源 : isEqual 方法是 NSObject 類提供的執行個體方法, 用于判斷相同類型的兩個變量是否相等;

-- 預設 : 預設方法還是比較位址, 需要開發者重寫這個方法;

-- NSString 的 isEqual 方法 : NSString 的 isEqual 方法是判斷兩個字元串是否相等, 包含的字元串相同就會傳回 true;

-- isEqualToString 方法 : 方法 : NSString 中定義的 isEqualToString 方法用于判斷目前字元串 與 另一個字元串的字元串序列是否相等;

重寫 isEqual 方法标準 : 

-- 自反性 : 對象 x, [x isEqual : x] 必須傳回 true;

-- 對稱性 : 對象 x 和 y, 如果 [x isEqual : y] 傳回值 必須與 [y isEqual : x] 傳回值相同;

-- 傳遞性 : 對象 x , y 和 z, [x isEqual : y] = true, [y isEqual : z] = true, 那麼 x z 也相等;

-- 一緻性 : x , y 對象無論調用多少次, 傳回值結果都應該保持一緻;

-- nil 對比 : 如果 x 不是 nil, [x isEqual : nil] 必須傳回 false;

(4) "==" 和 "isEqual" 示例源碼

示例源碼 : 

/*************************************************************************
    > File Name: OCEqual.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 六 10/ 3 16:07:56 2015
 ************************************************************************/
#import <Foundation/Foundation.h>

@interface OCEqual : NSObject
@property (nonatomic, copy) NSString * name;
@property (nonatomic, assign) int age;

- (id) initWithName : (NSString *) set_name setAge : (int) set_age;
@end

@implementation OCEqual
@synthesize name;
@synthesize age;

- (id) initWithName : (NSString *) set_name setAge : (int) set_age
{
	self.name = set_name;
	self.age = set_age;
	return self;
}

- (BOOL) isEqual : (id) other
{
	if(self == other)
		return YES;

	if(other != nil && [other isMemberOfClass : OCEqual.class])
	{
		OCEqual * equal = (OCEqual *) other;
		return [self.name isEqual : equal.name] && (self.age == equal.age);
	}
	return NO;	
}
@end


int main(int argc, char * argv[])
{
	@autoreleasepool {
		int int_a = 10;
		int double_a = 10.0;

		NSLog(@"int_a == double_a : %d", (int_a == double_a));
	
		NSString * str_a = @"Octopus";
		NSString * str_b = @"Octopus";
		NSString * str_c = [NSString stringWithFormat : @"Octopus"];
		NSString * str_d = [NSString stringWithFormat : @"Octopus"];

		NSLog(@"str_a == str_b : %d, str_c == str_d : %d, [str_c isEqual : str_d] : %d", 
			str_a == str_b, str_c == str_d, [str_c isEqual : str_d]);
		
		OCEqual * equal_a = [[OCEqual alloc] initWithName : @"Tom" setAge : 18];
		OCEqual * equal_b = [[OCEqual alloc] initWithName : @"Jerry" setAge : 20];
		OCEqual * equal_c = [[OCEqual alloc] initWithName : @"Jerry" setAge : 20];

		NSLog(@"[equal_a isEqual : equal_b] : %d, [equal_b isEqual : equal_c] : %d", 
			[equal_a isEqual : equal_b], [equal_b isEqual : equal_c]);
	}
}
           

-- 執行結果 : 

localhost:oc_object octopus$ clang -fobjc-arc -framework Foundation OCEqual.m 
localhost:oc_object octopus$ ./a.out 
2015-10-03 16:58:35.690 a.out[1168:507] int_a == double_a : 1
2015-10-03 16:58:35.693 a.out[1168:507] str_a == str_b : 1, str_c == str_d : 0, [str_c isEqual : str_d] : 1
2015-10-03 16:58:35.693 a.out[1168:507] [equal_a isEqual : equal_b] : 0, [equal_b isEqual : equal_c] : 1
           

二. 類别 與 擴充

1. Category 類别

(1) 擴充類簇需求

類簇擴充需求 : 開發過程中有時需要擴充類行為;

-- 繼承 : 通過繼承, 子類在父類基礎上添加方法 或者 重寫父類方法;

-- 問題 : 如果想要為父類增加一個方法, 子類同時也繼承這些方法, 此時使用繼承就滿足不了這個功能了;

-- 類簇 : OC 中沒有接口, 需要接口時, 就會選擇定義一個父類, 以該父類派生 N 個子類, 該系列的類被成為 類簇;

-- 類簇擴充方法 : 為父類增加方法, 類簇中得子類同時也增加該方法, 擴充類簇中得父類是最合适的方法;

(2) Category 類别

類别 (category) 簡介 : 

-- 作用 : 為現有類添加方法, 不需要通路原有類代碼, 不需要繼承;

-- 有點 : 動态地為現有類添加方法, 将類定義子產品化 分布到多個檔案中;

(3) Category 類别 接口 文法格式

類别 (category) 接口部分文法格式 : 

-- 接口檔案類命名 : "類名+類别名.h", 如 要擴充 OCPerson 類, 類别名為 SB, 那麼接口檔案名就是 "OCPerson+SB.h";

-- 示例 : 

@interface 已有類 (類别名)
//方法定義
...
@end
           

-- 類别名 : 必須是項目中沒有的類, 定義類别時使用的類名, 必須是已有的類;

-- 圓括号 : 類别名 定義在 需要擴充的已有類之後, 必須使用圓括号括起來;

-- 定義内容 : 類别中一般情況下隻定義方法;

(4) Category 類别 實作類 文法格式

類别 (category) 實作部分文法格式 : 

-- 實作類檔案命名 : "類名+類别名.m", 如 要擴充 OCPerson 類, 類别名為 SB, 那麼接口檔案名就是 "OCPerson+SB.m";

-- 示例 : 

@implementation 已有類 (類别名)
//方法定義
...
@end
           

(5) Category 類别 注意點

注意事項 : 

-- 影響範圍 : 通過 category 添加新方法後, 會影響到 指定的被擴充的類, 同時也會影響到其子類;

-- 多個類别 : 一個類可以 對應多個類别, 這些類别都可以為類增加方法定義;

-- 類别優點 : 進行子產品化設計, 調用私有方法, 實作非正式協定;

(6) Category 擴充 NSNumber 示例

NSNumber 擴充示例 : 為其添加一個計算圓面積的方法;

-- NSNumber+SB.h : 

/*************************************************************************
    > File Name: NSNumber+SB.h
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 六 10/ 3 18:58:53 2015
 ************************************************************************/
#import <Foundation/Foundation.h>
@interface NSNumber (SB)
- (NSNumber *) circleAera : (double) radius;
@end
           

--  NSNumber+SB.m : 

/*************************************************************************
    > File Name: NSNumber+SB.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 六 10/ 3 19:02:05 2015
 ************************************************************************/
 #import "NSNumber+SB.h"
 @implementation NSNumber (SB)

 - (NSNumber *) circleAera : (double) radius
 {
	double aera = 3.1415926 * radius * radius;
	return [NSNumber numberWithDouble : aera];
 }

 @end
           

--  NSNumber+SBTest.m : 

/*************************************************************************
    > File Name: NSNumber+SBTest.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 六 10/ 3 19:08:19 2015
 ************************************************************************/
#import <Foundation/Foundation.h>
#import "NSNumber+SB.h"

int main(int argc, char * argv[])
{
	@autoreleasepool {
		NSNumber * num = [NSNumber numberWithInt : 3];
		NSNumber * circleAera = [num circleAera : 1];
		NSLog(@"%@", circleAera);
	}
}
           

-- 執行結果 : 

localhost:oc_object octopus$ clang -fobjc-arc -framework Foundation NSNumber+SB.m NSNumber+SBTest.m 
localhost:oc_object octopus$ ./a.out 
2015-10-03 19:18:13.625 a.out[1333:507] 3.1415926
           

2. Category 類别實際用法

(1) 類的子產品化設計

子產品化設計簡介 : 

-- 實作部分唯一 : 定義一個類是, 使用 "類名.h" 定義接口部分, 使用 "類名.m" 定義實作部分, 不能将實作部分定義在多個 ".m" 字尾 檔案中;

-- 檔案臃腫 : 如果類很大, 将所有的代碼放在一個 "類名.m" 檔案中, 非常難維護;

(2) 調用私有方法

私有方法調用簡介 : 

-- 私有方法 : 接口中沒有定義, 在實作部分定義的方法是 私有方法, 不允許被外部調用;

-- 調用私有方法一 : 使用 NSObject 的 "performSelector :"執行調用, 也是可以調用私有方法的, 不過此方法會避開文法檢查, 導緻未知問題;

(3) 調用私有方法 代碼示例

代碼示例 : 

-- OCPrivate.h : 

/*************************************************************************
    > File Name: OCPrivate.h
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 日 10/ 4 06:55:34 2015
 ************************************************************************/
#import <Foundation/Foundation.h>

@interface OCPrivate : NSObject
@property (nonatomic, copy) NSString * name;
-(void) info;
@end
           

-- OCPrivate.m : 

/*************************************************************************
    > File Name: OCPrivate.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 日 10/ 4 06:57:48 2015
 ************************************************************************/
#import "OCPrivate.h"

@implementation OCPrivate
@synthesize name;

- (void) info
{
	NSLog(@"name : %@", self.name);
}

- (void) speak
{
	NSLog(@"Hello World !");
}
@end
           

-- OCPrivate+SB.h : 

/*************************************************************************
    > File Name: OCPrivate+SB.h
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 日 10/ 4 07:19:35 2015
 ************************************************************************/
#import "OCPrivate.h"
@interface OCPrivate (SB)
- (void) speak;
@end
           

-- OCPrivateTest.m : 

/*************************************************************************
    > File Name: OCPrivateTest.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 日 10/ 4 07:22:04 2015
 ************************************************************************/
#import "OCPrivate+SB.h"

int main(int argc, char * argv[])
{
	@autoreleasepool
	{
		OCPrivate * priva = [[OCPrivate alloc] init];
		priva.name = @"Tom";
		[priva info];
		[priva speak];
		
	}
}
           

3. extension 擴充

(1) extension 簡介

extension 簡介 : 

-- 作用 : 擴充相當于匿名類别;

-- 文法 : 

@interface 已有類 ()
{
	//執行個體變量 ...
}
// 方法定義 ...
@end
           

-- 用法 : 定義兩個頭檔案, OCExtension.h 和 OCExtension+speak.h, OCExtension.m 導入 OCExtension+speak.h 頭檔案;

(2) extension 源碼示例

源碼示例 : 

-- OCExtension.h : 

/*************************************************************************
    > File Name: OCExtension.h
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 日 10/ 4 08:18:43 2015
 ************************************************************************/
#import <Foundation/Foundation.h>
@interface OCExtension : NSObject
@property (nonatomic, copy) NSString * name;
@property (nonatomic, assign) int age; 

- (void) info;
@end
           

-- OCExtension+speak.h : 

/*************************************************************************
    > File Name: OCExtension+speak.h
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 日 10/ 4 08:31:37 2015
 ************************************************************************/
#import "OCExtension.h"
@interface OCExtension ()
@property (nonatomic, copy) NSString * home;
- (void) speak : (NSString *) content;
@end
           

-- OCExtension.m : 

/*************************************************************************
    > File Name: OCExtension.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 日 10/ 4 08:27:50 2015
 ************************************************************************/
#import "OCExtension+speak.h"
@implementation OCExtension
@synthesize name;
@synthesize age;
@synthesize home;
- (void) info
{
	NSLog(@"info : name : %@ , age : %d", self.name, self.age);
}
- (void) speak : (NSString *) content
{
	NSLog(@"%@ speak %@", self.name, content);
}
@end
           

-- OCExtensionTest.m : 

/*************************************************************************
    > File Name: OCExtensionTest.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 日 10/ 4 13:20:42 2015
 ************************************************************************/
#import "OCExtension+speak.h"

int main(int argc, char * argv[])
{
	@autoreleasepool {
		OCExtension * extension = [[OCExtension alloc] init];
		extension.name = @"Tom";
		extension.age = 18;
		extension.home = @"China";

		[extension info];
		[extension speak : @"Are you fucking kidding me"];
	}
}
           

三. 協定 與 委托

1. 類别實作非正式協定

(1) 非正式協定簡介

協定簡介 :

-- 作用 : OC 中得協定作用相當于其它語言中得接口;

-- 協定表現 : 協定定義的是 多個類 共同的行為規範, 通常定義一組公用方法, 這些方法都沒有實作, 方法由類來實作;

非正式協定簡介 : 

-- 建立 NSObject 類别 : 以 NSObject 為基礎, 為 NSObject 建立類别, 為該類别指定新增方法, 即給所有的 NSObject 子類增加了新方法;

-- 實作 NSObject 類别 : 實作 NSObject 類别時, 實作該列别下地所有方法, 即之前在 NSObject 類别中定義的方法;

(2) 非正式協定代碼示例

非正式協定代碼示例 : 

-- NSObject+speak.h : 為 NSObject 定義的類别接口, 所有的繼承 NSObject 的類都必須實作該類别中得抽象方法;

/*************************************************************************
    > File Name: NSObject+speak.h
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 08:55:48 2015
 ************************************************************************/
#import <Foundation/Foundation.h>
@interface NSObject (speak)
- (void) speak;
@end
           

-- OCNSObjectProtocal.h : NSObject 子類接口, 該接口繼承 NSObject 類, 注意 需要導入 NSObject+speak.h 頭檔案;

/*************************************************************************
    > File Name: OCNSObjectProtocal.h
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 09:00:37 2015
 ************************************************************************/
#import "NSObject+speak.h"
@interface OCNSObjectProtocal : NSObject
@end
           

-- OCNSObjectProtocal.m : OCNSObjectProtocal 實作類, 在該實作類中必須實作 類别中定義的 speak 方法;

/*************************************************************************
    > File Name: OCNSObjectProtocal.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 09:02:03 2015
 ************************************************************************/
#import "OCNSObjectProtocal.h"
@implementation OCNSObjectProtocal
- (void) speak
{
	NSLog(@"Speak Hello World");
}
@end
           

-- OCNSObjectProtocalTest.m : 測試類, 測試以上代碼是否可以執行;

/*************************************************************************
    > File Name: OCNSObjectProtocalTest.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 09:04:31 2015
 ************************************************************************/
#import "OCNSObjectProtocal.h"

int main(int argc, char * argv[])
{
	@autoreleasepool {
		OCNSObjectProtocal * obj = [[OCNSObjectProtocal alloc] init];
		[obj speak];
	}
}
           

-- 執行結果 : 

bogon:oc_object octopus$ clang -fobjc-arc -framework Foundation OCNSObjectProtocal.m OCNSObjectProtocalTest.m 
bogon:oc_object octopus$ ./a.out 
2015-10-05 09:06:44.895 a.out[2100:507] Speak Hello World
           

2. 定義正式協定

(1) 正式協定文法

正式協定文法 : 

-- 文法 : 

@protocol 協定名稱 <父類協定1, 父類協定2 ...>
// N 個協定方法
@end
           

-- 協定名稱規範 : 采用與類名相同的命名規則;

-- 繼承規則 : 一個協定 可以有 多個父類協定, 協定隻能繼承協定, 不能繼承類;

-- 方法規則 : 協定中隻能定義抽象方法, 不能定義方法實作, 既可以定義類方法, 也可以定義執行個體方法;

(2) 實作協定

實作協定文法 : 

-- 文法 : 

@interface 類名 : 父類 <協定1, 協定2...>
           

-- 對應關系 : 一個類可以實作多個協定;

(3) 聲明協定變量

變量聲明 :

-- 使用原變量聲明 : "變量名 * 對象名" , 如 "OCCat * cat";

-- 使用協定定義 : "NSObject <協定1, 協定2 ...> * 對象名", 如 "NSObject<OCProtocolCat> * cat";

-- 使用 id 類型定義 : "id<OCProtocolCat> 對象名", 如 "id<OCProtocolCat> cat", 注意此處沒有指針辨別; 

(4) 正式協定實作代碼

代碼示例 : 

-- OCAnimalProtocol.h : 最基礎的協定1;

/*************************************************************************
    > File Name: OCAnimalProtocol.h
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 09:25:41 2015
 ************************************************************************/
#import <Foundation/Foundation.h>
@protocol OCAnimalProtocol
- (void) name;
- (void) age;
@end
           

-- OCProtocolBord.h : 最基礎的協定2;

/*************************************************************************
    > File Name: OCProtocolBord.h
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 09:40:08 2015
 ************************************************************************/
#import <Foundation/Foundation.h>
@protocol OCProtocolBord
- (void) fly;
@end
           

-- OCProtocolCat.h : 該協定實作了 上面的兩個協定;

/*************************************************************************
    > File Name: OCProtocolCat.h
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 09:45:17 2015
 ************************************************************************/

#import <Foundation/Foundation.h>
#import "OCAnimalProtocol.h"
#import "OCProtocolBord.h"

@protocol OCProtocolCat <OCAnimalProtocol, OCProtocolBord>
- (void) purr;
@end
           

-- OCCat.h : OCCat 類接口部分, 生命了該類 實作協定 OCProtocolCat 協定;

/*************************************************************************
    > File Name: OCCat.h
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 09:50:21 2015
 ************************************************************************/

#import "OCProtocolCat.h"

@interface OCCat : NSObject <OCProtocolCat>
@end
           

-- OCCat.m : OCCat 類實作部分;

/*************************************************************************
    > File Name: OCCat.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 09:52:45 2015
 ************************************************************************/

 #import "OCCat.h"

 @implementation OCCat
 - (void) name
 {
	NSLog(@"name : cat");
 }
 - (void) age
 {
	NSLog(@"age : 18");
 }
 - (void) fly
 {
	NSLog(@"cat fly");
 }
 - (void) purr
 {
	NSLog(@"cat purr");
 }
 @end
           

-- OCProtocolTest.m : 以上類的功能測試類;

/*************************************************************************
    > File Name: OCProtocolTest.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 10:14:38 2015
 ************************************************************************/

#import <Foundation/Foundation.h>
#import "OCCat.h"

int main(int argc, char * argv[])
{
	@autoreleasepool {
		OCCat * cat = [[OCCat alloc] init];
		[cat name];
		[cat age];
		[cat fly];
		[cat purr];

		NSObject<OCProtocolCat> * cat1 = [[OCCat alloc] init];
		[cat1 name];
		[cat1 age];
		[cat1 fly];
		[cat1 purr];

		id<OCAnimalProtocol> cat2 = [[OCCat alloc] init];
		[cat2 name];
		[cat2 age];
	}
}
           

-- 執行結果 : 

bogon:6.4 octopus$ clang -fobjc-arc -framework Foundation OCCat.m OCProtocolTest.m 
bogon:6.4 octopus$ ./a.out 
2015-10-05 10:24:20.099 a.out[2271:507] name : cat
2015-10-05 10:24:20.101 a.out[2271:507] age : 18
2015-10-05 10:24:20.102 a.out[2271:507] cat fly
2015-10-05 10:24:20.102 a.out[2271:507] cat purr
2015-10-05 10:24:20.102 a.out[2271:507] name : cat
2015-10-05 10:24:20.103 a.out[2271:507] age : 18
2015-10-05 10:24:20.103 a.out[2271:507] cat fly
2015-10-05 10:24:20.104 a.out[2271:507] cat purr
2015-10-05 10:24:20.104 a.out[2271:507] name : cat
2015-10-05 10:24:20.104 a.out[2271:507] age : 18
           

3. 委托

委托概念 : 定義協定的類 将 定義協定的方法 委托給 實作協定的類;

-- 好處 : 類具有更好地通用性, 具體的動作交給實作類完成;

建立工程 : 

-- 歡迎界面, 選擇 Create a new xcode project;

【IOS 開發】Objective - C 面向對象進階特性 - 包裝類 | 類處理 | 類别 | 擴充 | 協定 | 委托 | 異常處理 | 反射一. Objective-C 對象簡單處理二. 類别 與 擴充三. 協定 與 委托四. 異常處理五. Objective-C 反射

-- 建立一個 OS 下地 Cocoa Application : 

【IOS 開發】Objective - C 面向對象進階特性 - 包裝類 | 類處理 | 類别 | 擴充 | 協定 | 委托 | 異常處理 | 反射一. Objective-C 對象簡單處理二. 類别 與 擴充三. 協定 與 委托四. 異常處理五. Objective-C 反射

-- 建立 工程 : 

【IOS 開發】Objective - C 面向對象進階特性 - 包裝類 | 類處理 | 類别 | 擴充 | 協定 | 委托 | 異常處理 | 反射一. Objective-C 對象簡單處理二. 類别 與 擴充三. 協定 與 委托四. 異常處理五. Objective-C 反射

項目中得源檔案 : 

-- main.m : main() 函數入口;

-- OCAppDelegate.h : OCAppDelegate 類接口檔案;

-- OCAppDelegate.m : OCAppDelegate 類實作部分;

【IOS 開發】Objective - C 面向對象進階特性 - 包裝類 | 類處理 | 類别 | 擴充 | 協定 | 委托 | 異常處理 | 反射一. Objective-C 對象簡單處理二. 類别 與 擴充三. 協定 與 委托四. 異常處理五. Objective-C 反射

代碼示例 : 

-- 前置操作 : 删除 MainMenu.xib 檔案, 删除 Hello-Info.plist 中的 MainMenu 選項;

【IOS 開發】Objective - C 面向對象進階特性 - 包裝類 | 類處理 | 類别 | 擴充 | 協定 | 委托 | 異常處理 | 反射一. Objective-C 對象簡單處理二. 類别 與 擴充三. 協定 與 委托四. 異常處理五. Objective-C 反射

-- OCAppDelegate.h : 

//
//  OCAppDelegate.h
//  Hello
//
//  Created by octopus on 15-10-5.
//  Copyright (c) 2015年 www.octopus.org.cn. All rights reserved.
//

#import <Cocoa/Cocoa.h>

//該接口 實作 NSApplicationDelegate 協定
@interface OCAppDelegate : NSObject <NSApplicationDelegate>
//定義視窗
@property (strong) NSWindow *window;

@end
           

-- OCAppDelegate.m : 

//
//  OCAppDelegate.m
//  Hello
//
//  Created by octopus on 15-10-5.
//  Copyright (c) 2015年 www.octopus.org.cn. All rights reserved.
//

#import "OCAppDelegate.h"

@implementation OCAppDelegate
@synthesize window;

//應用加載完成時回調的方法
- (void)applicationWillFinishLaunching:(NSNotification *)notification
{
    //設定視窗屬性
    self.window = [[NSWindow alloc] initWithContentRect :
                   NSMakeRect(300, 300, 320, 200)
                   styleMask:(NSTitledWindowMask | NSMiniaturizableWindowMask |NSClosableWindowMask)
                   backing:NSBackingStoreBuffered
                   defer:NO];
    self.window.title = @"Hello World";
    
    //設定文本框屬性
    NSTextField * label = [[NSTextField alloc] initWithFrame:NSMakeRect(60, 120, 200, 60)];
    [label setSelectable:YES];
    [label setBezeled:YES];
    [label setDrawsBackground:YES];
    [label setStringValue:@"HELLO WORLD"];
    
    //設定按鈕屬性
    NSButton * button = [[NSButton alloc] initWithFrame:NSMakeRect(120, 40, 80, 30)];
    button.title = @"OCTOPUS";
    [button setBezelStyle:NSRoundedBezelStyle];
    [button setBounds:NSMakeRect(120, 40, 80, 30)];
    
    //将 文本框 和 按鈕 添加到視窗中
    [self.window.contentView addSubview:label];
    [self.window.contentView addSubview:button];
}

//加載完成時回調的方法
- (void) applicationDidFinishLaunching:(NSNotification *)notification
{
    //顯示視窗
    [self.window makeKeyAndOrderFront:self];
}

@end
           

-- main.m : 

//
//  main.m
//  Hello
//
//  Created by octopus on 15-10-5.
//  Copyright (c) 2015年 www.octopus.org.cn. All rights reserved.
//

#import <Cocoa/Cocoa.h>
#import "OCAppDelegate.h"

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        //建立一個實作了 NSApplicationDelegate 協定的對象
        OCAppDelegate * delegate = [[OCAppDelegate alloc] init];
        //擷取 NSApplication 單例對象
        [NSApplication sharedApplication];
        //設定代理, 将處理方法委托給 delegate
        [NSApp setDelegate : delegate];
        //開始運作程式
        return NSApplicationMain(argc, argv);
    }
    
}
           

-- 運作結果 : 

【IOS 開發】Objective - C 面向對象進階特性 - 包裝類 | 類處理 | 類别 | 擴充 | 協定 | 委托 | 異常處理 | 反射一. Objective-C 對象簡單處理二. 類别 與 擴充三. 協定 與 委托四. 異常處理五. Objective-C 反射

四. 異常處理

1. @try ... @catch ... @finally ... 異常捕捉

(1) Objective-C 異常機制

Objective-C 異常機制 : 

-- 作用 : 開發者将引發異常的代碼放在 @try 代碼塊中, 程式出現異常 使用 @catch 代碼塊進行捕捉;

-- 每個代碼塊作用 : @try 代碼塊存放可能出現異常的代碼, @catch 代碼塊 異常處理邏輯, @finally 代碼塊回收資源;

-- 文法示例 : 

@try
{
	// 業務邏輯
}
@catch (異常類型名1 ex)
{
	//異常處理代碼
}
@catch (異常類型名2 ex)
{
	//異常處理代碼
}
// 可以捕捉 N 個 異常 ...
@finally
{
	//回收資源
}
           

(2) Objective-C 異常處理過程

異常處理過程 : 

-- 生成異常對象 : @try 中出現異常, 系統會生成一個異常對象, 該對象送出到系統中 系統就會抛出異常;

-- 異常處理流程 : 運作環境接收到 異常對象時, 如果存在能處理該異常對象的 @catch 代碼塊, 就将該異常對象交給 @catch 處理, 該過程就是捕獲異常, 如果沒有 @catch 代碼塊處理異常, 程式就會終止;

-- @catch 代碼塊捕獲過程 : 運作環境接收到 異常對象 時, 會依次判斷該異常對象類型是否是 @catch 代碼塊中異常或其子類執行個體, 如果比對成功, 被比對的 @catch 就會處理該異常, 都則就會跟下一個 @catch 代碼塊對比;

-- @catch 處理異常 : 系統将異常對象傳遞給 @catch 形參, @catch 通過該形參擷取異常對象詳細資訊;

其它注意點 : 

-- @try 與 @catch 對應關系 : 一個 @try 代碼塊 可以對應 多個 @catch 代碼塊; 

-- {} 省略問題 : 異常捕獲的 @try @catch @finally 的花括号不可省略;

NSException 異常類 : 

-- 簡介 : NSException 是 OC 中所有異常的父類;

-- 位置永遠在最後 : @catch 代碼塊捕獲異常時檢視 異常對象類型是否是 捕獲的異常類型 或者其子類, 一旦放在開頭, 後面的異常永遠不可能捕獲;

(3) 異常資訊通路

異常資訊通路 : 

-- name : 傳回異常的詳細名稱;

-- reason : 傳回異常引發的原因;

-- userInfo : 傳回異常的使用者資訊, 一個 NSDictionary 對象;

(4) 使用 finally 回收資源

回收實體資源 : @try 代碼塊中打開實體資源, 資料庫 網絡連接配接 檔案等, 都需要回收, 在 @finally 中回收最好;

-- 回收位置分析 : 如果再 @try 中回收, 出現異常, 異常後面的代碼無法執行, @catch 中回收, 如果不出現異常, 該代碼塊就不會執行; 是以 finally 中是必執行的代碼, 在這裡回收最合适;

(5) 異常代碼示例

異常代碼示例 : 

-- OCAnimal.h : 定義協定;

/*************************************************************************
    > File Name: OCAnimal.h
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 16:30:02 2015
 ************************************************************************/
#import <Foundation/Foundation.h>

@protocol OCAnimal
@optional
- (void) run;
@end
           

-- OCCat.h : 定義 OCCat 接口;

/*************************************************************************
    > File Name: OCCat.h
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 16:33:59 2015
 ************************************************************************/
#import "OCAnimal.h"

@interface OCCat : NSObject <OCAnimal>
@end
           

-- OCCat.m : 定義 OCCat 實作類;

/*************************************************************************
    > File Name: OCCat.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 16:36:36 2015
 ************************************************************************/
#import "OCCat.h"

@implementation OCCat
@end
           

-- OCCatTest.m : 測試類;

/*************************************************************************
    > File Name: OCCatTest.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 16:38:01 2015
 ************************************************************************/
#import "OCCat.h"

int main(int argc, char * argv[])
{
	@autoreleasepool {
		OCCat * cat = [[OCCat alloc] init];
		[cat run];
	}
}
           

-- 執行結果 : 

bogon:6.5 octopus$ clang -fobjc-arc -framework Foundation OCCat.m OCCatTest.m 
bogon:6.5 octopus$ ./a.out 
2015-10-05 16:39:23.589 a.out[2985:507] -[OCCat run]: unrecognized selector sent to instance 0x7fd7a3401870
2015-10-05 16:39:23.611 a.out[2985:507] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[OCCat run]: unrecognized selector sent to instance 0x7fd7a3401870'
*** First throw call stack:
(
	0   CoreFoundation                      0x00007fff903dd25c __exceptionPreprocess + 172
	1   libobjc.A.dylib                     0x00007fff8ecdbe75 objc_exception_throw + 43
	2   CoreFoundation                      0x00007fff903e012d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
	3   CoreFoundation                      0x00007fff9033b044 ___forwarding___ + 452
	4   CoreFoundation                      0x00007fff9033adf8 _CF_forwarding_prep_0 + 120
	5   a.out                               0x0000000108575efd main + 109
	6   libdyld.dylib                       0x00007fff851f35fd start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
Abort trap: 6
           

(6) 異常捕獲代碼示例

異常捕擷取示例 : 該示例扔使用上面的 OCAnimal.h, OCCat.h, OCCat.m 示例;

-- OCCatTest.m : 

/*************************************************************************
    > File Name: OCCatTest.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 16:38:01 2015
 ************************************************************************/
#import "OCCat.h"

int main(int argc, char * argv[])
{
	@autoreleasepool {
		@try
		{
			OCCat * cat = [[OCCat alloc] init];
			[cat run];
		}
		@catch (NSException * ex)
		{
			NSLog(@"exception name : %@, reason : %@", ex.name, ex.reason);
		}
		@finally
		{
			NSLog(@"finally execute");
		}
		NSLog(@"success");
	}
}
           

-- 執行結果 : 

bogon:6.5 octopus$ clang -fobjc-arc -framework Foundation OCCat.m OCCatTest.m 
bogon:6.5 octopus$ ./a.out 
2015-10-05 16:53:46.850 a.out[3008:507] -[OCCat run]: unrecognized selector sent to instance 0x7f884bc018b0
2015-10-05 16:53:46.853 a.out[3008:507] exception name : NSInvalidArgumentException, reason : -[OCCat run]: unrecognized selector sent to instance 0x7f884bc018b0
2015-10-05 16:53:46.853 a.out[3008:507] finally execute
2015-10-05 16:53:46.854 a.out[3008:507] success
           

2. 抛出自定義異常

(1) 自定義異常文法

自定義異常抛出 : 

-- 文法 : 

@throw 異常對象;
           

(2) 自定義異常代碼示例

自定義異常代碼示例 : 

-- OCException.h 接口 : 

/*************************************************************************
    > File Name: OCException.h
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 16:58:24 2015
 ************************************************************************/
#import <Foundation/Foundation.h>

@interface OCException : NSException
@end
           

-- OCException.m 實作類 : 

/*************************************************************************
    > File Name: OCException.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 17:03:15 2015
 ************************************************************************/
#import "OCException.h"

@implementation OCException
@end
           

-- OCCatTest.m 測試類 : 

/*************************************************************************
    > File Name: OCCatTest.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 16:38:01 2015
 ************************************************************************/
#import "OCException.h"

int main(int argc, char * argv[])
{
	@autoreleasepool
	{
		@throw [[OCException alloc] 
			initWithName : @"OCException" 
			reason : @"this reason is imporant"
			userInfo : nil];
	}
}
           

-- 執行結果 : 

bogon:6.5 octopus$ clang -fobjc-arc -framework Foundation OCException.m OCCatTest.m
bogon:6.5 octopus$ ./a.out 
2015-10-05 17:04:12.432 a.out[3040:507] *** Terminating app due to uncaught exception 'OCException', reason: 'this reason is imporant'
*** First throw call stack:
(
	0   CoreFoundation                      0x00007fff903dd25c __exceptionPreprocess + 172
	1   libobjc.A.dylib                     0x00007fff8ecdbe75 objc_exception_throw + 43
	2   a.out                               0x00000001062abef7 main + 135
	3   libdyld.dylib                       0x00007fff851f35fd start + 1
)
libc++abi.dylib: terminating with uncaught exception of type OCException
Abort trap: 6
           

五. Objective-C 反射

1. 擷取 Class

(1) 程式 與 環境 互動方式

程式 與 運作環境互動方式 : 

-- 通過 OC 源碼 : 編寫 OC 源碼, 編譯器編譯, 運作在運作環境中;

-- 通過 NSObject 動态程式設計 : NSObject 是所有類的基類, 所有對象都可以直接調用 NSObject 方法;

-- 調用 運作時函數 動态程式設計 : 運作時系統是動态庫, 可以直接調用這些動态共享庫;

(2) 擷取 Class 方式

擷取 Class 方式 : 

-- 通過類名 : 使用 "Class NSClassFromString (NSString * aClassName)" 函數擷取 Class 對象, 傳入 類名 字元串;

-- class 類方法 : 調用類方法 class, 調用方式 [NSString class];

-- class 對象方法 : 調用對象的 class 方法, 調用方式 [@"hello" class];

-- 推薦使用第二種方式 : 代碼更安全, 編譯階段就可以檢查 Class 是否存在, 程式性能高;

(3) 擷取 Class 代碼示例

代碼示例 : 

/*************************************************************************
    > File Name: OCGetClass.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 23:31:51 2015
 ************************************************************************/

#import <Foundation/Foundation.h>

int main(int argc, char * argv[])
{
	@autoreleasepool {
		//通過 NSClassFromString 方法傳入 類名字元串 擷取 Class 對象
		Class clazz = NSClassFromString(@"NSDate");
		NSLog(@"%@", clazz);
		id date = [[clazz alloc] init];
		NSLog(@"date : %@", date);

		NSString * str = @"hello";
		// 通過調用 類 或 對象的 class 方法 
		NSLog(@"[str class] : %@, [NSString class] : %@", [str class], [NSString class]);
		// 通過調用 類 或 對象的 getter 方法擷取, 即用 . 方法擷取
		NSLog(@"str.class : %@, NSString.class : %@", str.class, NSString.class);

	}
}
           

-- 執行結果 : 

bogon:6.6 octopus$ clang -fobjc-arc -framework Foundation OCGetClass.m 
bogon:6.6 octopus$ ./a.out 
2015-10-05 23:39:28.692 a.out[3237:507] NSDate
2015-10-05 23:39:28.699 a.out[3237:507] date : 2015-10-05 15:39:28 +0000
2015-10-05 23:39:28.700 a.out[3237:507] [str class] : __NSCFConstantString, [NSString class] : NSString
2015-10-05 23:39:28.700 a.out[3237:507] str.class : __NSCFConstantString, NSString.class : NSString
           

2. 檢查繼承關系

(1) 繼承關系判斷

繼承關系判斷方法 : 

-- 判斷類 : isMemberOfClass 方法, 傳入 Class 對象, 判斷該對象是否是 Class 對象對應類的執行個體;

-- 判斷類或子類 : isKindOfClass 方法, 傳入 Class 對象, 判斷該對象是否是 Class 對象對應類 或 子類的執行個體;

-- 判斷協定 : conformsToProtocol 犯法, 傳入 Protocol 參數, 傳入方法 "@protocol(協定名稱)" 或者  "Protocol * NSProtocolFromString(NSString * @"協定名稱")" 兩種方法擷取協定參數;

(2) 繼承關系判斷代碼示例

源碼示例 : 

-- OCAnimal.h : 定義協定;

/*************************************************************************
    > File Name: OCAnimal.h
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 23:54:14 2015
 ************************************************************************/
#import <Foundation/Foundation.h>

@protocol OCAnimal
- (void) name;
@end
           

-- OCCat.h : 定義接口;

/*************************************************************************
    > File Name: OCCat.h
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 23:56:16 2015
 ************************************************************************/
#import "OCAnimal.h"

@interface OCCat : NSObject <OCAnimal>
@end
           

-- OCCat.m : 定義實作類;

/*************************************************************************
    > File Name: OCCat.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 一 10/ 5 23:58:47 2015
 ************************************************************************/
#import "OCCat.h"

@implementation OCCat
- (void) name
{
	NSLog(@"My name is Tom");
}
@end
           

-- OCCatMain.m : 測試類;

/*************************************************************************
    > File Name: OCCatMain.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 二 10/ 6 00:00:01 2015
 ************************************************************************/
#import "OCCat.h"

int main(int argc, char * argv[])
{
	@autoreleasepool {
		OCCat * cat = [[OCCat alloc] init];
		NSLog(@"%@", cat.class);

		NSLog(@"cat isMemberOfClass OCCat : %d", [cat isMemberOfClass : OCCat.class]);
		NSLog(@"cat isMemberOfClass NSObject : %d", [cat isMemberOfClass : NSObject.class]);
		NSLog(@"cat isKindOfClass OCCat : %d", [cat isKindOfClass : OCCat.class]);
		NSLog(@"cat isKindOfClass OCCat : %d", [cat isKindOfClass : NSObject.class]);
		NSLog(@"cat conformsToProtocol OCAnimal : %d", [cat conformsToProtocol : @protocol(OCAnimal)]);
	}
}
           

-- 執行結果 : 

bogon:6.6 octopus$ clang -fobjc-arc -framework Foundation OCCat.m OCCatMain.m 
bogon:6.6 octopus$ ./a.out 
2015-10-06 00:07:56.838 a.out[3337:507] OCCat
2015-10-06 00:07:56.840 a.out[3337:507] cat isMemberOfClass OCCat : 1
2015-10-06 00:07:56.840 a.out[3337:507] cat isMemberOfClass NSObject : 0
2015-10-06 00:07:56.841 a.out[3337:507] cat isKindOfClass OCCat : 1
2015-10-06 00:07:56.841 a.out[3337:507] cat isKindOfClass OCCat : 1
2015-10-06 00:07:56.842 a.out[3337:507] cat conformsToProtocol OCAnimal : 1
           

3. 動态調用方法

(1) 動态調用成員變量

KVC 機制 : 通過該機制可以動态調用對象的 getter 和 setter 方法, 不論 該變量定義位置 (接口 | 實作) 和 使用何種通路控制符 (private | public), 都可以使用 KVC 通路;

(2) 判斷方法是否可調用

判斷對象是否可以調用方法 : NSObject 中定義了 respondsToSelector : 方法, 該方法傳入 SEL 參數, 該參數代表方法, 如果可以調用 傳回 YES, 反之 傳回 NO;

擷取 SEL 對象方法 : 

-- 指令擷取 : 使用 @selector 指令擷取目前類中指定的方法, 參數是 完整的方法簽名關鍵字, 隻有方法名不夠;

@selector(setAge:) withObject
           

-- 方法擷取 : 使用 SEL NSSelectorFromString(NSString * aSelectorName) 函數, 根據方法簽名關鍵字字元串擷取對應方法;

NSSelectorFromString(@"setAge:")
           

(3) SEL 動态調用方法

動态調用對象方法 : 

-- 動态調用一 : NSObject 的 performSelector : 方法可以調用方法, 需要傳入 SEL 對象, 傳入參數 可以通過 withObject: 标簽傳入參數;

[student performSelector : @selector(setAge:) withObject : [NSNumber numberWithInt : 18]];
[student performSelector : NSSelectorFromString(@"setAge:") withObject : [NSNumber numberWithInt : 19]];
           

-- 動态調用二 : objc_msgSend(receiver, selector, ...) 函數調用方法, 參數一 方法調用者, 參數二 調用的方法, 剩餘參數 方法參數;

objc_msgSend (student, @selector(setAge:), [NSNumber numberWithInt : 20]);
objc_msgSend (student, NSSelectorFromString(@"setAge:"), [NSNumber numberWithInt : 21]);
           

-- 注意 : 使用第二種方法需要導入包 "#import <objc/message.h>", 傳回浮點數時調用 objc_msgSend_fpret(), 傳回結構體資料時 使用 objc_msgSend_stret() 函數;

(4) IMP 動态調用方法

IMP 動态調用方法 簡介 : 

-- 擷取 IMP 對象 : NSObject 定義了 "- (IMP) methodForSelector : (SEL) aSelector :" 方法, 該方法傳入 SEL 參數, 傳回 IMP 對象;

-- IMP 作用 : IMP 是 OC 方法函數指針變量, 代表函數入口, 通過 IMP 也可以調用函數;

-- IMP 調用方法文法 : "傳回值類型 (*指針變量) (id, SEL, ...)" , 參數一 方法調用者, 參數二 方法 SEL 對象, 後面參數是方法參數;

(5) 動态調用方法 示例代碼

示例代碼 : 

-- OCStudent.m : 接口實作類主函數一體;

/*************************************************************************
    > File Name: OCStudent.m
    > Author: octopus
    > Mail: octopus_truth.163.com 
    > Created Time: 二 10/ 6 11:19:49 2015
 ************************************************************************/
#import <Foundation/Foundation.h>
#import <objc/message.h>

@interface OCStudent : NSObject
@end

@implementation OCStudent

- (void) setAge : (NSNumber *) age
{
	int age_num = [age intValue];
	NSLog(@"age is : %d", age_num);
}
@end

int main(int argc, char * argv[])
{
	@autoreleasepool
	{
		OCStudent * student = [[OCStudent alloc] init];

		[student performSelector : @selector(setAge:) withObject : [NSNumber numberWithInt : 18]];
		[student performSelector : NSSelectorFromString(@"setAge:") withObject : [NSNumber numberWithInt : 19]];

		objc_msgSend (student, @selector(setAge:), [NSNumber numberWithInt : 20]);
		objc_msgSend (student, NSSelectorFromString(@"setAge:"), [NSNumber numberWithInt : 21]);
	}
}
           

-- 執行結果 : 有報警;

bogon:6.6 octopus$ clang -fobjc-arc -framework Foundation OCStudent.m 
OCStudent.m:29:12: warning: performSelector may cause a leak because its selector is unknown [-Warc-performSelector-leaks]
                [student performSelector : NSSelectorFromString(@"setAge:") withObject : [NSNumber numberWithInt : 19]];
                         ^
OCStudent.m:29:30: note: used here
                [student performSelector : NSSelectorFromString(@"setAge:") withObject : [NSNumber numberWithInt : 19]];
                                           ^
1 warning generated.
bogon:6.6 octopus$ ./a.out 
2015-10-06 12:00:41.669 a.out[747:507] age is : 18
2015-10-06 12:00:41.671 a.out[747:507] age is : 19
2015-10-06 12:00:41.671 a.out[747:507] age is : 20
2015-10-06 12:00:41.672 a.out[747:507] age is : 21
           

繼續閱讀