Objective-C中非傳統設計模式的探索與實踐

本文還有配套的精品資源,點擊獲取 menu-r.4af5f7ec.gif

簡介:Objective-C的設計模式不僅僅局限于經典模式,還可以利用其動態特性實現一些非傳統的模式。本文介紹了一系列基于Objective-C動態特性的設計模式,包括使用協議代替類繼承、通過分類擴展類功能、利用KVC和KVO實現屬性訪問與觀察、使用Blocks作為閉包實現回調和并發、代理模式的變體、消息轉發機制、以及利用工廠方法、分類和Category實現單例、分類的分類、私有方法的實現等。這些設計模式提高了代碼的靈活性和可維護性,并在實際開發中發揮重要作用。
簡單的一些非經典的objc設計模式

1. objc非經典設計模式的理論基礎

在Objective-C編程的世界中,傳統的設計模式如單例、工廠、策略等被廣泛應用,但objc語言特有的靈活性和動態特性,讓我們有機會探索一些非傳統的設計模式。這些非經典設計模式并不遵循傳統的設計原則,但它們利用objc的特性,如動態類型、消息傳遞和運行時特性,能夠提供更簡潔或更高效的解決方案。

1.1 設計模式在objc中的演變

設計模式是軟件工程中的經典概念,它們是解決特定問題的最佳實踐。然而,objc語言的特性讓一些經典設計模式在使用時發生了變化,或者產生了更為簡潔的替代方案。非經典設計模式正是這些變化和替代方案的體現。

1.2 非經典設計模式的重要性

掌握非經典設計模式對于objc開發者來說至關重要。這不僅能夠幫助我們深入理解語言特性,還能夠引導我們編寫出更加高效和優雅的代碼。特別是在框架和庫開發過程中,非經典設計模式的使用可以顯著提高代碼的靈活性和可維護性。

1.3objc語言的特性與設計模式的關系

objc語言的動態特性、協議(Protocols)、分類(Categories)以及塊(Blocks)等,為設計模式的實現提供了獨特的優勢。非經典設計模式的產生往往根植于這些語言特性,它們與objc的運行時特性緊密結合,使得設計模式的實現更加直觀和簡潔。

在后續的章節中,我們將深入探討如何利用objc的特性來實現和應用非經典設計模式,以及它們在實際開發中帶來的創新和效率。

2. 利用協議實現接口的繼承與多態

2.1 協議作為接口的定義和作用

2.1.1 接口的引入與協議的基本用法

在Objective-C中,協議(Protocol)是一種定義一組方法的接口規范,這些方法可以由任何類來實現。協議提供了一種方式,允許不同的類實現同一組方法,而不必關心它們的繼承關系。這就像是在不同對象之間建立了一種新的“契約”關系。

協議的基本用法示例如下:

// 定義一個協議
@protocol SomeProtocol <NSObject>
- (void)doSomething;
@end// 類聲明遵循協議
@interface SomeClass : NSObject <SomeProtocol>
@end// 類實現協議
@implementation SomeClass
- (void)doSomething {NSLog(@"Doing something!");
}
@end

在上述代碼中,我們首先定義了一個名為 SomeProtocol 的協議,并聲明了一個名為 doSomething 的方法。隨后,我們聲明了一個 SomeClass 類,它遵循了 SomeProtocol 協議,并實現了協議中的 doSomething 方法。

2.1.2 協議與類繼承的區別和聯系

協議與類繼承的主要區別在于它們在實現多態的方式上。類繼承是基于“is-a”的關系,而協議則是基于“can-do”的能力描述。繼承意味著子類將從父類那里獲得屬性和方法,而協議僅規定了必須實現的方法集合。

從聯系上說,協議可以與類繼承相結合,形成更靈活的設計。一個類可以同時遵循多個協議,也可以繼承自一個類同時遵循多個協議,這為Objective-C中的面向對象設計提供了極高的自由度。

2.2 協議實現多態的方法和優勢

2.2.1 協議與多態性結合的場景分析

協議與多態性的結合,可以在不增加類層次復雜度的情況下,提供一種松耦合的擴展機制。比如,使用協議來定義一系列操作,然后讓不同的類實現這些協議,從而實現相同的操作在不同對象上具有不同的實現,即多態。

例如,假設我們有一個處理數據的協議 DataHandler

@protocol DataHandler <NSObject>
- (void)processData:(NSData *)data;
@end@interface JSONDataHandler : NSObject <DataHandler>
@end@implementation JSONDataHandler
- (void)processData:(NSData *)data {// 處理JSON數據的邏輯
}
@end@interface XMLDataHandler : NSObject <DataHandler>
@end@implementation XMLDataHandler
- (void)processData:(NSData *)data {// 處理XML數據的邏輯
}
@end

這里, JSONDataHandler XMLDataHandler 都遵循了 DataHandler 協議,并提供了自己對 processData: 方法的實現。這樣,當我們需要處理數據時,我們只需要依賴 DataHandler 協議,而不需要關心具體是哪個類來處理的。

