首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

Objective-C 類別擴展與協議完整指南:Extension vs Category vs Protocol

     編輯:關於C語言

一、類別擴展:為已知類別新增私有介面

定義於 .m 檔案頂部的 @interface ClassName () 區塊,編譯期可見,執行期合併到主類別。

核心特性

  • 可新增 實例變數(需配合 @property 產生 _ivar)
  • 可宣告 私有方法(不在 .h 公開)
  • 可宣告 私有屬性
  • 必須在 @implementation 中實作所有宣告方法,否則編譯警告
// MyClass.m
#import "MyClass.h"

@interface MyClass () // Class Extension
@property (nonatomic, strong) NSString *privateToken;
- (void)internalHelper;
@end

@implementation MyClass
- (void)internalHelper { /* 實作 */ }
@end

二、分類:為無原始碼類別新增方法

建立 ClassName+CategoryName.h/.m,編譯期獨立,執行期動態合併。

核心限制

  • 不可新增實例變數(無法改變類別佈局)
  • 可新增實例方法、類別方法、協議遵循、屬性(但屬性需手動實作 getter/setter 或用 Associated Objects)
  • 方法名稱衝突時行為未定義(最後編譯的勝出),建議加前綴 xx_myMethod
// NSString+Utils.h
@interface NSString (Utils)
- (BOOL)xx_isValidEmail;
@end

// NSString+Utils.m
@implementation NSString (Utils)
- (BOOL)xx_isValidEmail { /* 正則實作 */ return YES; }
@end

三、Extension vs Category vs Subclass 對比

特性ExtensionCategorySubclass
需原始碼是否否
可加實例變數是否 (用 Associated Objects 替代)是
方法成對象一部分是是否 (僅子類別擁有)
可繼承隨主類別隨主類別是
適用場景私有介面、框架內部系統類別擴充、模組化功能行為擴充、多態替換

四、協議:定義介面契約

協議宣告一組方法簽名,類別宣稱遵循即承諾實作。支援 @required (預設) 與 @optional。

@protocol NetworkDelegate 
@required
- (void)requestDidFinish:(id)response;
@optional
- (void)requestDidFail:(NSError *)error;
- (void)requestProgress:(float)progress;
@end

// 遵循協議
@interface MyClient : NSObject 
@end

@implementation MyClient
- (void)requestDidFinish:(id)response { /* 必須實作 */ }
- (void)requestDidFail:(NSError *)error { /* 選擇實作 */ }
// 未實作 progress 也合法
@end

五、代理模式:協議的經典應用

「自己不想做的事交給別人做」,解耦發送者與處理者。

// 協議定義
@protocol TaskDelegate 
- (void)taskDidComplete:(NSString *)result;
@end

// 發送者
@interface Worker : NSObject
@property (nonatomic, weak) id delegate;
- (void)startWork;
@end

@implementation Worker
- (void)startWork {
    // 耗時操作...
    if ([self.delegate respondsToSelector:@selector(taskDidComplete:)]) {
        [self.delegate taskDidComplete:@"Success"];
    }
}
@end

// 接收者 (ViewController)
@interface ViewController () 
@property (nonatomic, strong) Worker *worker;
@end

@implementation ViewController
- (void)viewDidLoad {
    self.worker = [Worker new];
    self.worker.delegate = self; // 設定代理
    [self.worker startWork];
}

- (void)taskDidComplete:(NSString *)result {
    NSLog(@"收到結果: %@", result);
}
@end

關鍵點

  • 代理屬性 必須用 weak 避免循環保留。
  • 呼叫前用 respondsToSelector: 檢查選擇性方法是否實作。
  • 協議繼承 NSObject 可讓 id 直接呼叫 respondsToSelector: 等方法。

六、Block 替代代理的現代寫法

iOS 4+ 推薦用 Block 簡化單一回呼場景:

typedef void(^CompletionBlock)(NSString *result, NSError *error);

@interface Worker : NSObject
- (void)startWorkWithCompletion:(CompletionBlock)completion;
@end

@implementation Worker
- (void)startWorkWithCompletion:(CompletionBlock)completion {
    dispatch_async(dispatch_get_global_queue(0,0), ^{
        // 工作...
        dispatch_async(dispatch_get_main_queue(), ^{
            if (completion) completion(@"Success", nil);
        });
    });
}
@end

// 使用時注意循環保留
__weak typeof(self) weakSelf = self;
[worker startWorkWithCompletion:^(NSString *result, NSError *error) {
    typeof(self) strongSelf = weakSelf;
    if (strongSelf) { strongSelf.label.text = result; }
}];

七、總結

  • Extension:內部私有介面首選,可加 ivar。
  • Category:擴充系統/第三方類別功能,不可加 ivar,注意命名衝突。
  • Protocol:定義介面契約,實現代理模式,weak 代理屬性防循環。
  • 現代開發:單一回呼優先用 Block,多回呼/長期關係用 Delegate+Protocol。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved