上接上篇iOS-runtime通篇詳解-上
原創(chuàng)內(nèi)容,轉(zhuǎn)載請(qǐng)注明出處:
http://www.reibang.com/p/4c276f5c338c
class-response
class-conforms
class-is
//判斷是否響應(yīng)方法
//入?yún)?類Class具被,方法名SEL
//返回:是否響應(yīng)BOOL值
BOOL class_respondsToSelector(Class cls, SEL sel)
//判斷是否遵循某個(gè)協(xié)議
//入?yún)?類Class碍沐,協(xié)議
//返回:是否響應(yīng)BOOL值
BOOL class_conformsToProtocol(Class cls, Protocol *protocol)
//判斷是否是元類
//入?yún)?類Class
//返回:返回結(jié)果
BOOL class_isMetaClass(Class cls)
(以上API的)運(yùn)行測(cè)試代碼地址在這里:iOS-Rumtime-All:demo-runtime-part3
#import "ViewController.h"
#import <objc/runtime.h>
@interface ViewController ()<UITableViewDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self method0];
BOOL result0 = class_replaceMethod([self class], @selector(method0), (IMP)method1, NULL);
NSLog(@">>>>>>>>2:%@",@(result0));
[self method0];
NSLog(@"\n");
BOOL result1 = class_conformsToProtocol([self class], NSProtocolFromString(@"UITableViewDelegate"));
BOOL result2 = class_conformsToProtocol([self class], NSProtocolFromString(@"UITableViewDataSource"));
BOOL result3 = class_addProtocol([self class], NSProtocolFromString(@"UITableViewDataSource"));
NSLog(@">>>>>>>>3:%@",@(result1));
NSLog(@">>>>>>>>4:%@",@(result2));
NSLog(@">>>>>>>>5:%@",@(result3));
BOOL result4 = class_conformsToProtocol([self class], NSProtocolFromString(@"UITableViewDelegate"));
BOOL result5 = class_conformsToProtocol([self class], NSProtocolFromString(@"UITableViewDataSource"));
NSLog(@">>>>>>>>6:%@",@(result4));
NSLog(@">>>>>>>>7:%@",@(result5));
NSLog(@"\n");
BOOL result6 = class_isMetaClass([self class]);
NSLog(@">>>>>>>>8:%@",@(result6));
BOOL result7 = class_respondsToSelector([self class], @selector(method0));
NSLog(@">>>>>>>>9:%@",@(result7));
BOOL result8 = class_respondsToSelector([self class], @selector(method1));
NSLog(@">>>>>>>>10:%@",@(result8));
}
-(void)method0{
NSLog(@">>>>>>>>0");
}
void method1(){
NSLog(@">>>>>>>>1");
}
+(void)method1{
NSLog(@">>>>>>>>0");
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
(以上運(yùn)行測(cè)試的)打印結(jié)果
demo-runtime-part3[4514:1037966] >>>>>>>>0
demo-runtime-part3[4514:1037966] >>>>>>>>2:1
demo-runtime-part3[4514:1037966] >>>>>>>>1
demo-runtime-part3[4514:1037966]
demo-runtime-part3[4514:1037966] >>>>>>>>3:1
demo-runtime-part3[4514:1037966] >>>>>>>>4:0
demo-runtime-part3[4514:1037966] >>>>>>>>5:1
demo-runtime-part3[4514:1037966] >>>>>>>>6:1
demo-runtime-part3[4514:1037966] >>>>>>>>7:1
demo-runtime-part3[4514:1037966]
demo-runtime-part3[4514:1037966] >>>>>>>>8:0
demo-runtime-part3[4568:1062173] >>>>>>>>9:1
demo-runtime-part3[4568:1062173] >>>>>>>>10:0
(以上打印結(jié)果的)解析
#從上面的測(cè)試我們可以發(fā)現(xiàn)各個(gè)函數(shù)的作用:
###class_conformsToProtocol:
判斷某類是否遵循某協(xié)議。從打印可以看出代碼已經(jīng)實(shí)現(xiàn)的協(xié)議UITableViewDelegate已經(jīng)可以判斷出來由缆,后來代碼通過class_addProtocol添加的協(xié)議也能判斷出來汗盘。
由此判斷此函數(shù)可以判斷出來代碼添加的協(xié)議皱碘,動(dòng)態(tài)添加的協(xié)議可以獲取到。
###class_isMetaClass:
判斷是否是元類隐孽。不細(xì)說了癌椿,有興趣可以看下這篇博客http://www.reibang.com/p/79b06fabb459
###class_respondsToSelector:
某類是否響應(yīng)某個(gè)方法。從打印結(jié)果可以看到菱阵,此函數(shù)可以判斷是否響應(yīng)某個(gè)實(shí)例方法踢俄,并不能判斷靜態(tài)方法。
OC里面也有一個(gè)類似的函數(shù):
- (BOOL)respondsToSelector:(SEL)aSelector;
雖然我們沒有源碼晴及,但是我們可以猜想上面這個(gè)方法是調(diào)用或者說在編譯的時(shí)候被轉(zhuǎn)換成class_respondsToSelector函數(shù)都办。
Ivar-get
//獲取變量名
//入?yún)?變量Ivar
//返回:char數(shù)組
const char *ivar_getName(Ivar v)
//獲取變量類型描述()
//入?yún)?變量Ivar
//返回:char數(shù)組
const char *ivar_getTypeEncoding(Ivar v)
//獲取變量基地址偏移量
//入?yún)?變量Ivar
//返回:偏移量ptrdiff_t,有興趣的可以參考這篇文章http://www.reibang.com/p/be00d998a4ed
ptrdiff_t ivar_getOffset(Ivar v)
(以上API的)運(yùn)行測(cè)試代碼地址在這里:iOS-Rumtime-All:demo-runtime-part4
#import "ViewController.h"
#import <objc/runtime.h>
@interface ViewController ()
{
NSObject *_property0;
UIView *_property1;
UIViewController *_property2;
float _property3;
int _property4;
}
@property (nonatomic,strong)NSObject *property5;
@property (nonatomic,strong)UIView *property6;
@property (nonatomic,strong)UIViewController *property7;
@property (nonatomic,assign)float property8;
@property (nonatomic,assign)int property9;
@end
@implementation ViewController
//編碼值 含意
//c 代表char類型
//i 代表int類型
//s 代表short類型
//l 代表long類型,在64位處理器上也是按照32位處理
//q 代表long long類型
//C 代表unsigned char類型
//I 代表unsigned int類型
//S 代表unsigned short類型
//L 代表unsigned long類型
//Q 代表unsigned long long類型
//f 代表float類型
//d 代表double類型
//B 代表C++中的bool或者C99中的_Bool
//v 代表void類型
//* 代表char *類型
//@ 代表對(duì)象類型
//# 代表類對(duì)象 (Class)
//: 代表方法selector (SEL)
//[array type] 代表array
//{name=type…} 代表結(jié)構(gòu)體
//(name=type…) 代表union
//bnum A bit field of num bits
//^type A pointer to type
//? An unknown type (among other things, this code is used for function pointers)
- (void)viewDidLoad {
[super viewDidLoad];
//class獲取--獲取整個(gè)成員變量列表
/**
* 1.獲取所有私有變量和屬性
* 2.獲取的私有變量的名和定義的名一模一樣
* 3.獲取的屬性的名前面都添加了下劃線
*/
unsigned int copyIvarListCount = 0;
Ivar *ivars = class_copyIvarList([self class], ©IvarListCount);
for (NSInteger i = 0; i< copyIvarListCount; i ++) {
Ivar ivar = ivars[i];
const char *name = ivar_getName(ivar);
const char *encoding = ivar_getTypeEncoding(ivar);
ptrdiff_t ofset = ivar_getOffset(ivar);
NSLog(@">>>>>>>>0:%@:%@:%td",
[NSString stringWithUTF8String:name],
[NSString stringWithUTF8String:encoding],
ofset);
}
free(ivars);
}
@end
(以上運(yùn)行測(cè)試的)打印結(jié)果
demo-runtime-part4[4611:1075970] >>>>>>>>0:_property0:@"NSObject":760
demo-runtime-part4[4611:1075970] >>>>>>>>0:_property1:@"UIView":768
demo-runtime-part4[4611:1075970] >>>>>>>>0:_property2:@"UIViewController":776
demo-runtime-part4[4611:1075970] >>>>>>>>0:_property3:f:784
demo-runtime-part4[4611:1075970] >>>>>>>>0:_property4:i:788
demo-runtime-part4[4611:1075970] >>>>>>>>0:_property8:f:792
demo-runtime-part4[4611:1075970] >>>>>>>>0:_property9:i:796
demo-runtime-part4[4611:1075970] >>>>>>>>0:_property5:@"NSObject":800
demo-runtime-part4[4611:1075970] >>>>>>>>0:_property6:@"UIView":808
demo-runtime-part4[4611:1075970] >>>>>>>>0:_property7:@"UIViewController":816
(以上打印結(jié)果的)解析
#從上面的測(cè)試我們可以發(fā)現(xiàn)各個(gè)函數(shù)的作用:
###ivar_getName:
獲取變量名虑稼。定義的變量直接獲取變量的名字琳钉,定義的屬性獲取的屬性會(huì)在原來屬性名的基礎(chǔ)上加一條下劃線。
###ivar_getTypeEncoding:
獲取變量的類型編碼蛛倦。編碼對(duì)應(yīng)的含義上面代碼已經(jīng)寫了歌懒。
###ivar_getOffset:
獲取變量基地址偏移量。有興趣的可以參考這篇文章http://www.reibang.com/p/be00d998a4ed
property-get
//獲取屬性名
//入?yún)?屬性objc_property_t
//返回:屬性名char字符串
const char *property_getName(objc_property_t property)
//獲取屬性的屬性
//入?yún)? objc_property_t
//返回:屬性的屬性char數(shù)組描述
const char *property_getAttributes(objc_property_t property)
(以上API的)運(yùn)行測(cè)試代碼地址在這里:iOS-Rumtime-All:demo-runtime-part5
#import "ViewController.h"
#import <objc/runtime.h>
@interface ViewController ()
{
NSObject *_property0;
UIView *_property1;
UIViewController *_property2;
float _property3;
int _property4;
}
@property (nonatomic,strong)NSObject *_property5;
@property (nonatomic, weak)UIView *property6;
@property (nonatomic,strong)UIViewController *property7;
@property (nonatomic,assign)float property8;
@property (nonatomic,assign)int property9;
@property (nonatomic,strong,readonly)UIViewController *property10;
@property (nonatomic,readwrite)UIViewController *property11;
@property (nonatomic, copy)NSString *property12;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//class獲取--獲取整個(gè)屬性列表(只獲取屬性不獲取變量)
/**
* 1.獲取所有屬性
* 2.獲取的屬性名和你代碼寫的一樣,獲取出來的屬性名不自動(dòng)添加下劃線
*/
unsigned int copyPropertyListCount = 0;
objc_property_t *propertys = class_copyPropertyList([self class], ©PropertyListCount);
for (NSInteger i = 0; i < copyPropertyListCount; i++) {
objc_property_t property = propertys[i];
const char *name = property_getName(property);
const char *attributes = property_getAttributes(property);
NSLog(@">>>>>>>>0:%@:%@",
[NSString stringWithUTF8String:name],
[NSString stringWithUTF8String:attributes]);
}
free(propertys);
}
@end
(以上運(yùn)行測(cè)試的)打印結(jié)果
demo-runtime-part5[4916:1190177] >>>>>>>>0:_property5:T@"NSObject",&,N,V__property5
demo-runtime-part5[4916:1190177] >>>>>>>>0:property6:T@"UIView",W,N,V_property6
demo-runtime-part5[4916:1190177] >>>>>>>>0:property7:T@"UIViewController",&,N,V_property7
demo-runtime-part5[4916:1190177] >>>>>>>>0:property8:Tf,N,V_property8
demo-runtime-part5[4916:1190177] >>>>>>>>0:property9:Ti,N,V_property9
demo-runtime-part5[4916:1190177] >>>>>>>>0:property10:T@"UIViewController",R,N,V_property10
demo-runtime-part5[4916:1190177] >>>>>>>>0:property11:T@"UIViewController",&,N,V_property11
demo-runtime-part5[4916:1190177] >>>>>>>>0:property12:T@"NSString",C,N,V_property12
(以上打印結(jié)果的)解析
#從上面的測(cè)試我們可以發(fā)現(xiàn)各個(gè)函數(shù)的作用:
###property_getName:
這個(gè)沒什么好說的溯壶,獲取屬性的名字及皂。
###property_getAttributes:
獲取屬性的屬性。從上面打印可以看出茸塞,屬性定義的時(shí)候?qū)懛ú灰粯佣阕蛴〕鰜淼膶傩缘膶傩砸膊灰粯硬槠剩旅婧?jiǎn)單說明一下property_getAttributes結(jié)果的每個(gè)符號(hào)的意義:
T:后面跟的是屬性的運(yùn)行時(shí)類型钾虐。
&:表示strong,W表示weak
N:noautomic
V:后面跟的是屬性所對(duì)應(yīng)的變量
有興趣了解更多請(qǐng)參考這篇博客:http://www.reibang.com/p/cefa1da5e775
property-copy
//獲取屬性的屬性列表
//入?yún)? objc_property_t笋庄,int變量指針
//返回: objc_property_attribute_t屬性的屬性結(jié)構(gòu)體包含鍵和值
//typedef struct {
// const char *name;
// const char *value;
//} objc_property_attribute_t;
//使用方法暫時(shí)不做demo演示了效扫,請(qǐng)參考上面代碼演示
objc_property_attribute_t *property_copyAttributeList(objc_property_t property, unsigned int *outCount)
//獲取屬性的屬性值
//入?yún)? objc_property_t倔监,attributeName屬性的屬性鍵
//返回: 屬性的屬性值char數(shù)組
//使用方法暫時(shí)不做demo演示了,請(qǐng)參考上面代碼演示
char *property_copyAttributeValue(objc_property_t property, const char *attributeName)
method-get
//獲取方法名
//入?yún)? 方法描述結(jié)構(gòu)體Method
//返回: 方法名SEL
SEL method_getName(Method m)
//獲取方法實(shí)現(xiàn)
//入?yún)? objc_property_t菌仁,attributeName屬性的屬性鍵
//返回: 屬性的屬性值char數(shù)組
IMP method_getImplementation(Method m)
//獲取方法的屬性信息(包括返回值類型浩习,參數(shù)類型等等信息)
//入?yún)? 方法描述結(jié)構(gòu)體Method
//返回: 屬性值char數(shù)組
const char *method_getTypeEncoding(Method m)
//獲取方法的參數(shù)個(gè)數(shù)
//入?yún)? 方法描述結(jié)構(gòu)體Method
//返回: 屬性的個(gè)數(shù)
unsigned int method_getNumberOfArguments(Method m)
//獲取返回值的類型
//入?yún)? 方法描述結(jié)構(gòu)體Method,返回值的容器char數(shù)組济丘,容器大小谱秽。返回值的類型字符串會(huì)被copy到第二個(gè)參數(shù)里。
//返回: void
void method_getReturnType(Method m, char *dst, size_t dst_len)
//獲取參數(shù)的屬性參數(shù)
//入?yún)? 方法描述結(jié)構(gòu)體Method摹迷,返回值的容器char數(shù)組疟赊,容器大小。返回值的類型字符串會(huì)被copy到第二個(gè)參數(shù)里峡碉。
//返回: void
void method_getArgumentType(Method m, unsigned int index, char *dst, size_t dst_len)
//獲取方法的描述
//入?yún)? 方法描述結(jié)構(gòu)體Method
//返回: 方法描述結(jié)構(gòu)體objc_method_description
//struct objc_method_description {
// SEL name;
// char *types;
//};
struct objc_method_description *method_getDescription(Method m)
(以上API的)運(yùn)行測(cè)試代碼地址在這里:iOS-Rumtime-All:demo-runtime-part6
#import "ViewController.h"
#import <objc/runtime.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Method result0 = class_getInstanceMethod([self class], @selector(method0:agu1:agu2:agu3:agu4:agu5:));
//獲取方法名
//入?yún)? 方法描述結(jié)構(gòu)體Method
//返回: 方法名SEL
SEL result1 = method_getName(result0);
NSLog(@">>>>>>>>0:%@",NSStringFromSelector(result1));
//獲取方法實(shí)現(xiàn)
//入?yún)? objc_property_t近哟,attributeName屬性的屬性鍵
//返回: 屬性的屬性值char數(shù)組
IMP result2 = method_getImplementation(result0);
//獲取方法的屬性信息(包括返回值類型,參數(shù)類型等等信息)
//入?yún)? 方法描述結(jié)構(gòu)體Method
//返回: 屬性值char數(shù)組
const char *result3 = method_getTypeEncoding(result0);
NSLog(@">>>>>>>>2:%@",[NSString stringWithUTF8String:result3]);
//獲取方法的參數(shù)個(gè)數(shù)
//入?yún)? 方法描述結(jié)構(gòu)體Method
//返回: 屬性的個(gè)數(shù)
unsigned int result4 = method_getNumberOfArguments(result0);
NSLog(@">>>>>>>>3:%ud",result4);
for (unsigned int i =0 ; i < result4; i++) {
char result5[1024] = {};
//獲取參數(shù)的屬性參數(shù)
//入?yún)? 方法描述結(jié)構(gòu)體Method鲫寄,返回值的容器char數(shù)組吉执,容器大小。返回值的類型字符串會(huì)被copy到第二個(gè)參數(shù)里地来。
//返回: void
method_getArgumentType(result0, i, result5, 1024);
NSLog(@">>>>>>>>4:%ud",result4);
}
//獲取返回值的類型
//入?yún)? 方法描述結(jié)構(gòu)體Method戳玫,返回值的容器char數(shù)組,容器大小未斑。返回值的類型字符串會(huì)被copy到第二個(gè)參數(shù)里量九。
//返回: void
char result6[1024] = {};
method_getReturnType(result0, result6, 1024);
NSLog(@">>>>>>>>5:%s",result6);
//獲取方法的描述
//入?yún)? 方法描述結(jié)構(gòu)體Method
//返回: 方法描述結(jié)構(gòu)體objc_method_description
//struct objc_method_description {
// SEL name;
// char *types;
//};
struct objc_method_description result7 = *method_getDescription(result0);
NSLog(@">>>>>>>>5:%@:%@",NSStringFromSelector(result7.name),[NSString stringWithUTF8String:result7.types]);
}
-(NSArray *)method0:(NSArray *)agu0
agu1:(CGFloat)agu1
agu2:(NSObject *)agu2
agu3:(NSString *)agu3
agu4:(CGRect)agu4
agu5:(UIView *)agu5{
NSLog(@">>>>>>>>1");
return @[];
}
@end
(以上運(yùn)行測(cè)試的)打印結(jié)果
demo-runtime-part6[5528:1411303] >>>>>>>>0:method0:agu1:agu2:agu3:agu4:agu5:
demo-runtime-part6[5528:1411303] >>>>>>>>2:@88@0:8@16d24@32@40{CGRect={CGPoint=dd}{CGSize=dd}}48@80
demo-runtime-part6[5528:1411303] >>>>>>>>3:8d
demo-runtime-part6[5528:1411303] >>>>>>>>4:@
demo-runtime-part6[5528:1411303] >>>>>>>>4::
demo-runtime-part6[5528:1411303] >>>>>>>>4:@
demo-runtime-part6[5528:1411303] >>>>>>>>4:d
demo-runtime-part6[5528:1411303] >>>>>>>>4:@
demo-runtime-part6[5528:1411303] >>>>>>>>4:@
demo-runtime-part6[5528:1411303] >>>>>>>>4:{CGRect={CGPoint=dd}{CGSize=dd}}
demo-runtime-part6[5528:1411303] >>>>>>>>4:@
demo-runtime-part6[5528:1411303] >>>>>>>>5:@
demo-runtime-part6[5528:1411303] >>>>>>>>6:method0:agu1:agu2:agu3:agu4:agu5::@88@0:8@16d24@32@40{CGRect={CGPoint=dd}{CGSize=dd}}48@80
(以上打印結(jié)果的)解析
#從上面的測(cè)試我們可以發(fā)現(xiàn)各個(gè)函數(shù)的作用:
###method_getName:
獲取方法名。這個(gè)函數(shù)和NSStringFromSelector(result1)的結(jié)果是一樣的颂碧。
可以猜想這兩個(gè)函數(shù)可能存在一定的關(guān)系荠列。
###method_getImplementation:
獲取方法的實(shí)現(xiàn)。
###method_getTypeEncoding:
獲取方法的編碼:
@88@0:8@16d24@32@40{CGRect={CGPoint=dd}{CGSize=dd}}48@80载城。
詳細(xì)解釋請(qǐng)參考這篇文章http://blog.csdn.net/zhenganzhong_csdn/article/details/47094407
###method_getNumberOfArguments:
獲取方法參數(shù)的個(gè)數(shù)肌似。
###method_getArgumentType:
獲取參數(shù)的類型。這里返回的類型編碼請(qǐng)參考上面的碼表诉瓦。
###method_getReturnType:
獲取返回值的類型川队。這里返回的類型編碼請(qǐng)參考上面的碼表。
###method_getDescription:
獲取方法的描述睬澡。包括方法的名字和方法的編碼值固额。
這兩個(gè)值我們上面已經(jīng)介紹了。請(qǐng)才考上面的代碼煞聪。
method-copy
//同上method_getReturnType
char *method_copyReturnType(Method m)
//同上method_getArgumentType
char *method_copyArgumentType(Method m, unsigned int index)
method-set
//設(shè)置方法的實(shí)現(xiàn)
//入?yún)?方法Method斗躏,要設(shè)置的方法的實(shí)現(xiàn)IMP
//返回:設(shè)置方法的實(shí)現(xiàn)
IMP method_setImplementation(Method m, IMP imp)
method-exchange(method swing)
//交換方法的實(shí)現(xiàn)
//入?yún)?要交換實(shí)現(xiàn)的兩個(gè)方法Method
//返回:void
void method_exchangeImplementations(Method m1, Method m2)
(以上API的)運(yùn)行測(cè)試代碼地址在這里:iOS-Rumtime-All:demo-runtime-part7
#import "ViewController.h"
#import <objc/runtime.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 方法 方法名 方法實(shí)現(xiàn)
// method0 method0 method0
// method1 method1 method1
// method2 method2 method2
[self method0];
Method result0 = class_getInstanceMethod([self class], @selector(method0));
Method result1 = class_getInstanceMethod([self class], @selector(method1));
Method result2 = class_getInstanceMethod([self class], @selector(method2));
method_setImplementation(result0, method_getImplementation(result1));
// 方法 方法名 方法實(shí)現(xiàn)
// method0 method0 method1
// method1 method1 空
// method2 method2 method2
[self method0];
method_exchangeImplementations(result1, result2);
// 方法 方法名 方法實(shí)現(xiàn)
// method0 method0 method1
// method1 method1 method2
// method2 method2 空
[self method1];
}
-(void)method0{
NSLog(@">>>>>>>>0:%s",__func__);
}
-(void)method1{
NSLog(@">>>>>>>>1:%s",__func__);
}
-(void)method2{
NSLog(@">>>>>>>>2:%s",__func__);
}
@end
(以上運(yùn)行測(cè)試的)打印結(jié)果
demo-runtime-part7[6157:1606828] >>>>>>>>0:-[ViewController method0]
demo-runtime-part7[6157:1606828] >>>>>>>>1:-[ViewController method1]
demo-runtime-part7[6157:1606828] >>>>>>>>2:-[ViewController method2]
(以上打印結(jié)果的)解析
#從上面的測(cè)試我們可以發(fā)現(xiàn)各個(gè)函數(shù)的作用:
###class_getInstanceMethod:
獲取類的實(shí)例方法。
###method_setImplementation:
設(shè)置方法的實(shí)現(xiàn)昔脯。如上代碼啄糙,在沒有設(shè)置實(shí)現(xiàn)前笛臣,每個(gè)方法的方法名和實(shí)現(xiàn)都是一一對(duì)應(yīng)的。
后來我們將method0的實(shí)現(xiàn)設(shè)置為method1后隧饼,我們?cè)僬{(diào)用method0的時(shí)候沈堡,執(zhí)行的是method1.
這時(shí)候method0的實(shí)現(xiàn)是method1,method1的實(shí)現(xiàn)為method1燕雁。
###method_exchangeImplementations:
交換兩個(gè)方法的實(shí)現(xiàn)诞丽。如上代碼我們?cè)偕弦徊降幕A(chǔ)上交換了method1和method2的實(shí)現(xiàn)。在交換前method1的實(shí)現(xiàn)是method1拐格,method2的實(shí)現(xiàn)是method2率拒。
交換完成后method1的實(shí)現(xiàn)是method2,method2的實(shí)現(xiàn)是method1禁荒,所以交換完成后調(diào)用method1執(zhí)行的是method2.
objc
//創(chuàng)建一個(gè)類對(duì)(類和元類)
//入?yún)?父類Class猬膨,要?jiǎng)?chuàng)建的類名,類大小呛伴。
//返回:創(chuàng)建的新類
Class objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes)
//注冊(cè)類
//入?yún)?類Class
//返回:void
void objc_registerClassPair(Class cls)
//獲取所有已注冊(cè)類的列表
//入?yún)?int型變量指針
//返回:類的指針列表
Class *objc_copyClassList(unsigned int *outCount)
//銷毀一個(gè)類及其相關(guān)聯(lián)的類
//入?yún)?類Class
//返回:void
//注意銷毀的是類不是對(duì)象
void objc_disposeClassPair(Class cls)
(以上API的)運(yùn)行測(cè)試代碼地址在這里:iOS-Rumtime-All:demo-runtime-part8
#import "ViewController.h"
#import <objc/runtime.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//創(chuàng)建--一個(gè)新類和元類
/**
* 1.添加動(dòng)態(tài)添加變量只能在 objc_allocateClassPair 和 objc_registerClassPair之間才可以
*/
Class result0 = objc_allocateClassPair([NSObject class], "ObjectSubClass", 0);
NSLog(@">>>>>>>>0:%@",NSStringFromClass(result0));
id result1 = [[result0 alloc]init];
NSLog(@">>>>>>>>2:%@",result1);
class_addIvar(result0, "_attribute1", sizeof(NSString *), log(sizeof(NSString *)), "i");
Ivar ivar = class_getInstanceVariable(result0, "_attribute1");//獲取變量,如果沒獲取到說明不存在
NSLog(@">>>>>>>>3:%@",[NSString stringWithUTF8String:ivar_getName(ivar)]);
//注冊(cè)--在應(yīng)用中注冊(cè)由objc_allocateClassPair創(chuàng)建的類
objc_registerClassPair(result0);
//銷毀--一個(gè)類及其相關(guān)聯(lián)的類,注意不是對(duì)象
objc_disposeClassPair(result0);
}
@end
(以上運(yùn)行測(cè)試的)打印結(jié)果
demo-runtime-part8[6341:1657279] >>>>>>>>0:ObjectSubClass
demo-runtime-part8[6341:1657279] >>>>>>>>1:<ObjectSubClass: 0x608000013bc0>
demo-runtime-part8[6341:1657279] >>>>>>>>2:_attribute1
(以上打印結(jié)果的)解析
#從上面的測(cè)試我們可以發(fā)現(xiàn)各個(gè)函數(shù)的作用:
###objc_allocateClassPair:
創(chuàng)建一個(gè)類對(duì)勃痴,包括新類和元類。
如上代碼热康,我們創(chuàng)建了一個(gè)類ObjectSubClass并且給這個(gè)類創(chuàng)建了實(shí)例和動(dòng)態(tài)添加了屬性沛申。并且操作都已成功。
添加動(dòng)態(tài)添加變量只能在 objc_allocateClassPair 和 objc_registerClassPair之間才可以姐军。
###objc_registerClassPair:
注冊(cè)新創(chuàng)建的類對(duì)铁材。新創(chuàng)建的類對(duì)需要注冊(cè)才能生效。
###objc_disposeClassPair:
銷毀剛才創(chuàng)建的類對(duì)奕锌。
sel
//獲取方法名
//入?yún)?方法名SEL
//返回:方法名char
const char *sel_getName(SEL sel)
//獲取方法id
//入?yún)?屬性方法名char
//返回:SEL
SEL sel_getUid(const char *str)
//注冊(cè)方法
//入?yún)?要注冊(cè)的方法名
//返回:返回方法名選擇器
//在系統(tǒng)中注冊(cè)一個(gè)方法著觉,將方法名映射到一個(gè)選擇器,并返回這個(gè)選擇器
SEL sel_registerName(const char *str)
//對(duì)比方法選擇器
//入?yún)?要對(duì)比的兩個(gè)選擇器SEL
//返回:是否相等
BOOL sel_isEqual(SEL lhs, SEL rhs)
(以上API的)運(yùn)行測(cè)試代碼地址在這里:iOS-Rumtime-All:demo-runtime-part9
#import "ViewController.h"
#import <objc/runtime.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//獲取方法名
//入?yún)?方法名SEL
//返回:方法名char
const char *result0 = sel_getName(@selector(method0));
NSLog(@">>>>>>>>0:%s",result0);
//獲取方法id
//入?yún)?屬性方法名char
//返回:SEL
SEL result1 = sel_getUid(result0);
NSLog(@">>>>>>>>1:%@",NSStringFromSelector(result1));
//注冊(cè)方法
//入?yún)?要注冊(cè)的方法名
//返回:返回方法名選擇器
//在系統(tǒng)中注冊(cè)一個(gè)方法惊暴,將方法名映射到一個(gè)選擇器饼丘,并返回這個(gè)選擇器
SEL result2 = sel_registerName("method1");
NSLog(@">>>>>>>>2:%@",NSStringFromSelector(result2));
//對(duì)比方法選擇器
//入?yún)?要對(duì)比的兩個(gè)選擇器SEL
//返回:是否相等
BOOL result3 = sel_isEqual(result1, result2);
NSLog(@">>>>>>>>2:%d",result3);
}
-(void)method0{}
@end
(以上運(yùn)行測(cè)試的)打印結(jié)果
demo-runtime-part9[7824:1762586] >>>>>>>>0:method0
demo-runtime-part9[7824:1762586] >>>>>>>>1:method0
demo-runtime-part9[7824:1762586] >>>>>>>>2:method1
demo-runtime-part9[7824:1762586] >>>>>>>>2:0
(以上打印結(jié)果的)解析
#從上面的測(cè)試我們可以發(fā)現(xiàn)各個(gè)函數(shù)的作用:
###sel_getName:
獲取方法名。如上打印結(jié)果method0的方法名為method0辽话。
###sel_getUid:
獲取選擇器肄鸽。如上打印結(jié)果method0的選擇器為method0。
###sel_registerName:
注冊(cè)方法名油啤。
在系統(tǒng)中注冊(cè)一個(gè)方法典徘,將方法名映射到一個(gè)選擇器,并返回這個(gè)選擇器益咬。
如上打印逮诲,系統(tǒng)注冊(cè)并且返回了
###sel_isEqual:
如上打印。method0和method1是不相等的,所以打印0汛骂;
object
//獲取變量實(shí)例
//入?yún)?變量所屬實(shí)例,變量結(jié)構(gòu)體Ivar
//返回:變量實(shí)例
id object_getIvar(id obj, Ivar ivar)
//給實(shí)例設(shè)置變量實(shí)例
//入?yún)?要設(shè)置變量的實(shí)例评腺,變量結(jié)構(gòu)體Ivar帘瞭,變量值value
//返回:void
void object_setIvar(id obj, Ivar ivar, id value)
(以上API的)運(yùn)行測(cè)試代碼地址在這里:iOS-Rumtime-All:demo-runtime-part10
#import "ViewController.h"
#import <objc/runtime.h>
@interface ViewController ()
{
NSArray *_property0;
}
@property (nonatomic,strong)NSObject *property1;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
unsigned int result0 = 0;
Ivar *result1 = class_copyIvarList([self class], &result0);
for (unsigned int i = 0; i < result0; i++) {
Ivar result2 = result1[i];
//獲取變量實(shí)例
//入?yún)?變量所屬實(shí)例,變量結(jié)構(gòu)體Ivar
//返回:變量實(shí)例
id result3 = object_getIvar(self, result2);
NSLog(@">>>>>>>>0:%@",result3);
NSString *result4 = [NSString stringWithUTF8String:ivar_getName(result2)];
if ([result4 isEqualToString:@"_property0"]) {
//給實(shí)例設(shè)置變量實(shí)例
//入?yún)?要設(shè)置變量的實(shí)例蒿讥,變量結(jié)構(gòu)體Ivar蝶念,變量值value
//返回:void
object_setIvar(self, result2, @[@"0",@"1",@"2",@"3",@"4",@"5"]);
}else if([result4 isEqualToString:@"_property1"]){
//給實(shí)例設(shè)置變量實(shí)例
//入?yún)?要設(shè)置變量的實(shí)例,變量結(jié)構(gòu)體Ivar芋绸,變量值value
//返回:void
object_setIvar(self, result2, [[NSObject alloc]init]);
}
id result5 = object_getIvar(self, result2);
NSLog(@">>>>>>>>1:%@",result5);
}
}
@end
(以上運(yùn)行測(cè)試的)打印結(jié)果
demo-runtime-part10[7907:1785561] >>>>>>>>0:(null)
demo-runtime-part10[7907:1785561] >>>>>>>>1:(
0,
1,
2,
3,
4,
5
)
demo-runtime-part10[7907:1785561] >>>>>>>>0:(null)
demo-runtime-part10[7907:1785561] >>>>>>>>1:<NSObject: 0x610000006a10>
(以上打印結(jié)果的)解析
#從上面的測(cè)試我們可以發(fā)現(xiàn)各個(gè)函數(shù)的作用:
###object_getIvar:
獲取實(shí)例變量值媒殉。總共有兩個(gè)參數(shù)摔敛,第一個(gè)是實(shí)例廷蓉,第二個(gè)是變量的結(jié)構(gòu)體,前面已經(jīng)說過了马昙。這個(gè)函數(shù)的作用獲取某個(gè)實(shí)例的屬性的值桃犬。
###object_setIvar:
設(shè)置變量值。三個(gè)參數(shù)行楞。第一個(gè)是要設(shè)置變量的實(shí)例攒暇,第二個(gè)變量的結(jié)構(gòu)體。第三個(gè)是要設(shè)置屬性值子房。
這里要著重說明一下的是形用,變量設(shè)置需要類型對(duì)的上,如果類型對(duì)不上會(huì)產(chǎn)生很多問題证杭。
在篇尾
由于篇幅太長田度,簡(jiǎn)書都不能編輯了,只好拆成幾篇解愤。
程序員不需要打賞每币,只希望自己的項(xiàng)目能幫助更多人,請(qǐng)支持我的git開源框架:TFEasyCoder
下篇:iOS-runtime通篇詳解-拓展