2.2.2 利用協議實現面向對象設計的靈活性

協議是Objective-C面向對象編程中的一個關鍵特性,它允許開發者定義可被多個不同類實現的方法集合。這種機制提供了極高的靈活性和擴展性,特別是在以下方面:

  • 委托模式 :協議常被用作定義委托(Delegate)接口,允許多個對象根據協議實現各自的行為。
  • 數據源 :例如, UITableView 通過協議方法獲取數據,這些方法可以由任何遵循 UITableViewDataSource 協議的類實現。
  • 單元測試 :協議使得模擬和測試變得更加容易,因為可以在測試環境中用遵循特定協議的偽對象替代真實對象。
// 定義一個簡單的協議
@protocol MyProtocol;
@interface MyClass : NSObject <MyProtocol>
@end// 定義協議
@protocol MyProtocol <NSObject>
- (void)myProtocolMethod;
@end// 實現協議
@implementation MyClass
- (void)myProtocolMethod {NSLog(@"Implementing MyProtocolMethod");
}
@end

在這個例子中,我們定義了一個 MyProtocol 協議,并且 MyClass 類遵循并實現了協議中的方法。這種方式確保了 MyClass 實例能夠響應與協議相關的方法調用。

總的來說,協議在Objective-C中的應用提供了程序設計上的靈活性,它可以幫助開發者創建既松耦合又高度可擴展的系統架構。

3. 分類(Category)的高級應用技巧

3.1 分類(Category)擴展類功能的原理和實踐

3.1.1 分類的定義及其背后的機制

在 Objective-C 中,分類(Category)是一種強大的語言特性,允許開發者向已有的類中動態添加方法,而不必訪問類的源代碼,也不需要創建子類。這種機制非常適用于對第三方類庫或系統框架進行擴展。分類通過聲明一個新的 .h 文件和相應的 .m 文件來定義,其背后的工作原理基于運行時(Runtime)機制。

在運行時,每個對象都持有一個方法列表,分類的實現將新方法添加到這個列表中。編譯器在編譯階段會將分類中聲明的方法合并到原類的方法列表中,從而實現了對類的擴展。這種方式不會改變原有類的定義,使得分類成為了一種擴展類功能的非侵入式手段。

3.1.2 分類在不同場景下的應用方法

分類的應用場景非常廣泛,以下是一些典型的使用案例:

  • 模塊化代碼 :將不同的功能模塊化,每個分類代表一個功能模塊。例如,為 NSString 類添加一個分類,專門處理字符串格式化功能。
  • 隱藏私有API :在公共頭文件中聲明公共接口,將實現細節放在分類中,這樣可以保持接口的簡潔性,同時將細節隱藏。
  • 避免類的膨脹 :當一個類的功能變得龐大時,可以通過分類來組織和分散代碼,使其更易于管理和維護。
  • 代碼調試和優化 :將實驗性的代碼和優化功能放在分類中,不影響現有項目的穩定性和其他功能的正常運行。

3.2 分類與其他設計模式的結合

3.2.1 分類與繼承模式的比較

分類和繼承都是面向對象編程中的重要概念,它們都可以用于擴展類的功能,但它們有本質的不同:

  • 繼承 是一種靜態關系,子類通過繼承獲得父類的所有屬性和方法,并可以添加或重寫它們。繼承是面向對象中的基本關系,但過于緊密,子類和父類之間耦合度較高。
  • 分類 是一種動態關系,它在不改變原類定義的情況下,向類中添加方法。分類更靈活,可以被多個類包含,且與原類解耦。

在實際開發中,選擇繼承還是分類取決于具體需求。如果需要進行面向對象的多態設計,繼承通常是更合適的選擇。當需要對第三方類庫進行擴展,或希望保持類之間的解耦,分類是更優的選擇。

3.2.2 分類實現私有方法的技術剖析

在 Objective-C 中,分類還可以用來封裝私有方法。私有方法通常是指那些只在類的實現文件中使用,而不希望在類的外部被調用的方法。通過分類,我們可以將這些私有方法集中管理,而不是散布在類的實現文件中。這不僅有助于保持類的整潔,還可以在需要時輕松地對這些私有方法進行重構。

通過在 .m 文件中聲明分類(通常命名為 PrivateCategory ),可以將私有方法聲明在其中。但是,需要注意的是,分類中的方法默認是公開的。要實現真正的私有方法,需要采取額外的措施,例如利用編譯器的屬性控制( static 關鍵字或使用 __private 屬性)來確保這些方法不會被外部訪問。

下面是一個簡單的例子:

// 在NSString+Private.h文件中
@interface NSString (Private)
- (void)privateMethod;
@end// 在NSString+Private.m文件中
@implementation NSString (Private)
- (void)privateMethod {// 私有方法的實現
}
@end

請注意,雖然分類使得私有方法更容易被訪問,但最佳實踐是不要過分依賴分類來實現真正的私有功能,因為運行時仍然可以通過反射訪問這些方法。更安全的私有方法實現方式包括使用類擴展(class extensions)或者將私有方法放在實現文件中不進行聲明。

