runtime是OC比較底層的東西痹束,而我們?cè)趯W(xué)OC的時(shí)候很容易忽視r(shí)untime的學(xué)習(xí),但是runtime的熟悉還是很有必要的讶请,他可以使你更了解底層的封裝祷嘶,從而對(duì)OC的理解更加深入(比如成員變量的本質(zhì)就是一個(gè)結(jié)構(gòu)體)
1.關(guān)于成員變量
首先建一個(gè)類屎媳,加入叫Person,在類下面導(dǎo)入runtime框架
#import <objc/runtime.h>
在這里首先介紹下runtime關(guān)于成員的相關(guān)屬性
Ivar *class_copyIvarList(Class cls, unsigned int *outCount) //獲取所有成員變量
const char *ivar_getName(Ivar v) //獲取某個(gè)成員變量的名字
const char *ivar_getTypeEncoding(Ivar v) //獲取某個(gè)成員變量的類型編碼
Ivar class_getInstanceVariable(Class cls, const char *name) //獲取某個(gè)類中指定名稱的成員變量
id object_getIvar(id obj, Ivar ivar) //獲取某個(gè)對(duì)象中的某個(gè)成員變量的值
void object_setIvar(id obj, Ivar ivar, id value) //設(shè)置某個(gè)對(duì)象的某個(gè)成員變量的值
我們來(lái)操作一下
首先創(chuàng)建成員變量
@property(nonatomic,strong)NSString * name;
@property(nonatomic,strong)NSString * gender;
@property(nonatomic,assign)NSNumber* age;
@property(nonatomic,assign)NSInteger height;
①利用runtime得到成員變量的屬性
-(NSString*)description
{
unsigned int outCount;
//獲取所有的成員變量
//class 要獲取的某個(gè)類名论巍,outCount:通過(guò)這一個(gè)函數(shù)執(zhí)行之后將成員變量的個(gè)數(shù)賦值到此
Ivar *ivarList = class_copyIvarList([Person class], &outCount);
for (NSInteger i = 0; i < outCount; i++) {
//每次獲取一個(gè)成員變量
Ivar ivar = ivarList[i];
//打印成員變量的名字和編碼類型
NSLog(@"name = %s,type = %s",ivar_getName(ivar),ivar_getTypeEncoding(ivar));
}
return nil;
}
②利用runtime給成員變量賦值
首先在Person.h文件定義一個(gè)方法
+ (Person *)personWithName:(NSString *)name gender:(NSString *)gender age:(NSNumber *)age height:(NSInteger)height;
在Person.m文件實(shí)現(xiàn)
+ (Person *)personWithName:(NSString *)name gender:(NSString *)gender age:(NSNumber *)age height:(NSInteger)height
{
Person *person = [Person new];
unsigned int outCount;
Ivar *ivarList = class_copyIvarList(self,&outCount);
//obj:要設(shè)置的對(duì)象烛谊, ivar:壓迫設(shè)置的對(duì)象的某一個(gè)屬性 value:value
object_setIvar(person,ivarList[0],name);
object_setIvar(person,ivarList[1],gender);
object_setIvar(person,ivarList[2],age);
object_setIvar(person,ivarList[3],@(height));
return person;
}
③得到成員變量的值
在person.h里設(shè)置方法
- (void)getPersonMessager;
在Person.m里實(shí)現(xiàn)
- (void)getPersonMessager
{
unsigned int outCount;
Ivar *ivarList = class_copyIvarList([Person class], &outCount);
for (NSInteger i = 0; i < outCount; i++) {
NSLog(@"name = %s,value = %@",ivar_getName(ivarList[i]),object_getIvar(self, ivarList[i]));
}
}
2.關(guān)于實(shí)例方法
runtime的屬性:
1 + resolveInstanceMethod:(SEL)sel // 為一個(gè)實(shí)例方法動(dòng)態(tài)添加實(shí)現(xiàn)
2 + resolveClassMethod:(SEL)sel // 為一個(gè)類方法動(dòng)態(tài)添加實(shí)現(xiàn)
3 - (id)forwardingTargetForSelector:(SEL)aSelector
//為沒(méi)有實(shí)現(xiàn)的方法指定一個(gè)對(duì)象
4 - (void)forwardInvocation:(NSInvocation *)anInvocation
//子類重載這個(gè)方法為消息指定其他對(duì)象
具體的用法
①
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
NSString *selString = NSStringFromSelector(sel);
if ([selString isEqualToString:@"walkOnTheStreet:"]) {
//為一個(gè)沒(méi)有實(shí)現(xiàn)的方法是動(dòng)態(tài)添加實(shí)現(xiàn)
cls:類
name:沒(méi)有實(shí)現(xiàn)的方法
IMP:要添加的實(shí)現(xiàn)
types:動(dòng)態(tài)添加的實(shí)現(xiàn)的類型編碼
class_addMethod(self, @selector(walkOnTheStreet:), (IMP)walkFunc, "V@:@");
//Void 對(duì)應(yīng)類型編碼V ,對(duì)象類型是 @
}
return [super resolveInstanceMethod:sel];
}
②切換消息轉(zhuǎn)化對(duì)象:把Person的方法轉(zhuǎn)移到Dog里實(shí)現(xiàn)
在Person里設(shè)置方法
- (void)walkOnTheStreet1
在Dog里定義一個(gè)一樣的方法
- (void)walkOnTheStreet1
在Dog.m里實(shí)現(xiàn)
- (void)walkOnTheStreet1
{
NSLog(@"you are dog!!!!!!--%s",__func__);
}
在Person.m里轉(zhuǎn)移
方法1
- (void)orwardInvocation:(NSInvocation *)anInvocation
{
//判斷Dog顯影方法
if ([Dog instancesRespondToSelector:anInvocation.selector]) {
self.dog= [Dog new];
[anInvocation invokeWithTarget:self.dog];//taget
}
}
方法1
//給方法1指定一個(gè)有效的簽名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
NSMethodSignature *methodSignature = [super methodSignatureForSelector:aSelector];
if (!methodSignature) {
methodSignature = [Dog instanceMethodSignatureForSelector:aSelector];
}
return methodSignature;
}
方法2
- (id)forwardingTargetForSelector:(SEL)aSelector
{
NSString *selString = NSStringFromSelector(aSelector);
if ([selString isEqualToString:@"walkOnTheStreet1"]) {
self.dog = [Dog new];
return self.dog;
}
//如果方法沒(méi)有響應(yīng)
return [super forwardingTargetForSelector:aSelector];
}