// ------ 动态创建类, 添加成员变量, 赋值并调用动态添加的方法 -------

 @implementation ViewController

 - (void)viewDidLoad {
[super viewDidLoad]; // 动态创建People类, 继承自NSObject类
// 额外空间 未知,通常设置为 0
Class People = objc_allocateClassPair([NSObject class], "Person", ); // 以NSString*为例
// 变量size sizeof(NSString)
// 对齐 指针类型的为log2(sizeof(NSString*))
// 类型 @encode(NSString*)
// 添加_name 成员变量
BOOL flag1 = class_addIvar([People class], "_name", sizeof(NSString *), log2(sizeof(NSString *)), @encode(NSString *));
if (flag1) {
NSLog(@"添加成员变量_name成功!");
}
// 添加_age 成员变量
BOOL flag2 = class_addIvar([People class], "_age", sizeof(int), sizeof(int), @encode(int));
if (flag2) {
NSLog(@"添加成员变量_age成功!");
} // 注册方法名为say:的方法
SEL s = sel_registerName("say:"); // 添加say:方法的实现
// "v@:@"
// v表示返回值为void, i表示返回值为int
// @表示参数id(self)
// :表示SEL(_cmd)
// @表示id
class_addMethod([People class], s, (IMP)sayFunction1, "v@:@"); // 注册该类
objc_registerClassPair([People class]); // 创建类的实例
id peopleInstance = [[People alloc] init]; // KVC 动态改变 对象peopleInstance 中的实例变量
[peopleInstance setValue:@"老师" forKey:@"name"];
// Ivar nameVar = class_getInstanceVariable([People class], "_name");
// object_setIvar(peopleInstance, nameVar, @"老师"); // 从类中获取成员变量Ivar
Ivar ageIvar = class_getInstanceVariable([People class], "_age");
// 为成员变量赋值
object_setIvar(peopleInstance, ageIvar, @); // 调用 peopleInstance 对象中的 s 方法选择器对应的方法
// objc_msgSend(peopleInstance, s, @"大家好!");
((void (*)(id, SEL, id))objc_msgSend)(peopleInstance, s, @"大家好!!!"); // 当People类或者它的子类的实例还存在,则不能调用objc_disposeClassPair这个方法;因此这里要先销毁实例对象后才能销毁类;
peopleInstance = nil; // 销毁类
objc_disposeClassPair([People class]);
} // 动态添加方法的实现
void sayFunction1(id self, SEL _cmd, id some) {
Ivar ageIvar = class_getInstanceVariable([self class], "_age");
NSString *age = object_getIvar(self, ageIvar);
NSLog(@"%@岁的%@说: %@, %@", age,[self valueForKey:@"name"],some, NSStringFromSelector(_cmd));
}

// ------ 获取属性, 成员变量 以及 方法 -------

 @implementation People

 - (NSDictionary *)allProperties {
unsigned int count = ; // 获取类的所有属性, 如果没有属性count就为0
objc_property_t *properties = class_copyPropertyList([self class], &count);
NSMutableDictionary *resultDict = [@{} mutableCopy]; for (int i = ; i < count; i++) {
// 获取属性的名称和值
const char *propertyName = property_getName(properties[i]);
NSString *name = [NSString stringWithUTF8String:propertyName];
id propertyValue = [self valueForKey:name]; if (propertyValue) {
resultDict[name] = propertyValue;
} else {
resultDict[name] = @"字典的key对应的value不能为nil哦!";
}
} // 这里properties是一个数组指针, 我们需要使用free函数来释放内存
free(properties); return resultDict;
} - (NSDictionary *)allIvars {
unsigned int count = ;
NSMutableDictionary *resultDict = [@{} mutableCopy]; // 获取类的所有成员变量ivar
Ivar *ivars = class_copyIvarList([self class], &count); for (int i = ; i < count; i++) {
const char *ivarName = ivar_getName(ivars[i]);
NSString *name = [NSString stringWithUTF8String:ivarName];
id ivarValue = [self valueForKey:name]; if (ivarValue) {
resultDict[name] = ivarValue;
} else {
resultDict[name] = @"字典的key对应的value不能为nil哦~";
}
} free(ivars); return resultDict;
} - (NSDictionary *)allMethods {
unsigned int count = ;
NSMutableDictionary *resultDict = [@{} mutableCopy]; Method *methods = class_copyMethodList([self class], &count); for (int i = ; i < count; i++) {
SEL methodSEL = method_getName(methods[i]);
const char *methodName = sel_getName(methodSEL);
NSString *name = [NSString stringWithUTF8String:methodName]; unsigned int arguments = method_getNumberOfArguments(methods[i]); resultDict[name] = @(arguments - );
} free(methods); return resultDict;
} @end