@interface NSString ()
- (void)_reallyPrivateMethod;
@end

通過上述方法,可以安全地將方法定義為真正的私有方法,因為它們不會出現在類的公開接口中,也不會被其他文件訪問。

4. KVC與KVO在objc中的數據綁定技術

在Objective-C編程中,KVC(鍵值編碼)和KVO(鍵值觀察)提供了強大的數據綁定和動態觀察機制,極大地增強了模型與視圖間的解耦和數據的動態交互能力。本章深入探討這兩個技術的基本原理、用途以及如何在項目中實現數據綁定和屬性觀察的案例。

4.1 KVC與KVO的基本原理和用途

4.1.1 KVC的鍵值編碼機制解析

KVC允許我們通過字符串的鍵(key)直接訪問和設置對象的屬性,而無需調用該屬性的setter和getter方法。這通過Objective-C運行時的特性來實現,使得動態語言的特性在編譯時靜態語言中得到體現。

在KVC中,我們經常使用 valueForKey: setValue:forKey: 來訪問和修改屬性。需要注意的是,如果訪問不存在的鍵,程序會拋出異常。

// 使用KVC設置對象的屬性值
Person *person = [[Person alloc] init];
[person setValue:@"John Doe" forKey:@"name"];
// 使用KVC獲取對象的屬性值
NSString *name = [person valueForKey:@"name"];
代碼邏輯的逐行解讀分析
  • Person *person = [[Person alloc] init]; 創建了一個Person類的實例。
  • [person setValue:@"John Doe" forKey:@"name"]; 通過KVC機制,將name屬性的值設置為”John Doe”。
  • NSString *name = [person valueForKey:@"name"]; 通過KVC獲取person對象name屬性的值,并將該值存儲到字符串變量name中。

4.1.2 KVO的鍵值觀察模式實現細節

KVO是一種觀察者模式的實現,它允許對象監聽其他對象屬性值的變化。當被觀察對象的屬性值改變時,觀察者對象會收到通知。KVO利用Objective-C運行時動態地為對象添加屬性的getter和setter方法,從而實現對屬性變化的監控。

// 注冊觀察者
[person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];// 被觀察者屬性變化
[person setName:@"Jane Doe"];// 實現觀察者回調方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {if ([keyPath isEqualToString:@"name"]) {NSString *newValue = change[NSKeyValueChangeNewKey];NSLog(@"新名字是: %@", newValue);}
}
代碼邏輯的逐行解讀分析
  • [person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil]; 在person對象上注冊一個觀察者,觀察其name屬性的變化。
  • [person setName:@"Jane Doe"]; 更改person對象的name屬性值。
  • observeValueForKeyPath:ofObject:change:context: 當被觀察的屬性值變化時,這個方法會被調用,我們在這個方法中可以根據屬性鍵(keyPath)判斷具體哪個屬性發生了變化,并進行相應的操作。

4.2 利用KVC與KVO進行數據綁定和屬性觀察的案例

4.2.1 數據綁定在模型與視圖之間的應用

數據綁定是將視圖的屬性與模型的屬性進行關聯,當模型屬性改變時,視圖會自動更新。KVC和KVO能夠有效地在模型和視圖之間建立這種動態的綁定關系。

以一個簡單的用戶界面為例,我們要實現一個文本框顯示用戶的姓名,當模型中用戶的姓名屬性更新時,文本框中顯示的姓名也自動更新。

graph LR;
A[模型Model] -->|KVO監聽| B[數據同步]
B --> C[更新視圖View]
數據綁定流程說明
  1. 模型Model :定義用戶的數據模型,包含用戶的姓名等屬性。
  2. 數據同步 :當Model中的用戶姓名屬性被修改時,KVO機制會觸發通知,數據同步過程開始。
  3. 更新視圖View :將新的數據(新的姓名)更新到界面的文本框組件。

4.2.2 屬性觀察在業務邏輯中的實踐技巧

在業務邏輯層,使用KVO不僅可以監控數據的變化,還能根據數據的變化做出相應的業務處理。例如,我們可以基于用戶的登錄狀態變化來更新應用的導航欄顯示。

// 用戶類User
@interface User : NSObject
@property (nonatomic, assign) NSInteger loginStatus;
@end// 觀察用戶登錄狀態變化
[self.user addObserver:self forKeyPath:@"loginStatus" options:NSKeyValueObservingOptionNew context:nil];// 實現觀察回調方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {if ([keyPath isEqualToString:@"loginStatus"]) {NSInteger newStatus = [change[NSKeyValueChangeNewKey] integerValue];if (newStatus == 1) {// 用戶已登錄,更新導航欄顯示self.navigationItem.title = @"歡迎回來";} else {// 用戶未登錄,更新導航欄顯示self.navigationItem.title = @"歡迎";}}
}
代碼邏輯的逐行解讀分析
  • [self.user addObserver:self forKeyPath:@"loginStatus" options:NSKeyValueObservingOptionNew context:nil]; 在用戶對象上注冊觀察者,監聽loginStatus屬性。
  • [change[NSKeyValueChangeNewKey] integerValue] 獲取屬性變化后的值。
  • if (newStatus == 1) 判斷用戶登錄狀態是否為已登錄,并根據狀態更新導航欄標題。

