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

Objective-C Category 實用模式全解析

     編輯:關於C語言

Category 機制速覽

Category(分類)允許在**不繼承、不修改原始碼**的情況下,為現有類別**新增方法**。編譯器將分類方法合併至類別的方法列表,運行時無差別調用。主要用途:

  1. 分散大型類別實作到多檔案(團隊協作)。
  2. 為系統/第三方類別擴充功能(如 NSString+Utils)。
  3. 實現「非正式協議」與私有方法宣告。

模式一:屬性存取控制(私有可寫、公開唯讀)

利用 **Class Extension (匿名分類)** 在 .m 檔重新宣告屬性為 readwrite,對外僅暴露 readonly。

Things.h (公開介面)

@interface Things : NSObject
@property (assign) NSInteger thing1;
@property (readonly, assign) NSInteger thing2; // 唯讀
- (void)resetAllValue;
@end

Things.m (實作與私有擴充)

@interface Things ()  // Class Extension
@property (assign) NSInteger thing3;          // 完全私有
@property (readwrite, assign) NSInteger thing2; // 內部可寫
@end

@implementation Things
@synthesize thing1, thing2, thing3;

- (void)resetAllValue {
    self.thing1 = 1;
    self.thing2 = 2;  // 內部可寫
    self.thing3 = 3;
}

- (NSString *)description {
    return [NSString stringWithFormat:@"thing1=%ld, thing2=%ld, thing3=%ld",
            self.thing1, self.thing2, self.thing3];
}
@end

模式二:大型類別拆檔(多人協作)

將單一巨型類別的方法按功能領域拆分到多個 CategoryName.m,編譯時自動合併。

CategoryThing.h

@interface CategoryThing : NSObject {
    NSInteger thing1, thing2, thing3;
}
@end

// 分類宣告(僅方法,無實例變數)
@interface CategoryThing (Thing1)
- (void)setThing1:(NSInteger)v;
- (NSInteger)thing1;
@end

@interface CategoryThing (Thing2)
- (void)setThing2:(NSInteger)v;
- (NSInteger)thing2;
@end

@interface CategoryThing (Thing3)
- (void)setThing3:(NSInteger)v;
- (NSInteger)thing3;
@end

Thing1.m

@implementation CategoryThing (Thing1)
- (void)setThing1:(NSInteger)v { thing1 = v; }
- (NSInteger)thing1 { return thing1; }
@end

Thing2.m、Thing3.m 同理。注意:分類**不能新增實例變數**,上例中 thing1/2/3 必須在主介面 @interface CategoryThing : NSObject { ... } 宣告。

模式三:系統類別功能擴充(最常見)

為 NSString 新增 lengthAsNumber 方法,回傳長度的 NSNumber。

NSString+NumberConversion.h

@interface NSString (NumberConversion)
- (NSNumber *)lengthAsNumber;
@end

NSString+NumberConversion.m

@implementation NSString (NumberConversion)
- (NSNumber *)lengthAsNumber {
    NSUInteger len = [self length];
    return [NSNumber numberWithUnsignedInteger:len];
}
@end

使用

#import "NSString+NumberConversion.h"
NSNumber *n = @"Hello".lengthAsNumber; // n.integerValue == 5

進階技巧與坑點

主題說明
關聯物件分類無法加 ivar,但可用 objc_setAssociatedObject/objc_getAssociatedObject 綁定任意物件,實現「分類擁有狀態」。
方法覆蓋風險若多個分類實作同名方法,**編譯順序決定勝負**,行為不可預測。**嚴禁**在分類中覆蓋主類別或其他分類的方法。
載入時機分類在 dyld 載入映像時自動註冊,+load 會被調用,適合執行初始化邏輯。
命名慣例檔名 ClassName+Feature.h/m,分類名 (Feature),方法前綴加獨特標識(如 xyz_)避免衝突。
Swift 互操作Swift 無法直接使用 Objective-C 分類方法,需暴露為 extension 或封裝為獨立函數。

關聯物件範例:為 UIView 新增 tagObject

@interface UIView (TagObject)
@property (nonatomic, strong) id tagObject;
@end

@implementation UIView (TagObject)
static const void *TagKey = &TagKey;

- (void)setTagObject:(id)obj {
    objc_setAssociatedObject(self, TagKey, obj, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id)tagObject {
    return objc_getAssociatedObject(self, TagKey);
}
@end

Category 是 Objective-C 動態特性的精華,善用它能讓程式碼結構清晰、擴充彈性、團隊協作高效。牢記「只加方法、不加 ivar、不覆蓋」三原則,即可安享其利。

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