// ------- 给类添加 属性 及 回调block -------

 // 在People的分类中进行

 typedef void(^CodingCallBack)();

 @interface People (Associated)

 @property (strong, nonatomic) NSNumber *associatedBust; // 胸围
@property (copy, nonatomic) CodingCallBack associatedCallBack; // 写代码 @end @implementation People (Associated) - (NSNumber *)associatedBust {
// 获取关联对象
return objc_getAssociatedObject(self, @selector(associatedBust));
} - (void)setAssociatedBust:(NSNumber *)associatedBust {
// 设置关联对象
objc_setAssociatedObject(self, @selector(associatedBust), associatedBust, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
} - (CodingCallBack)associatedCallBack {
return objc_getAssociatedObject(self, @selector(associatedCallBack));
} - (void)setAssociatedCallBack:(CodingCallBack)associatedCallBack {
objc_setAssociatedObject(self, @selector(associatedCallBack), associatedCallBack, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
} @end

// ------- 序列化 及 反序列化 -------

 @interface People2 : NSObject <NSCoding>

 @property (nonatomic, copy) NSString *name; // 姓名
@property (nonatomic, strong) NSNumber *age; // 年龄
@property (nonatomic, copy) NSString *occupation; // 职业
@property (nonatomic, copy) NSString *nationality; // 国籍 @end @implementation People2 // 反序列化数据
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super init];
if (self) {
unsigned int count = ;
Ivar *ivars = class_copyIvarList([self class], &count); for (int i = ; i < count; i++) {
const char *ivarName = ivar_getName(ivars[i]);
NSString *name = [NSString stringWithUTF8String:ivarName];
id value = [coder decodeObjectForKey:name]; [self setValue:value forKey:name];
} free(ivars);
}
return self;
} // 序列化数据
- (void)encodeWithCoder:(NSCoder *)aCoder {
unsigned int count = ;
Ivar *ivars = class_copyIvarList([self class], &count); for (int i = ; i < count; i++) {
const char *ivarName = ivar_getName(ivars[i]);
NSString *name = [NSString stringWithUTF8String:ivarName];
id ivarValue = [self valueForKey:name]; [aCoder encodeObject:ivarValue forKey:name];
} free(ivars);
} @end

// ------- Json 及 model 互转 -------

 @interface People2 : NSObject

 @property (nonatomic, copy) NSString *name; // 姓名