通過這樣的實踐,KVC和KVO不僅僅提供了數據綁定和屬性觀察的機制,同時也豐富了我們在處理動態數據交互時的編程策略和方法。

5. Blocks與閉包在objc中的實現與運用

5.1 Blocks的定義和閉包的基本概念

5.1.1 Blocks的語法和內存管理

Blocks是Objective-C中一種特殊的代碼塊,它能將一段代碼及其相關的狀態封裝起來,從而形成一個可以復用的功能塊。在Objective-C中,它通常被用來實現回調函數、操作列表、排序和異步執行等任務。

Blocks的語法使用了 ^ 符號來定義,它可以捕獲在代碼塊創建時外部變量的值,使得即使外部變量在Block創建后改變了,Block內依然可以使用這些變量的值。但這種捕獲可能會帶來內存管理方面的問題,特別是當捕獲的變量是引用類型時(如對象)。

void (^myBlock)(void) = ^{NSLog(@"Block內部可以訪問到外部的變量");
};// 執行Block
myBlock();

從上面的簡單例子中可以看到,Block在Objective-C中被定義為 void (^blockName)(void) 這樣的形式。當Block內部引用了外部的局部變量時,Block會創建這些變量的復制,并在內部使用這些復制的值。

關于內存管理,由于Block實際上是一個引用類型,所以當它被創建在一個自動釋放池中時,需要特別注意引用計數。例如,當Block被賦值給一個屬性,或者作為回調方法的參數傳遞時,可能需要對Block進行 copy 操作,以確保Block在適當的時候不被釋放。

5.1.2 閉包在objc中的定義和作用

閉包(Closure)是編程語言中一個可執行代碼塊的表達式,它能捕獲周圍狀態的值。在Objective-C中,Blocks可以被視為閉包的一種實現方式。閉包允許開發者在代碼中創建函數類型的實例,這些實例可以捕獲并存儲其定義時所在的作用域中變量的引用。這種特性使閉包非常適合實現回調、事件處理器、數據封裝等功能。

Objective-C中的閉包有以下幾個主要作用:

  • 封裝代碼 :將多行代碼封裝成一個單獨的代碼塊,可以在之后的程序執行中多次調用。
  • 參數傳遞 :可以像傳遞普通數據類型一樣傳遞代碼塊,實現高度的靈活性。
  • 訪問外部變量 :閉包可以捕獲其定義時作用域中的變量,并在執行時引用這些變量。

5.2 Blocks在objc中的高級用途

5.2.1 Blocks在回調和異步處理中的應用

在異步處理和回調機制中,Blocks提供了極大的便利性。由于Blocks可以捕獲并存儲作用域中的變量值,因此它在異步編程模型中可以用來簡化數據傳遞的流程。

比如,在網絡請求中,通常需要一個回調函數來處理請求成功或失敗的情況。使用Blocks可以將成功或失敗的處理邏輯寫在請求方法中,而不需要單獨定義回調函數:

