1、runtime 是什么?
Runtime又叫运行时,是一套底层的C语言 API,其为iOS内部的核心之一,我们平时编写的OC代码,底层都是基于它来实现的。我们需要了解的是 Objective-C 是一门动态语言,它会将一些工作放在代码运行时才处理而并非编译时。也就是说,有很多类和成员变量在我们编译的时是不知道的,而在运行时,我们所编写的代码会转换成完整的确定的代码运行
2、runtime 可以干什么?
Runtime的特性主要是消息(方法)传递,如果消息(方法)在对象中找不到,就进行转发
3、KVC的定义
KVC(Key-value coding)键值编码,就是指在IOS的开发中,可以允许开发者通过Key名称直接访问对象的属性,或者给对象的属性赋值。而不需要调用明确的存储方法。这样就可以在运行时动态地访问和修改对象的属性。
在实现了访问器方法的类中,使用点语法和KVC访问对象其实差别不大,二者可以任意混用。但是没有访问起方法的类中,点语法无法使用,这时KVC就有优势了。
3.1 KVC常用的方法
KVC的定义都是对NSObject的扩展来实现的,Objective-C中有个显式的NSKeyValueCoding类别名,所以对于所有继承了NSObject的类型,都能使用KVC(一些纯Swift类和结构体是不支持KVC的,因为没有继承NSObject),下面是KVC最为重要的四个方法:
- (nullable id)valueForKey:(NSString *)key; //直接通过Key来取值
- (void)setValue:(nullable id)value forKey:(NSString *)key; //通过Key来设值
- (nullable id)valueForKeyPath:(NSString *)keyPath; //通过KeyPath来取值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath; //通过KeyPath来设值
Runtime和KVC的结合可以实现字典的数据模型转换
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface TestModel : NSObject
@property (nonatomic, strong)NSString *name;
@property (nonatomic, strong)NSString *sex;
@property (nonatomic, strong)NSString *phone;
@property (nonatomic, strong)NSString *address;
- (instancetype)initWithDic:(NSDictionary *)dic;
@end
NS_ASSUME_NONNULL_END
#import "TestModel.h"
#import <objc/runtime.h>// 导入运行时文件
@implementation TestModel
- (instancetype)initWithDic:(NSDictionary *)dic
{
if (self == [super init]) {
NSArray *names = [self getProperties:[self class]];
NSArray *types = [self getTypes:[self class]];
for (NSInteger i = 0; i < names.count; i ++) {
NSString *name = names[i];
NSString *type = types[i];
if ([type rangeOfString:@"NSArray"].location != NSNotFound) {
[self setValue:@[] forKey:name];
}else if ([type rangeOfString:@"NSDictionary"].location != NSNotFound) {
[self setValue:@{} forKey:name];
}else if ([type rangeOfString:@"NSString"].location != NSNotFound) {
[self setValue:@"" forKey:name];
}
}
// 字典可能是空
if (![dic isKindOfClass:[NSDictionary class]]) {
return self;
}else {
for (NSInteger i = 0; i < names.count; i ++) {
NSString *name = names[i];
// 如果字典中的值为空,赋值可能会出现问题
if (dic[name] != nil && ![dic[name] isKindOfClass:[NSNull class]]) {
if ([dic[name] isKindOfClass:[NSNumber class]]) {
[self setValue:[NSString stringWithFormat:@"%@",dic[name]] forKey:name];
}else {
[self setValue:dic[name] forKey:name];
}
}
if ([name isEqualToString:@"ID"] && dic[@"id"] != nil && ![dic[@"id"] isKindOfClass:[NSNull class]]) {
[self setValue:dic[@"id"] forKey:name];
}
if ([name isEqualToString:@"descrip"] && dic[@"description"] != nil && ![dic[@"description"] isKindOfClass:[NSNull class]]) {
[self setValue:dic[@"description"] forKey:name];
}
}
}
}
return self;
}
//返回当前类的所有属性
- (id)getProperties:(Class)cls{
// 获取当前类的所有属性
unsigned int count;// 记录属性个数
objc_property_t *properties = class_copyPropertyList(cls, &count);
// 遍历
NSMutableArray *mArray = [NSMutableArray array];
for (int i = 0; i < count; i++) {
// An opaque type that represents an Objective-C declared property.
// objc_property_t 属性类型
objc_property_t property = properties[i];
// 获取属性的名称 C语言字符串
const char *cName = property_getName(property);
// 转换为Objective C 字符串
NSString *name = [NSString stringWithCString:cName encoding:NSUTF8StringEncoding];
[mArray addObject:name];
}
return mArray.copy;
}
//返回当前类的所有属性类型
- (id)getTypes:(Class)cls{
// 获取当前类的所有属性
unsigned int count;// 记录属性个数
objc_property_t *properties = class_copyPropertyList(cls, &count);
// 遍历
NSMutableArray *mArray = [NSMutableArray array];
for (int i = 0; i < count; i++) {
// An opaque type that represents an Objective-C declared property.
// objc_property_t 属性类型
objc_property_t property = properties[i];
// 获取属性的名称 C语言字符串
const char *cName = property_getAttributes(property);
// 转换为Objective C 字符串
NSString *name = [NSString stringWithCString:cName encoding:NSUTF8StringEncoding];
[mArray addObject:name];
}
return mArray.copy;
}
在使用时只要调用这个类
NSDictionary *dic = @{@"name":@"小红",@"sex":@"女",@"phone":@"13478961265",@"address":@"长安街186号"};
TestModel *model = [[TestModel alloc] initWithDic:dic];
NSLog(@"输出:TestModel:%@",model);
打印结果

本文介绍了iOS开发中的Runtime和KVC。Runtime是一套底层API,是Objective-C动态语言的基础,主要涉及消息传递和转发。KVC则是通过Key名称动态访问和修改对象属性的技术,尤其在没有访问器方法的类中展现出优势。通过Runtime与KVC的结合,可以方便地实现字典到数据模型的转换。
1237

被折叠的 条评论
为什么被折叠?