@property (nonatomic, strong) NSNumber *age; // 年龄
@property (nonatomic, copy) NSString *occupation; // 职业
@property (nonatomic, copy) NSString *nationality; // 国籍 // 生成model
- (instancetype)initWithDictionary:(NSDictionary *)dictionary; // 转换成字典
- (NSDictionary *)covertToDictionary; @end @implementation People2 - (instancetype)initWithDictionary:(NSDictionary *)dictionary {
self = [super init];
if (self) {
for (NSString *key in dictionary.allKeys) {
id value = dictionary[key]; SEL setter = [self propertySetterByKey:key];
if (setter) {
// objc_msgSend(self, setter, value);
((void(*)(id, SEL, id))objc_msgSend)(self, setter, value);
}
}
}
return self;
} - (NSDictionary *)covertToDictionary {
unsigned int count = ;
objc_property_t *properties = class_copyPropertyList([self class], &count); if (count != ) {
NSMutableDictionary *resultDict = [@{} mutableCopy]; for (int i = ; i < count; i++) {
const char *propertyName = property_getName(properties[i]);
NSString *key = [NSString stringWithUTF8String:propertyName]; SEL getter = [self propertyGetterByKey:key];
if (getter) {
id value = ((id (*)(id, SEL))objc_msgSend)(self, getter);
if (value) {
resultDict[key] = value;
} else {
resultDict[key] = @"字典的key对应的value不能为nil哦!";
}
}
} free(properties);
return resultDict;
} free(properties);
return nil;
} // --------- private method --------------------------------------
- (SEL)propertySetterByKey:(NSString *)key {
// set方法, 首字母大写
NSString *propertySetterName = [NSString stringWithFormat:@"set%@:", key.capitalizedString]; SEL setter = NSSelectorFromString(propertySetterName);
if ([self respondsToSelector:setter]) {
return setter;
}
return nil;
} - (SEL)propertyGetterByKey:(NSString *)key {
SEL getter = NSSelectorFromString(key);
if ([self respondsToSelector:getter]) {
return getter;
}
return nil;
} @end

// ------- 动态转换方法实现 --------

 // 添加了方法声明, 但是没有实现该方法
@interface People : NSObject - (void)sing; @end @implementation People + (BOOL)resolveInstanceMethod:(SEL)sel {
// 我们没有给People类声明sing方法, 这里我们动态添加方法
if ([NSStringFromSelector(sel) isEqualToString:@"sing"]) {
class_addMethod([self class], sel, (IMP)otherSing, "v@:");
return YES;
}
return [super resolveClassMethod:sel];
} void otherSing(id self, SEL cmd) {
NSLog(@"%@ 唱歌啦~~",((People *)self).name);
} @end

// ------- 修改方法调用对象 --------

 // Bird 类中并没有名字为 sing 的方法, 这时可以在Bird类中 将对象修改成People
@interface Bird : NSObject @property (copy, nonatomic) NSString *name; @end @implementation Bird // 第一步:我们不动态添加方法,返回NO,进入第二步;
+ (BOOL)resolveInstanceMethod:(SEL)sel {
return NO;
} // 第二部:我们不指定备选对象响应aSelector,进入第三步;
- (id)forwardingTargetForSelector:(SEL)aSelector {
return nil;
} // 第三步:返回方法选择器,然后进入第四部;
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if ([NSStringFromSelector(aSelector) isEqualToString:@"sing"]) {
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
return [super methodSignatureForSelector:aSelector];
} // 第四部:这步我们修改调用对象
- (void)forwardInvocation:(NSInvocation *)anInvocation {
// 我们改变调用对象为People
People *p = [[People alloc] init];
p.name = @"t1"; [p sing];
} @end

// ------- 修改调用的方法 -------

 @interface Bird : NSObject

 @property (copy, nonatomic) NSString *name;

 @end

 @implementation Bird

 // 第一步:我们不动态添加方法,返回NO,进入第二步;
+ (BOOL)resolveInstanceMethod:(SEL)sel {
return NO;
} // 第二部:我们不指定备选对象响应aSelector,进入第三步;
- (id)forwardingTargetForSelector:(SEL)aSelector {
return nil;
} // 第三步:返回方法选择器,然后进入第四部;
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if ([NSStringFromSelector(aSelector) isEqualToString:@"sing"]) {
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
return [super methodSignatureForSelector:aSelector];
} // 第四部:这步我们修改调用方法
- (void)forwardInvocation:(NSInvocation *)anInvocation {
[anInvocation setSelector:@selector(dance)];
// 还要指定是哪个对象的方法
[anInvocation invokeWithTarget:self];
} // 若forwardInvocation没有实现,则会调用此方法
- (void)doesNotRecognizeSelector:(SEL)aSelector {
NSLog(@"消息无法处理: %@", NSStringFromSelector(aSelector));
} - (void)dance {
NSLog(@"跳舞!! come on!~");
} @end