NSURL *url = [NSURL URLWithString:@"http://example.com/data.json"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
__block NSError *error = nil;
__weak __typeof(self) weakSelf = self;[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {weakSelf.progressBlock(data); // 更新進度if (connectionError) {error = connectionError;} else {NSError *parseError = nil;id jsonObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&parseError];if (parseError) {error = parseError;} else {weakSelf.jsonBlock(jsonObject); // 成功處理數據}}if (error) {NSLog(@"請求錯誤:%@", error);}
}];

在上面的示例中, progressBlock jsonBlock 是Block類型的屬性,它們被用作異步請求完成后的回調處理。

5.2.2 利用Blocks實現數據封裝和函數式編程

由于Blocks提供了代碼封裝的便利性,它可以用來實現函數式編程中的某些特性,比如“高階函數”。在Objective-C中,可以使用Blocks作為參數或者返回值,實現對數據的封裝和函數的組合。

利用Blocks的這種能力,可以實現一些簡單的函數式編程技術。例如,可以使用Blocks作為參數來過濾數組:

NSArray *numbers = @[@1, @2, @3, @4, @5];
NSArray *evenNumbers = [numbers filteredArrayUsingBlock:^BOOL(id obj, NSUInteger idx, BOOL *stop) {return [obj isEqual:@([obj unsignedIntegerValue] % 2 == 0)];
}];

在這個例子中, filteredArrayUsingBlock: 方法使用了一個Block作為過濾條件,返回數組中所有偶數的數組。這種使用Blocks的方式使得代碼更加靈活且易于閱讀。

總的來說,Blocks在Objective-C中的應用不僅限于回調和異步處理,它們還提供了數據封裝和函數式編程的強大工具,使得Objective-C的編程風格更加現代化和靈活。在實際開發中,合理利用Blocks能顯著提高代碼的可維護性和執行效率。

6. 代理(Delegate)模式的變體與實例

6.1 代理模式的原理和objc中的實現

6.1.1 代理模式的基本思想

代理模式是一種常見的設計模式,用于表示一種行為的接口,使得其他對象可以在這個接口的約束下執行一些特定的操作。其核心思想是將某些操作委托給其他對象來執行,以保持代碼的松耦合和可擴展性。

在軟件設計中,代理模式經常被用于實現以下幾個目標:

  1. 控制對一個對象的訪問;
  2. 當對象的某些操作變得過于復雜時,簡化對象的使用;
  3. 當一個對象的生命周期需要被外部管理時。

6.1.2 在objc中實現代理模式的方法

在Objective-C中,代理模式是通過協議(Protocol)和委托(Delegate)屬性來實現的。協議定義了一組方法,類可以聲明它遵循這些方法,但不必實現它們。委托則是實現了這些協議的類的實例。

示例代碼塊
// 定義一個協議,包含代理方法
@protocol MyDelegate <NSObject>
- (void)delegateMethodToHandleAction:(NSString *)action;
@end// 類A實現了協議,作為代理
@interface ClassA : NSObject <MyDelegate>
@property (nonatomic, weak) id<MyDelegate> delegate;
@end@implementation ClassA- (void)performAction {// 假設發生了一個需要通知代理的事件[self.delegate delegateMethodToHandleAction:@"action"];
}@end// 類B遵循協議,并注冊為A的代理
@interface ClassB : NSObject <MyDelegate>
@end@implementation ClassB- (void)delegateMethodToHandleAction:(NSString *)action {NSLog(@"ClassB handled action: %@", action);
}@end// 使用時,創建A和B的實例,并將B設置為A的代理
ClassA *a = [[ClassA alloc] init];
ClassB *b = [[ClassB alloc] init];
a.delegate = b;// 調用方法,觸發代理方法
[a performAction];

在這個例子中, ClassA 需要執行某些操作時,它通過它的 delegate 屬性調用 delegateMethodToHandleAction: 方法。 ClassB 實現了這個協議,并被設置為 ClassA 的代理,從而響應代理消息。

6.2 探索代理模式的變體和擴展應用

6.2.1 多代理模式的實現和適用場景

在某些復雜的場景下,單一的代理可能不足以滿足需求。多代理模式允許多個對象同時作為代理,共同響應代理消息。這在需要多個對象協作處理同一個事件時非常有用。

示例代碼塊
// 多代理需要遵循協議的類實現可選的方法
@protocol MultiDelegate <NSObject>
@optional
- (void)optionalMethodForMultipleDelegates;
@end// 類C和D都遵循這個協議
@interface ClassC : NSObject <MultiDelegate>
@end@implementation ClassC- (void)optionalMethodForMultipleDelegates {NSLog(@"ClassC handled optional method");
}@end@interface ClassD : NSObject <MultiDelegate>
@end@implementation ClassD- (void)optionalMethodForMultipleDelegates {NSLog(@"ClassD handled optional method");
}@end// 類E可以擁有多個代理
@interface ClassE : NSObject
@property (nonatomic, weak) id<MultiDelegate> delegate1;
@property (nonatomic, weak) id<MultiDelegate> delegate2;
@end@implementation ClassE- (void)triggerMultipleDelegates {if ([self.delegate1 respondsToSelector:@selector(optionalMethodForMultipleDelegates)]) {[self.delegate1 optionalMethodForMultipleDelegates];}if ([self.delegate2 respondsToSelector:@selector(optionalMethodForMultipleDelegates)]) {[self.delegate2 optionalMethodForMultipleDelegates];}
}@end// 使用時,創建E的實例,并將C和D設置為E的多個代理
ClassE *e = [[ClassE alloc] init];
ClassC *c = [[ClassC alloc] init];
ClassD *d = [[ClassD alloc] init];
e.delegate1 = c;
e.delegate2 = d;// 調用方法,觸發多個代理
[e triggerMultipleDelegates];
6.2.2 委托模式與通知結合的設計思路

委托模式與通知模式結合可以創建更加靈活的設計,它允許對象在不直接知道對方的情況下進行通信。一個對象可以通知一個中間對象,而這個中間對象再轉發通知到其他監聽的代理對象。

示例代碼塊
// 使用NSNotificationCenter實現通知的發送和監聽
// 假設ClassF需要向其他對象發送通知
ClassF *f = [[ClassF alloc] init];// 注冊監聽者
[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(handleNotification:)name:@"MyNotification"object:f];// ClassF發送通知
[[NSNotificationCenter defaultCenter] postNotificationName:@"MyNotification"object:f];// 在監聽者對象中實現handleNotification:方法來響應通知
- (void)handleNotification:(NSNotification *)notification {NSLog(@"Received notification: %@", notification.name);
}// 別忘了在不需要監聽時移除監聽者
- (void)dealloc {[[NSNotificationCenter defaultCenter] removeObserver:self];
}

通過這種方式,類F可以通知其他對象進行操作,而這些對象并不需要直接引用類F。這種模式在需要解耦的對象間通信中非常有用。

7. objc中消息轉發機制與工廠方法的綜合應用

在Objective-C編程中,消息轉發機制和工廠方法是兩種重要的面向對象設計技術。它們在運行時動態地處理方法調用和對象的創建過程,從而提供更大的靈活性和擴展性。

7.1 消息轉發機制的深入理解和使用

7.1.1 消息轉發的工作原理

Objective-C的消息轉發機制允許對象有機會響應原本未定義的消息。當一個消息發送給對象,但該對象沒有實現相應的方法時,系統會按照一定順序嘗試解決這個問題:

  1. 動態方法解析:運行時首先調用對象的 +resolveInstanceMethod: +resolveClassMethod: 方法。開發者可以在這里動態添加方法實現。
  2. 快速轉發(Fast Forwarding):如果沒有方法被解析,運行時會調用對象的 forwardingTargetForSelector: 方法,允許開發者將消息轉發給另一個對象處理。

  3. 完整轉發(Full Forwarding):如果快速轉發沒有處理,運行時最后會調用對象的 methodSignatureForSelector: forwardInvocation: 方法。在 forwardInvocation: 中,開發者可以使用NSInvocation對象,封裝消息并進行更復雜的轉發。

7.1.2 如何利用消息轉發解決方法調用問題

消息轉發可以用來處理很多邊界情況,例如:

  • 動態代理:可以創建一個中介對象,負責轉發消息給實際處理者。
  • 模擬方法實現:當某些類的方法實現不可更改時,可以通過消息轉發提供額外的處理邏輯。
  • 抽象接口:定義抽象接口,并在運行時決定具體的實現類。

消息轉發不僅可以增加程序的靈活性,還可以作為編程時的一種設計模式,用于實現延遲加載、插件系統等功能。

7.2 工廠方法與分類結合的實例化模式

7.2.1 工廠方法在objc中的實現策略

工廠方法是一種創建型設計模式,它提供了一種創建對象的最佳方式。在Objective-C中,工廠方法通常使用類方法實現,并返回一個類的實例。結合分類(Category),可以在不修改原有類的情況下,為類添加工廠方法,實現具體的實例化邏輯。

一個工廠方法的實現步驟可能如下:

  1. 定義一個類方法,返回自定義類類型的實例。
  2. 在工廠方法中執行必要的初始化操作。
  3. 遵循單一職責原則,每個工廠方法負責創建一種類型的對象。

示例代碼:

@interface CustomClass : NSObject
+ (instancetype)customFactoryMethod;
@end@implementation CustomClass (Factory)+ (instancetype)customFactoryMethod {CustomClass *object = [[self alloc] init];// Perform any additional setup requiredreturn object;
}@end

7.2.2 結合分類實現更靈活的對象創建過程

分類可以用來增強已有類的功能。結合工廠方法,可以讓對象的創建過程更加靈活。例如,可以通過分類為某個類添加多個工廠方法,每個工廠方法對應不同的創建策略。

使用分類添加工廠方法的優點包括:

  • 代碼組織清晰:分類可以在邏輯上分離不同的創建策略。
  • 易于擴展:無需修改原有類的情況下,添加新的工廠方法。
  • 隱藏實現細節:客戶端代碼不需要知道對象的具體創建過程。
@interface CustomClass (FactoryExtension)+ (instancetype)customFactoryMethodWithParameter:(NSString *)parameter;@end@implementation CustomClass (FactoryExtension)+ (instancetype)customFactoryMethodWithParameter:(NSString *)parameter {CustomClass *object = [[self alloc] init];// Use the parameter to configure the objectreturn object;
}@end

7.3 利用Category實現線程安全的單例和其他高級技巧

7.3.1 Category在線程安全單例中的應用

利用分類實現線程安全的單例模式是一種常見的技巧。通過分類,可以將單例的實現封裝起來,同時保證線程安全。Objective-C運行時提供了 dispatch_once 函數,這是實現線程安全單例的推薦方式。

示例代碼:

@implementation SingletonClass (Singleton)static SingletonClass *_instance = nil;+ (instancetype)sharedInstance {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{_instance = [[self alloc] init];});return _instance;
}@end

