runtime 給類別添加屬性淺析
很多時(shí)候因?yàn)樾枨笙胫o一個(gè)類添加屬性,就是給一個(gè)類添加成員變量了,這樣子方便了用這個(gè)類的時(shí)候响巢,有了自己添加的屬性盗冷,做什么事都是 信手捏來了均澳。
源碼
#import <Foundation/Foundation.h>
#import <objc/runtime.h> //千萬別忘記添加哦
@interfaceNSObject(FY)
@property(nonatomic,copy)NSString* name;//像平時(shí)一樣的添加屬性
@end
下面是在.m中實(shí)現(xiàn)的
staticvoid* FYKeyName = (void*)"FYKeyName";//聲明這個(gè)變量要存儲(chǔ)的key的名字
@implementationNSObject(FY)
- (void)setName:(NSString*)name{
objc_setAssociatedObject(self, FYKeyName, name, OBJC_ASSOCIATION_COPY);//把這個(gè)值存儲(chǔ)起來類型是copy曲掰,值是name蛔琅,存儲(chǔ)的鍵值是"FYKeyName",存儲(chǔ)到self的屬性里面
}
- (NSString*)name{
returnobjc_getAssociatedObject(self, FYKeyName);//獲取self的key為FYKeyName的值
}
@end
到此為止這個(gè)屬性已經(jīng)添加完成了胎许。
其實(shí)為毛添加屬性啊,我們公司的按鈕不能連續(xù)點(diǎn)擊罗售,是所有按鈕辜窑。。寨躁。沒錯(cuò)是all not some穆碎。我問Google大神了,搜到了消息是runtime解決問題职恳,但是沒找到如何解決所禀。在我努力尋找方面。。色徘。恭金。一萬字。褂策。
終于知道runtime是運(yùn)行時(shí)横腿,什么是運(yùn)行時(shí)呢?就是我們寫的OC代碼會(huì)讓runtime翻譯并且執(zhí)行斤寂,runtime是一套比較底層的純C語言API, 屬于1個(gè)C語言庫, 包含了很多底層的C語言API耿焊。
在我們平時(shí)編寫的OC代碼中, 程序運(yùn)行過程時(shí), 其實(shí)最終都是轉(zhuǎn)成了runtime的C語言代碼, runtime算是OC的幕后工作者。
所以給類添加屬性就派上用場(chǎng)了扬蕊,我解決思路是這樣子的搀别,給按鈕添加類別就是點(diǎn)擊事件間隔,執(zhí)行點(diǎn)擊事件的時(shí)候判斷一下是否時(shí)間到了尾抑,如果時(shí)間不到歇父,那么攔截點(diǎn)擊事件。
怎么攔截點(diǎn)擊事件呢再愈?
其實(shí)點(diǎn)擊事件在runtime里面是obj發(fā)送消息榜苫,我們可以把要發(fā)送的消息的SEL 和自己寫的SEL交換一下,然后在自己寫的SEL里面判斷是否執(zhí)行點(diǎn)擊事件翎冲〈共牵【有點(diǎn)繞】
代碼:
#import
#import
@interfaceUIControl(FY)
@property(nonatomic,assign)NSTimeIntervalacceptEventInterval;
@property(nonatomic)BOOLignoreEvent;
@end
@implementationUIControl(FYControl)
staticconstchar*UIControl_acceptEventInterval="UIControl_acceptEventInterval";
staticconstchar*UIControl_ignoreEvent="UIControl_ignoreEvent";
@end
@implementationUIControl(FY)
- (void)setAcceptEventInterval:(NSTimeInterval)acceptEventInterval
{
objc_setAssociatedObject(self,UIControl_acceptEventInterval, @(acceptEventInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSTimeInterval)acceptEventInterval {
return[objc_getAssociatedObject(self,UIControl_acceptEventInterval) doubleValue];
}
-(void)setIgnoreEvent:(BOOL)ignoreEvent{
objc_setAssociatedObject(self,UIControl_ignoreEvent, @(ignoreEvent), OBJC_ASSOCIATION_ASSIGN);
}
-(BOOL)ignoreEvent{
return[objc_getAssociatedObject(self,UIControl_ignoreEvent) boolValue];
}
+(void)load {
Method a = class_getInstanceMethod(self,@selector(sendAction:to:forEvent:));
Method b = class_getInstanceMethod(self,@selector(_sendAction:to:forEvent:));
method_exchangeImplementations(a, b);//交換方法
}
- (void)_sendAction:(SEL)action to:(id)target forEvent:(UIEvent*)event
{
if(self.ignoreEvent)return;
if(self.acceptEventInterval>0)
{
self.ignoreEvent=YES;
[selfperformSelector:@selector(setIgnoreEventWithNo) withObject:nilafterDelay:self.acceptEventInterval];
}
[self_sendAction:action to:target forEvent:event];
}
-(void)setIgnoreEventWithNo{
self.ignoreEvent=NO;
}
@end
用的時(shí)候很好用的
-(void)click{
btn =[[UIButton alloc]initWithFrame:CGRectMake(100,100,100,40)];
[btnsetTitle:@"btn"forState:UIControlStateNormal];
[btnsetTitleColor:[UIColor redColor]forState:UIControlStateNormal];
btn.touchTimeValue =3;
[self.viewaddSubview:btn];
[btnaddTarget:selfaction:@selector(objcName)forControlEvents:UIControlEventTouchUpInside];
}
輸出:2016-03-1713:14:20.365runTimeObj[9297:2669428] 測(cè)試
2016-03-1713:14:23.717runTimeObj[9297:2669428] 測(cè)試
2016-03-1713:14:26.876runTimeObj[9297:2669428] 測(cè)試
這個(gè)例子是利用了兩個(gè)參數(shù),一個(gè)參數(shù)Bool判斷是否往下執(zhí)行抗悍,一個(gè)時(shí)間用來修改Bool的值驹饺,最后就是執(zhí)行方法b。有些同學(xué)納悶缴渊,這執(zhí)行方法b赏壹,不是執(zhí)行自身方法嗎?難道不是遞歸衔沼?其實(shí)不是蝌借,在load函數(shù)里面已經(jīng)把a(bǔ),b方法交換了指蚁。
這樣子就可以操作一些系統(tǒng)方法了菩佑。后續(xù)還會(huì)出runtime在項(xiàng)目中的實(shí)際應(yīng)用。
轉(zhuǎn)自:http://fgyong.cn/2016/03/17/iOS%E9%AB%98%E7%BA%A7%E5%BC%80%E5%8F%91runtime%E9%82%A3%E7%82%B9%E4%BA%8B%E5%AE%9E%E6%88%98(1)/