iOS runtime 知识点整理的更多相关文章

  1. iOS Runtime常用方法整理

    关于runtime的学习网上有很多博客,在学习之前也查过很多资料,觉得南峰子老师博客中对 runtime 的讲解挺详细的,博客地址:http://southpeak.github.io/categor ...

  2. iOS 常见知识点(三):Lock

    iOS 常见知识点(一):Runtime iOS 常见知识点(二):RunLoop 锁是最常用的同步工具.一段代码段在同一个时间只能允许被有限个线程访问,比如一个线程 A 进入需要保护代码之前添加简单 ...

  3. ACM个人零散知识点整理

    ACM个人零散知识点整理 杂项: 1.输入输出外挂 //读入优化 int 整数 inline int read(){ int x=0,f=1; char ch=getchar(); while(ch& ...

  4. 包建强的培训课程(11):iOS Runtime实战

    @import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...

  5. iOS --runtime理解

    iOS~runtime理解 Runtime是想要做好iOS开发,或者说是真正的深刻的掌握OC这门语言所必需理解的东西.最近在学习Runtime,有自己的一些心得,整理如下,一为 查阅方便二为 或许能给 ...

  6. ios runtime swizzle

    ios runtime swizzle @implementation NSObject(Extension) + (void)swizzleClassMethod:(Class)class orig ...

  7. ios runtime的相关知识

    一.iOS runtime原理 对于runtime机制,在网上找到的资料大概就是怎么去用这些东西,以及查看runtime.h头文件中的实现,当然这确实是一种很好的学习方法,但是,其实我们还是不会知道r ...

  8. iOS 学习资料整理

    iOS学习资料整理 https://github.com/NunchakusHuang/trip-to-iOS 很好的个人博客 http://www.cnblogs.com/ygm900/ 开发笔记 ...

  9. iOS Runtime 实践(1)

    很多时候我们都在看iOS开发中的黑魔法——Runtime.懂很多,但如何实践却少有人提及.本文便是iOS Runtime的实践第一篇. WebView 我们这次的实践主题,是使用针对接口编程的方式,借 ...

随机推荐

  1. (最重要)学了这么久的编程,你知道byte吗?

    在c#中,Byte b=12; 上面是合法的,因为Byte是一个字节.他的范围是0-255. 如果是 Byte b=4096;这是错的 ,必须加上强制类型转换. 这个小问题,虽然很小但是值得注意.

  2. .net实现webservice简单实例分享

    原理:WebService是一个SOA(面向服务的编程)的架构,它是不依赖于语言,不依赖于平台,可以实现不同的语言间的相互调用,通过Internet进行基于Http协议的网络应用间的交互.作用:主要用 ...

  3. Oracle数据库学习笔记

    创建表的同时插入数据:create table zhang3 as select * from zhang1;create table zhang3(id,name) as select * from ...

  4. mysql5.6.23免安装配置

    1.官网下载,并解压 2.环境变量,path下,追加mysql的bin路径D:\Program Files\mysql\bin; 3.mysql目录下的my-default.ini重命名为my.ini ...

  5. Ansible 学习笔记

    最近因为需要管理很多台机器,而这些机器又需要频繁重新安装,实在受不了Puppet需要在每个客户机上都安装一遍,于是转头开始学些Ansible.根据这段时间的使用,这个确实是神器,唯一的感觉就是相见恨晚 ...

  6. Infinite loop when using cookieless session ID on Azure

    If you use cookieless session ID and deploy them on Azure, you might get infinite loop when you quer ...

  7. Django(三)

    1.Django请求的生命周期         路由系统 -> 视图函数(获取模板+数据-->渲染) -> 字符串返回给用户   2.路由系统         /index/    ...

  8. <hr> 的18种样式

    18 Simple Styles for Horizontal Rules (hr CSS Design) Simple Styles for <hr>'s Code: <!DOCT ...

  9. Logstash学习-配置语法

    区段(section) Logstash 用{}来定义区域.区域内可以包括插件区域定义,你可以在一个区域定义多个插件,插件区域内则可以定义键值对设置. 数据类型 Logstash支持少量的数据值类型: ...

  10. python :模态对话框

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...