7.3.2 Category實現分類的分類以及其它高級特性

分類的分類(Category of Category),是一種高級技巧,可以為一個已有的分類添加新的方法。這是Objective-C語言的特性之一,允許開發者在不修改原有類定義的情況下,為分類繼續增加方法。

示例代碼:

// 假設已有的分類
@interface SomeClass (SomeCategory)
- (void現有的方法);
@end// 現在想為這個分類增加新的方法
@interface SomeClass (SomeCategory) (MoreMethods)
- (void新增方法);
@end@implementation SomeClass (SomeCategory) (MoreMethods)
- (void新增方法) {// 新增方法的實現
}
@end

這種方法可以在類庫的維護和更新中非常有用,特別是對于第三方庫的擴展。

通過上述章節的介紹和示例代碼,我們展示了Objective-C中消息轉發機制、工廠方法以及Category的高級應用技巧,以及它們在實際編程中的應用。在接下來的章節中,我們將進一步探索如何利用這些技術解決實際開發中的問題。

本文還有配套的精品資源,點擊獲取 menu-r.4af5f7ec.gif

簡介:Objective-C的設計模式不僅僅局限于經典模式,還可以利用其動態特性實現一些非傳統的模式。本文介紹了一系列基于Objective-C動態特性的設計模式,包括使用協議代替類繼承、通過分類擴展類功能、利用KVC和KVO實現屬性訪問與觀察、使用Blocks作為閉包實現回調和并發、代理模式的變體、消息轉發機制、以及利用工廠方法、分類和Category實現單例、分類的分類、私有方法的實現等。這些設計模式提高了代碼的靈活性和可維護性,并在實際開發中發揮重要作用。


