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

Objective-C Category 機制深度解析:擴充系統類別的最佳實務

     編輯:關於C

什麼是 Category?

Category(分類) 是 Objective-C 獨有的語言特性,允許在不繼承、不修改原始碼的前提下,為既有類別(含系統框架類別如 NSString、NSArray)動態新增方法。它實現了「開放-封閉原則」:對擴充開放,對修改封閉。

Category vs 繼承:核心差異

維度Category繼承
能否新增實例變數(Ivar)❌ 無法(僅能用關聯物件模擬)✅ 可自由新增
能否覆寫既有方法⚠️ 可行但極度不建議(會遮蔽原實作,且無法呼叫 super)✅ 正規覆寫,可呼叫 super
編譯單元分離✅ 同一類別可拆分多個 .h/.m,利於團隊協作❌ 子類別通常集中在單一檔案
命名空間隔離✅ 可用 Private 分類實現「檔案級私有方法」❌ 子類別方法皆公開

命名慣例與檔案組織

// 擴充 NSString 加入字串反轉功能
// 檔名:NSString+ReverseString.h / .m

// NSString+ReverseString.h
#import 

@interface NSString (ReverseString)
- (NSString *)reversedString;
@end

// NSString+ReverseString.m
#import "NSString+ReverseString.h"

@implementation NSString (ReverseString)
- (NSString *)reversedString {
    NSUInteger len = self.length;
    unichar *buffer = malloc(len * sizeof(unichar));
    [self getCharacters:buffer range:NSMakeRange(0, len)];
    for (NSUInteger i = 0; i < len / 2; i++) {
        unichar tmp = buffer[i];
        buffer[i] = buffer[len - 1 - i];
        buffer[len - 1 - i] = tmp;
    }
    NSString *result = [NSString stringWithCharacters:buffer length:len];
    free(buffer);
    return result;
}
@end

進階用法:模擬私有方法與關聯物件

1. 檔案級私有方法

將分類宣告與實作直接寫在 .m 檔案頂部,外部不可見:

// Foo.m
@interface Foo (Private)
- (void)internalHelper;
@end

@implementation Foo (Private)
- (void)internalHelper { NSLog(@"內部輔助方法"); }
@end

@implementation Foo
- (void)publicMethod { [self internalHelper]; }
@end

2. 關聯物件擴充狀態

雖然 Category 不能加 Ivar,但可用 objc_setAssociatedObject 綁定額外資料:

// UIView+TagExtension.m
#import 
static const char kAssociatedTagKey;

@implementation UIView (TagExtension)
- (void)setExtendedTag:(id)tag {
    objc_setAssociatedObject(self, &kAssociatedTagKey, tag, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id)extendedTag {
    return objc_getAssociatedObject(self, &kAssociatedTagKey);
}
@end

常見陷阱與最佳實務

  1. 方法名稱衝突:多個 Category 定義同名方法時,載入順序決定勝出者,行為不可預期。建議加前綴,如 xyz_reversedString。
  2. 無法呼叫被覆寫的原始實作:Category 覆寫系統方法會導致原實作永久不可及,除非用 Method Swizzling(進階技巧,慎用)。
  3. 分類載入時機:所有 Category 在 App 啟動時由 Runtime 一次性載入,順序不保證。
  4. 框架開發:公開庫請將 Category 方法標註為 FOUNDATION_EXPORT 或在模組映射中公開。

總結

Category 是 Objective-C 實現「組合優於繼承」的利器。善用它可:

  • 為系統類別補齊缺失功能(如 NSString 加密、UIColor 十六進位初始化)。
  • 將龐大類別拆分為職責單一的分類檔案(如 ViewController+Networking、ViewController+UILayout)。
  • 以 Private 分類替代 C++ private 關鍵字,實現編譯期可見性控制。

記住核心限制:只能加方法,不能加 Ivar;若需狀態,請改用關聯物件或繼承。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved