iOS-runtime通篇詳解-下

上接上篇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], &copyIvarListCount);
    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], &copyPropertyListCount);
    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通篇詳解-拓展

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末琢歇,一起剝皮案震驚了整個(gè)濱河市兰怠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌李茫,老刑警劉巖揭保,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異魄宏,居然都是意外死亡秸侣,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來味榛,“玉大人椭坚,你說我怎么就攤上這事〔” “怎么了善茎?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長频轿。 經(jīng)常有香客問我垂涯,道長,這世上最難降的妖魔是什么航邢? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任耕赘,我火速辦了婚禮,結(jié)果婚禮上膳殷,老公的妹妹穿的比我還像新娘操骡。我一直安慰自己,他們只是感情好赚窃,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布当娱。 她就那樣靜靜地躺著,像睡著了一般考榨。 火紅的嫁衣襯著肌膚如雪跨细。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天河质,我揣著相機(jī)與錄音冀惭,去河邊找鬼。 笑死掀鹅,一個(gè)胖子當(dāng)著我的面吹牛散休,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播乐尊,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼戚丸,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了扔嵌?” 一聲冷哼從身側(cè)響起限府,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎痢缎,沒想到半個(gè)月后胁勺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡独旷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年署穗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了寥裂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡案疲,死狀恐怖封恰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情褐啡,我是刑警寧澤诺舔,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站春贸,受9級(jí)特大地震影響混萝,放射性物質(zhì)發(fā)生泄漏遗遵。R本人自食惡果不足惜萍恕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望车要。 院中可真熱鬧允粤,春花似錦、人聲如沸翼岁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽琅坡。三九已至悉患,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間榆俺,已是汗流浹背售躁。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留茴晋,地道東北人陪捷。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像诺擅,于是被迫代替她去往敵國和親市袖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 求而不得未必是遺憾 肥肥貓愛文創(chuàng) 你有沒有笑著拒絕過很喜歡的東西 你有沒有總是在別人面前強(qiáng)裝開心 你有沒有明知是自...
    only吶吶吶閱讀 544評(píng)論 0 0
  • 小橋 流水 青石階 煙籠廊橋風(fēng)雨斜 憑欄俯瞰春水瀾 碧池漣漪柔風(fēng)漫 水韻慢慢紅塵戀 妙雨如斯輕輕彈 一曲天籟和弦舞...
    葉子青書閱讀 232評(píng)論 0 1
  • 刻板印象主要是指人們對(duì)某個(gè)事物或物體形成的一種概括固定的看法,并把這種觀看法推而廣之撮执,認(rèn)為這個(gè)事物或者整體都具有該...
    皮皮蝦走起閱讀 1,237評(píng)論 0 0