本文還有配套的精品資源,點擊獲取
menu-r.4af5f7ec.gif

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/92105.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/92105.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/92105.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【筆記】重學單片機(51)(下)

中斷系統 正常運行過程中&#xff0c;被打斷進行另外工作&#xff0c;結束后回到原有進程。 5個中斷源 外部中斷源&#xff08;2個&#xff09;&#xff1a;INT0——由P3.2端口線引入&#xff0c;低電平或下降沿引起。INT1——由P3.3端口線引入&#xff0c;低電平或下降沿引起。…

Go實現程序啟動器進而實現隱藏真實內容

注意&#xff1a; 本文內容于 2025-08-03 01:10:35 創建&#xff0c;可能不會在此平臺上進行更新。如果您希望查看最新版本或更多相關內容&#xff0c;請訪問原文地址&#xff1a;Go實現程序啟動器進而實現隱藏真實內容。感謝您的關注與支持&#xff01; 突發奇想&#xff0c;…

Fiddler 中文版怎么用 實現接口抓包調試與前后端聯調閉環

API調試在現代開發流程中的地位愈發重要&#xff1a;接口數量激增、請求邏輯復雜、數據結構多變、安全校驗機制加嚴……一個小小的參數錯誤、一次隱蔽的跨域問題、一個環境配置疏漏&#xff0c;都可能導致長時間的排查成本。而擁有一款既強大又易用的調試工具&#xff0c;尤其是…

ollama 多實例部署

如果我們需要在一臺服務器上使用多個ollama服務&#xff0c;那么我們需要進行將ollama前端和ollama后端對應連接的操作&#xff0c;否則就會出現如下場景&#xff1a;我們可以在當前端口設置&#xff0c;這句話就是指明當前ollama實例使用哪個后端進行請求&#xff1a;export O…

orchestrator部署

場景&#xff1a; 用于管理MySQL高可用 下載jq包 每臺orchestrator集群機器上都進行下載。 # wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm # rpm -ivh epel-release-latest-7.noarch.rpm # yum repolist ###檢查是否已經添加到源列表 # yum i…

CentOS 6.4 上安裝 Oracle 10.2.0.1 并升級到 10.2.0.4

目錄 一、系統檢查與設置 1. 檢查系統版本與磁盤空間 2. 修改系統參數 3. 創建組和用戶 4. 設置主機名 5. 檢查安裝軟件包 6. 設置 oracle 用戶環境變量 二、安裝 Oracle 軟件包 1. 安裝 10.2.0.1 安裝包 2. 安裝 10.2.0.4 補丁 三、建庫 四、配置監聽器 1. 編輯配…

【基于C# + HALCON的工業視系統開發實戰】二十六、車規級PCB全自動質檢:3D SPI+AI光學檢測融合方案

摘要&#xff1a;本文詳細闡述基于C# .NET Core 6與HALCON 24.11開發的車規級PCB板AOI智能檢測系統&#xff0c;提出3D SPI與AI光學檢測融合方案。系統通過結構光3D測量技術實現錫膏印刷質量檢測&#xff0c;結合多算法融合的自動光學檢測完成元件缺陷識別&#xff0c;構建SPI與…

Go源碼解讀——互斥鎖與讀寫鎖

