继上Runtime梳理(三)
前面讲Runtime其实都是基于理论的,文绉绉的,湿哒哒的感觉并没有什么软用;那么这一篇我们就轻松一点复习加一点Runtime图解,是的Runtime更加通俗易懂,方便理解,架构知识吧,回顾一下前面Runtime知识:
概念类
- id和Class
Class super_class const char *name long version long info long instance_size objec_ivar_list *ivars objc_method_list **methodLists objc_cache_list *cache objc_protocol_list *protocols
SEL
objc_selector *SELobjc_selector char *name char *type
Method
id (* IMP)(id,SEL,...);
IMP
objc_method *Method objc_method SEL method_name obcj_method char *method_types IMP method_imp
Ivar
objc_ivar *Ivar objc_ivar char *ivar_name objc_ivar char *ivar_type objc_ivar int ivar_offset objc_ivar int space objc_propery_t objc_property_t是属性 objc_property *objc_property_t objc_property_attribute_t const char*name const char*value
Cache
objc_cache *Cache objc_cache unsigned int mask unsigned int occupied Method buckets[1]
Category
objc_catagory *Category char *category char *class_name objc_method_list *instance_methods objc_method_list *class_methods objc_method_list *protocols
方法
消息传递
objc_msgSend objc_msgSend_stret: objc_msgSendSuper: objc_msgSendSuper_stret:
消息动态解析
resolveInstanceMethod: forwardingTargetForSelector: methodSignatureForSelector: forwardInvocation: doesNotRecognizeSelector
- 补充方法和函数
// 手动添加一个类、属性、变量、方法、释放内存、赋值、方法调用 object_getIvar(self, class_getInstanceVariable([self class], "_age")); objc_registerClassPair(People); objc_allocateClassPair([NSObject class], "Person", 0); class_addIvar(People, "_name", sizeof(NSString*), log2(sizeof(NSString *)); @encode(NSString *)); SEL s = sel_registerName("say:"); class_addMethod(People, s, (IMP)sayFunction, "good"); Ivar ageIvar = class_getInstanceVariable(People, "_age"); object_setIvar(peopleInstance, ageIvar, @18); ((void (*)(id, SEL, id))objc_msgSend)(peopleInstance, s, @"大家好"); objc_disposeClassPair(People);
class_copyPropertyList([self class], &count);
property_getName(properties[i]);
//
free();
//
class_copyIvarList([self class], &count);
ivar_getName(ivars[i]);
//
class_copyMethodList([self class], &count);
SEL methodSEL = method_getName(methods[i]);
sel_getName(methodSEL);
int arguments = method_getNumberOfArguments(methods[i]);
// 关联对象 objc_association_retain_nonatomc
objc_setAssociatedObject(self, @selector(associatedBust), bust, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
// 获取关联
objc_getAssociatedObject(self, @selector(associatedBust));
// propertySetterByKey:自定义方法
SEL setter = [self propertySetterByKey:key];
((void()(id, SEL, id))objc_msgSend)(self, setter, value);
//
((void()(id, SEL))objc_msgSend)((id)car, @selector(eat));
// 交换两个方法地址
method_exchangeImplementations(imageWihtName, imageName);
####发现
+ Runtime提供一组函数,函数的形式主要为`class_copyXXXX`。这组函数就是用来获取`Ivar、Method、Property、Protocol`的,他们分别是:
`class_copyIvarList
class_copyPropertyList
class_copyProtocolList
class_copyMethodList`
set get ...亦有规律可循
+ 我们用一张图来看一下相关的API吧:
![Runtime.png](http://upload-images.jianshu.io/upload_images/1095409-0d115a91ca536741.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
+ 我们来装个逼吧,提取手机所有已经安装过的App列表,包含Bundle ID!它就是通过Runtime去获取workspace类,然后performSelector函数,这是很装逼特技:
> ````
Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
NSObject *workspace = [LSApplicationWorkspace_class performSelector:@selector(defaultWorkspace)];
NSLog(@"Installed apps:%@",[workspace performSelector:@selector(allApplications)]);
#pragma clang diagnostic pop
- 通过Class获取链接库名称
Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
const char *name = class_getImageName(LSApplicationWorkspace_class);
printf("%s\n",name);
- 补充一个Runtime的协议运用
创建一个RuntimeProtocol类
// RuntimeProtocol.h
#import <Foundation/Foundation.h>
@protocol RuntimeBaseProtocol <NSObject>
@optional
- (void)doBaseAction;
@end
@protocol RuntimeProtocol <NSObject>
@required
- (void)doRequiredAction;
@optional
- (void)doOptionalAction;
@end
@interface RuntimeProtocol : NSObject <RuntimeProtocol,RuntimeBaseProtocol>
{
NSString * name;
NSString * kind;
}
@property (copy, nonatomic) NSString * value;
@property (assign, nonatomic) int age;
+ (void)doClassMethod;
// RuntimeProtocol.m 没有东西
#import "RuntimeProtocol.h"
@implementation RuntimeProtocol
@end
打印协议名称:
unsigned int count = 0;
__unsafe_unretained Protocol ** protocols = class_copyProtocolList([RuntimeProtocol class], &count);
for (NSUInteger i = 0; i < count; i++)
{
const char * name = protocol_getName(protocols[i]);
printf("%s\n",name);
}````
结果:
`
RuntimeProtocol
RuntimeBaseProtocol
`
打印属性:
>
unsigned int countP = 0;
objc_property_t * properties = class_copyPropertyList([RuntimeProtocol class], &countP);
for (unsigned int i = 0; i < countP; i++)
{
const char * name = property_getName(properties[i]);
printf("%s\n",name);
}
结果是这样的:
`
value
age
hash ???
superclass ???
description ???
debugDescription ???
`
发现了一点不一样的东西:`hash、superclass、description、debugDescription` 其实他们是从NSObject来的,可以自己查找资料看看
###用完整的表述一下:
![Runtime2.png](http://upload-images.jianshu.io/upload_images/1095409-c85b1ef10e7abaf4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
下一篇继续: [《[RuntimeAPI》](http://www.jianshu.com/p/510ec5f75ea7)