iOS使用Category新增@property變數

weixin_33866037發表於2016-03-30

本文csdn地址:http://blog.csdn.net/game3108/article/details/51147941

由於Objective-C的動態語言特性,可以動態的建立類,新增屬性和方法。

Class demoClass = objc_allocateClassPair([NSObject class], "TestDemo", 0);  
class_addMethod(demoClass, @selector(intro), (IMP)&selfIntro, "v@:");  
class_addIvar(demoClass,"myVar", sizeof(id), 0, "@");   
objc_registerClassPair(demoClass); 

其中就有一個class_addIvar可以動態新增變數。但class_addIvar只能在動態建立類的時候增加變數,定義類是靜態建立的類則無法新增。

而Category只能新增方法,使用 @property 也是隻會生成setter和getter方法的宣告。具體原因請參考這篇文章,這文章詳細解釋了Category的實現,為什麼可以動態新增方法,和不能新增例項變數的原因,這裡也不多介紹了。

那如果確實想給Category增加一個@property的變數,應該如何去實現?
比如如下標頭檔案:

//
//  UIView+Associate.h
//  TouchPalDialer
//
//  Created by game3108 on 16/3/30.
//
//

#import <UIKit/UIKit.h>

@interface UIView (Associate)

@property (nonatomic, assign) NSInteger associateLength;

@end

首先,先要了解
@property的本質其實是 ivar(例項變數)+getter+setter
那既然如此,重寫getter和setter方法,並且增加一個ivar的變數,就可以實現@property的功能

對於重寫getter和setter方法,可以用如下方式

//
//  UIView+Associate.m
//  TouchPalDialer
//
//  Created by game3108 on 16/3/30.
//
//

#import "UIView+Associate.h"

@implementation UIView (Associate)

@dynamic associateLength;

- (NSInteger) associateLength{
    NSLog(@"associate get");
    return 0;
}

- (void) setAssociateLength:(NSInteger)associateLength{
    NSLog(@"associate length : %d" , associateLength);
}

@end

但重寫getter和setter方法還是不夠,必須要建立一個例項變數,這樣,就用到了OC runtime動態繫結變數的方法:

OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_1);

OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_1);

這樣可以動態建立一個ivar的例項變數使用,如下:

//
//  UIView+Associate.m
//  TouchPalDialer
//
//  Created by game3108 on 16/3/30.
//
//

#import "UIView+Associate.h"
#import <objc/runtime.h>

@implementation UIView (Associate)

@dynamic associateLength;

static char associateLengthKey;

- (NSInteger) associateLength{
    return [(NSNumber *)objc_getAssociatedObject(self, &associateLengthKey) integerValue];
}

- (void) setAssociateLength:(NSInteger)associateLength{
    objc_setAssociatedObject(self, &associateLengthKey, @(associateLength), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end

測試程式碼

UIView *testView = [[UIView alloc]init];
NSLog(@"test number: %d", testView.associateLength);
testView.associateLength = 20;
NSLog(@"test number: %d", testView.associateLength);

輸出結果
test number: 0 test number: 20

參考連結

1.刨根問底Objective-C Runtime(3)- 訊息 和 Category
2.Runtime-動態建立類新增屬性和方法
3.stackoverflow:objective-c-add-property-in-runtime

相關文章