互斥鎖Mutextype Mutex struct {// 表示互斥鎖狀態state int32// 表示信號量&#xff0c;協程阻塞等待該信號量&#xff0c;解鎖的協程釋放信號量從而喚醒等待信號量的協程sema uint32 }Locked: 表示該Mutex是否已被鎖定&#xff0c;0&#xff1a;沒有鎖定 1&#xff1a;已被鎖…

Linux(centos)安全狗

sdui進入操作頁面 [rootlocalhost safedog_an_linux64_2.8.32947]# sdui維護 查看、啟動或停止服務。 [rootiZbp1f0xuq9rc41s6gdvfyZ /]# systemctl status safedog [rootiZbp1f0xuq9rc41s6gdvfyZ /]# systemctl start safedog [rootiZbp1f0xuq9rc41s6gdvfyZ /]# systemct…

ES9 / ES2018 正則表達式增強

? 一、命名捕獲組&#xff08;Named Capture Groups&#xff09;給捕獲結果起名字&#xff0c;更易讀、更易維護。&#x1f539; 傳統寫法&#xff08;位置識別&#xff09;&#xff1a;const result /(\d{4})-(\d{2})-(\d{2})/.exec("2025-07-31"); console.log(…

深入Java開發:Token的全方位解析與實戰指南(下)

深入Java開發&#xff1a;Token的全方位解析與實戰指南&#xff08;下&#xff09; 上一篇 深入Java開發&#xff1a;Token的全方位解析與實戰指南&#xff08;上&#xff09; 五、Token 的生命周期與管理 5.1 Token 的生命周期狀態 Token 的生命周期涵蓋了從創建到最終失效…

第二十四天(數據結構:棧和隊列)隊列實踐請看下一篇

棧和隊列棧 &#xff1a; 是限定在表尾進行插入和刪除操作的線性表實現是一回事&#xff0c;但是必須要滿足棧的基本特點它的設計思路是:先進后出&#xff0c;后進先出棧有兩端1 棧頂(top) &#xff1a;插入數據刪除數據都只能在這一端訪問也只能訪問棧頂2 棧底(bottom) : 棧底…

三、Spark 運行環境部署:全面掌握四種核心模式

作者&#xff1a;IvanCodes 日期&#xff1a;2025年7月25日 專欄&#xff1a;Spark教程 Apache Spark 作為統一的大數據分析引擎&#xff0c;以其高性能和靈活性著稱。要充分利用Spark的強大能力&#xff0c;首先需要根據不同的應用場景和資源環境&#xff0c;正確地部署其運行…

【Django】-2- 處理HTTP請求

一、request 請求 先理解&#xff1a;Request 是啥&#xff1f;用戶訪問你的網站時&#xff0c;會發一個 “請求包” &#x1f4e6; &#xff0c;里面裝著&#xff1a;想訪問啥路徑&#xff1f;用啥方法&#xff08;GET/POST 等&#xff09;&#xff1f;帶了啥頭信息&#xff0…

飛算 JavaAI:突破效率邊界的代碼智能構造平臺

飛算 JavaAI&#xff1a;突破效率邊界的代碼智能構造平臺 一、引言&#xff1a;數字化浪潮下的開發效率困局與破局路徑 當企業數字化轉型駛入深水區&#xff0c;軟件開發正面臨需求迭代頻次激增、人力成本高企、技術架構復雜化的多重挑戰。傳統開發模式中&#xff0c;從需求分…

國家科學技術獎答辯PPT案例_科技進步獎ppt制作_技術發明獎ppt設計美化_自然科學獎ppt模板 | WordinPPT

“國家科學技術獎”是在科學技術領域設立的最高榮譽&#xff0c;旨在獎勵在科學技術進步活動中做出突出貢獻的個人和組織&#xff0c;從而推動國家科學技術事業的發展&#xff0c;加快建設科技強國。科學技術獎是國內科技界的最高殿堂&#xff0c;是對做出杰出貢獻的科技工作者…

如何通過黑白棋盤進行定位配準融合?(前后安裝的兩個相機)

一.總結: 完整流程 &#xff1a;硬件準備 → 數據采集 → 空間統一 → 相機標定&#xff08;內參畸變&#xff09; → 外參求解 → 定位配準融合 → 校驗 → 生成映射表 → 上線remap驗證 我們場景流程 &#xff1a;硬件準備 → 數據采集 → 空間統一 → 定位配準融合 → …

【node】token的生成與解析配置

在用戶登錄成功之后為了記錄用戶的登錄狀態通常會將用戶信息編寫為一個token&#xff0c;通過解析token判斷用戶是否登錄。 token的生成 JSON Web Token&#xff08;JWT&#xff09; 是一種基于JSON的輕量級身份驗證和授權機制。它是一種開放標準&#xff08;RFC 7519&#xff…

yolo 、Pytorch (5)IOU

一、簡介 IOU的全稱為交并比&#xff08;Intersection over Union&#xff09;&#xff0c;是目標檢測中使用的一個概念&#xff0c;IoU計算的是“預測的邊框”和“真實的邊框”的交疊率&#xff0c;即它們的交集和并集的比值。最理想情況是完全重疊&#xff0c;即比值為1。 …

【銀河麒麟服務器系統】自定義ISO鏡像更新內核版本

自定義ISO鏡像更新內核版本 鏡像制作流程 環境 更新倉庫 準備新版本內核包 內核清單簡介 已下載軟件包版本 更新內核包 更新鏡像源 制作自動化鏡像 修改引導 修改UEFI引導 傳統引導 修改ks文件內容 打包鏡像 mkisofs參數說明 封裝鏡像命令 常見問題解決方案 鏡像制作流程 #merm…