xml地图|网站地图|网站标签 [设为首页] [加入收藏]

【奥门金沙手机娱乐网址】iOS-Runtime知识点整理,ios-runtime知识点

时间:2019-11-29 03:41来源:计算机
iOS-Runtime知识点收拾,ios-runtime知识点 正文目录 1.Runtime简介 2.Runtime相关的头文件 3.工夫点和利用项景 3_1.获取属性成员变量列表 3_2.置换方法达成 3_3.类对象的关系对象,假属性 3_4.动态增

iOS-Runtime知识点收拾,ios-runtime知识点

正文目录

  • 1.Runtime简介
  • 2.Runtime相关的头文件
  • 3.工夫点和利用项景
    • 3_1.获取属性成员变量列表
    • 3_2.置换方法达成
    • 3_3.类对象的关系对象,假属性
    • 3_4.动态增进方法,拦截未达成的艺术
    • 3_5.动态创制三个类
  • 4.面试题

-1.Runtime简要介绍 回到顶上部分

1.Runtime简介

因为Objc是一门动态语言,所以它总是想办法把一些说了算职业从编写翻译连接推迟到运转时。也正是说唯有编写翻译器是非常不足的,还需求三个运作时系统 (runtime system卡塔尔(قطر‎ 来施行编写翻译后的代码。那就是 Objective-C Runtime 系统设有的含义,它是后生可畏体Objc运营框架的一块基石。

Runtime其实有五个本子:“modern”和 “legacy”。大家今后用的 Objective-C 2.0 接收的是当今(Modern卡塔尔国版的Runtime系统,只可以运营在 iOS 和 OS X 10.5 之后的62个人程序中。而OS X较老的叁16位程序仍利用 Objective-C 1中的(早先时代)Legacy 版本的 Runtime 系统。那四个本子最大的界别在于当您改正叁个类的实例变量的构造时,在开始的一段时期版本中您须要再行编译它的子类,而后天版就无需。

Runtime基本是用C和汇编写的,可以知道苹果为了动态系统的敏捷而作出的大力。你能够在这里地下到苹果维护的开源代码。苹果和GNU各自维护八个开源的runtime版本,那三个本子之间都在竭力的保持意气风发致。

-2.Runtime相关的头文件 回到最上端

2.Runtime相关的头文件

ios的sdk中 usr/include/objc文件夹下边有那般几个文件

List.h
NSObjCRuntime.h
NSObject.h
Object.h
Protocol.h
a.txt
hashtable.h
hashtable2.h
message.h
module.map
objc-api.h
objc-auto.h
objc-class.h
objc-exception.h
objc-load.h
objc-runtime.h
objc-sync.h
objc.h
runtime.h

都以和平运动转时有关的头文件,个中重流年用的函数定义在message.h和runtime.h这多个文本中。 在message.h中第生龙活虎饱含了有的向目的发送音讯的函数,那是OC对象方法调用的底层完毕。 runtime.h是运作时最根本的文本,当中满含了对运营时举办操作的艺术。 首要富含:

1.操作对象的品类的定义

/// An opaque type that represents a method in a class definition. 一个类型,代表着类定义中的一个方法
typedef struct objc_method *Method;

/// An opaque type that represents an instance variable.代表实例(对象)的变量
typedef struct objc_ivar *Ivar;

/// An opaque type that represents a category.代表一个分类
typedef struct objc_category *Category;

/// An opaque type that represents an Objective-C declared property.代表OC声明的属性
typedef struct objc_property *objc_property_t;

// Class代表一个类,它在objc.h中这样定义的  typedef struct objc_class *Class;
struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;

这一个品种的概念,对二个类进行了完全的解释,将类定义也许目的的每贰个有些都抽象为贰个品类type,对操作四个类属性和措施丰盛有益。OBJC2_UNAVAILABLE标识的天性是Ojective-C 2.0不支持的,但其实能够用响应的函数获取这么些属性,举例:假使想要获取Class的name属性,能够按如下方法得到:

Class classPerson = Person.class;
// printf("%sn", classPerson->name); //用这种方法已经不能获取name了 因为OBJC2_UNAVAILABLE
const char *cname  = class_getName(classPerson);
printf("%s", cname); // 输出:Person

2.函数的概念

对目的开展操作的格局常常以object_开头

对类举行操作的办法日常以class_开头

对类或对象的法门开展操作的秘诀平日以method_开头

对成员变量进行操作的艺术平日以ivar_开头

对品质进行操作的方法平常以property_开头开头

对协商进行操作的点子平常以protocol_开头

依赖上述的函数的前缀 能够大概精晓到层级关系。对于以objc_始发的方法,则是runtime最后的管家,能够拿走内存中类的加载音讯,类的列表,关联对象和涉及属性等操作。

譬如:使用runtime对当前的施用中加载的类举办打印,别被吓豆蔻梢头跳。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    unsigned int count = 0;
    Class *classes = objc_copyClassList(&count);
    for (int i = 0; i < count; i++) {
        const char *cname = class_getName(classes[i]);
        printf("%sn", cname);
    }
}

-3.工夫点和应用途景 回到最上端

3.本事点和利用途景

在偏下的代码中,都用到了Person类,Person类知识简单的定义了叁个成员变量和四个属性

@interface Person : NSObject
{
    @private
    float _height;
}
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
@end

3_1.拿到属性分子变量列表

归来最上部对此得到成员变量的列表能够动用class_copyIvarList函数,如若想要获取属性列表能够应用class_copyPropertyList函数,使用的演示如下:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    Class classPerson = NSClassFromString(@"Person"); // 与下面一句效果一样,可以不用导入头文件
//    Class clazz = Person.class;
    unsigned int count = 0;
    Ivar *ivarList = class_copyIvarList(classPerson, &count); // 获取成员变量数组
    for (int i = 0; i < count; i++) {
        const char *cname = ivar_getName(ivarList[i]); // 获取成员变量的名字
        NSString *name = [NSString stringWithUTF8String:cname];
        NSLog(@"%@", name);
    }
    NSLog(@"-------------------分割线------------------");
    objc_property_t *propertyList = class_copyPropertyList(classPerson, &count); // 获取属性数组
    for (int i = 0; i < count; i++) {
        const char *cname = property_getName(propertyList[i]);
        NSString *name = [NSString stringWithUTF8String:cname];
        NSLog(@"%@", name);
    }

}

以上代码的出口为:

2015-06-05 22:28:16.194 runtime终极[4192:195757] _height
2015-06-05 22:28:16.195 runtime终极[4192:195757] _age
2015-06-05 22:28:16.195 runtime终极[4192:195757] _name
2015-06-05 22:28:16.195 runtime终极[4192:195757] -------------------分割线------------------
2015-06-05 22:28:16.195 runtime终极[4192:195757] name
2015-06-05 22:28:16.195 runtime终极[4192:195757] age

缘何会有上边的输出结果,因为@property会做三份职业:
1.生成八个口疮划线的成员变量
2.生成那么些成员变量的get方法
3.生成那一个成员变量的set方法
由此会输出八个分子变量_height、_age和_name。须求注意的是属性名是不骨痿划线的,和概念时的名字如出豆蔻梢头辙。因而能够说:ivarList能够得到到@property关键字定义的属性 ,而propertyList不得以博获得成员变量。也便是:使用ivarList是能够将兼具的成员变量和质量都赢得的。

当属性是readonly的同一时间重写了getter时,这种场地依然会遭受的,比方三个天性是总括型属性,要求依赖其余属性的值计算而来。那个时候生成的口疮划线的分子变量就不在了, 通过ivarList不可能得到该属性了。由此当有这种值的时候,无论采纳ivarList依然选拔propertyList都无计可施得到全体的习性或变量。

在开展下八个话题以前:先须要弄清楚另三个难题:对于一个readonly的属性,到底是didSet+set好,依旧重写getter好?

比超多的readonly的性质是总计型的,依然是重视于其余质量,因而能够利用didSet+set,也正是在别的质量的set方法内,将本属性set。 但是didSet+set一时候完全没必要,不合乎懒加载的规规矩矩,浪费了总计本领,用重写getter的方法好有的。 因而重写getter总是会好一些。

回归正题:在KVC时,想要获取全体的成员变量和属性, 怎么办吧?

先是要打听setValue: forKeyPath:情势的最底层实现:以name属性为例
1.首先先去类的主意列表去索求有木有setName:,若是有,就径直调用[person setName:value]
2.找找有未有水肿划线的分子变量_name,如果有 _name = value;
3.找有未有成员变量name,若是有 name = value;
4.只要都未曾找到,就径直报错。
于是对此readonly的又重写了getter的习性而言:就算对propertyList的习性壹次利用kvc,就能报错,由此为保障代码平常,不能够利用propertyList的属性进行kvc;
别的:这种天性本来就是总计型的了,为何还应该有为它赋值呢,由此对它进行kvc也不合情理。
当使用ivaList时,直接就不能够获取到这种特性,因而是kvc的特级方案。再者,使用propertyList无法获取成员变量(_height卡塔尔国,不能对成员变量举办赋值。而选择ivaList是足以将该赋值的分子变量都得到的。

如上正是利用ivar依旧选用property举行kvc的实证。

话题外: 超级多类 有些成员变量 既没有暴露给外界调用的getter又尚未setter,只是用@private注解了弹指间:为啥??
测度是:是办法调用时利用的高级中学级变量,因为是跟随对象发生,不相符利用静态static,又因为外表不会动用,所以没须求给外界提供接口,不过或者有几许个点子都亟待以此量,不切合做一些变量,所以就这么定义了。

对此这种景况,要想不对这种分子变量赋值,在KVC时又有什么不可如此修改一下,通过ivarList获取,去掉propertyList中绝非的成员变量,这样就过滤掉了地点的这种成员变量了。

3_1_1.用到1:KVC字典转模型

归来顶上部分

得到属性分子列表贰个第生龙活虎的接纳正是,叁回收取模型中的属性分子变量,依据它的名字获取字典中的key然后收取字典中这些key对应的value,使用setValue: forKeyPath:办法设置值。为啥要如此,而不再采取情势setValuesForKeysWithDictionary:。因为在setValuesForKeysWithDictionary:艺术内部会实施这样三个历程
遍历字典里面包车型大巴全数key,一个一个抽取来,遍历每种key遵照以下进程
1.取出key,
2.取出key的value,即dict[key],直接给模型的质量分子变量赋值
3.怎么给模型的属性赋值,使用办法setValue:value forKeyPath:key实行赋值,这些法子的奉行进程在后边已经涉嫌。

为此,开辟中常常遇上的字典中的key比模型中多时,会身不由己的 this class is not key-value compliant for ‘xxx’其豆蔻年华bug就很好解释了,平时是因为字典中的key,比模型中的属性分子变量多。那么当模型中的属性比字典中多时,使用setValuesForKeysWithDictionary:会不不会有bug呢?经测量试验:当多出去的质量是目的数据类型时,为null,当属性是宗旨数据类型时,会有三个体系私下认可值(如int为0卡塔尔国。

据此使用各样为属性赋值的措施开展KVC:

Class clazz = Person.class;
unsigned int count = 0;

Person *person = [[Person alloc]init];
NSDictionary *dict = @{@"name":@"zhangsan",@"age":@19, @"height": @1.75};

Ivar *ivars = class_copyIvarList(clazz, &count);
// NSLog(@"%tu", count); // 3
for (int i = 0; i < count; i++) {
    const char *cname = ivar_getName(ivars[i]);
    NSString *name = [NSString stringWithUTF8String:cname];
    NSString *key = [name substringFromIndex:1]; // 去掉'_'
    [person setValue:dict[key] forKey:key];
}
NSLog(@"%@", person); // 已经重写了description方法

输出是:

<Person, 0x7ff15b80f230>{ name = zhangsan, height = 1.750000, age = 19}

行使这种方法进行kvc,尽管字典中的key多的时候也不会有bug,可是新的标题应际而生了,假诺模型中的属性比字典中的key多便会师世bug而且:假诺多的是目的类型不会有bug,该属性的值为null,尽管是基本数据类型就能够出错could not set nil as the value for the key ‘xxx’。举个例子,将方面包车型地铁字典改为:

NSDictionary *dict = @{@"age":@19, @"height": @1.75}; // 去掉了name NSString类型

修正之后输出为:

<Person, 0x7f996263fbd0>{ name = (null), height = 1.750000, age = 19}

如果将字典改为:

NSDictionary *dict = @{@"name":@"zhangsan",@"age":@19}; // 去掉了height float类型

次第直接崩溃。

什么样缓解地点的bug:能够在setValue:value forKeyPath:key措施调用在此以前开展如下管理:收取属性对应的种类,假使类型是着力数据类型,value替换为默许值(如int对应私下认可值为0卡塔尔。

runtime提供的ivar_getTypeEncoding函数能够取获得属性的品种,重返值代表的意义如下:

奥门金沙手机娱乐网址 1
height是float类型对应的TypeCode是"f"由此得以开展过滤一下,代码改造如下:

Class clazz = Person.class;
unsigned int count = 0;

Person *person = [[Person alloc]init];
NSDictionary *dict = @{@"name":@"zhangsan",@"age":@19, @"height": @1.75};

Ivar *ivars = class_copyIvarList(clazz, &count);
for (int i = 0; i < count; i++) {
    const char *cname = ivar_getName(ivars[i]);
    NSString *name = [NSString stringWithUTF8String:cname];
    NSString *key = [name substringFromIndex:1];

    const char *coding = ivar_getTypeEncoding(ivars[i]); // 获取类型
    NSString *strCode = [NSString stringWithUTF8String:coding];
    id value = dict[key];
    if ([strCode isEqualToString:@"f"]) {// 判断类型是否是float
        value = @(0.0);
    }

    [person setValue:value forKey:key];
}
NSLog(@"%@", person);

与上述同类就能够健康实践了,输出为:

<Person, 0x7fc75d004a00>{ name = zhangsan, height = 0.000000, age = 19}

3_1_2.选用2:NSCoding归档和平解决档

回到最上部获取属性成员列表其它一个第意气风发的应用正是展开归档和平解决档,其规律和地点的kvc基本上同样,这里只是呈现一些代码:

- (void)encodeWithCoder:(NSCoder *)aCoder {
    unsigned int count = 0;
    Ivar *ivars = class_copyIvarList(self.class, &count);
    for (int i = 0; i < count; i++) {
        const char *cname = ivar_getName(ivars[i]);
        NSString *name = [NSString stringWithUTF8String:cname];
        NSString *key = [name substringFromIndex:1];

        id value = [self valueForKey:key]; // 取出key对应的value
        [aCoder encodeObject:value forKey:key]; // 编码
    }
}
- (id)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super init]) {
        unsigned int count = 0;
        Ivar *ivars = class_copyIvarList(self.class, &count);
        for (int i = 0; i < count; i++) {
            const char *cname = ivar_getName(ivars[i]);
            NSString *name = [NSString stringWithUTF8String:cname];
            NSString *key = [name substringFromIndex:1];

            id value = [aDecoder decodeObjectForKey:key]; // 解码
            [self setValue:value forKey:key]; // 设置key对应的value
        }
    }
    return self;    
}

3_2.沟通方法完结

重回最上端

交流方法达成的要求境况:自身创造了叁个成效性的办法,在品种中数十四遍被援用,当项目标急需发生转移时,要运用另后生可畏种作用代替这么些效果,供给是不改换旧的品类(也正是不变原本情势的落到实处卡塔尔国。

能够在类的分类中,再写多个新的办法(是顺应新的须求的卡塔尔,然后换到八个办法的得以达成。这样,在不改进项指标代码,而只是增加了新的代码 的情形下,就水到渠成了花色的更改。

调换多少个法子的贯彻日常写在类的load方法里面,因为load方法会在程序运转前加载二回,而initialize方法会在类还是子类在 第二次采纳的时候调用,当有分类的时候会调用数次。

// 程序一运行的时候调用
+ (void)load
{
 // 如果是类方法,使用的是class_getClassMethod,如果是对象方法使用的是class_getInstanceMethod
    Method methodOne = class_getInstanceMethod(self, @selector(methodOne:));
    Method methodTwo = class_getInstanceMethod(self, @selector(methodTwo:));
    // 交换两个方法的实现
    method_exchangeImplementations(methodOne, methodTwo);
}

小心的是
1.足以调换的几个主意的参数必需是非常的,参数的项目意气风发致。
2.借使在方法one的内部想要调用方法two,这个时候在方法one的个中应该用one调用,而事实上是在调用two,不然会诱致死循环。
例如:

// 交换前
- (NSString *) methodOne:(NSString *)str{
 NSLog(@"%@", [self methodTwo:str]);
 return "suc";
}
// 交换后 在方法的实现中,要注意将调用two的地方,换成自己的名字
- (NSString *) methodOne:(NSString *)str{
 NSLog(@"%@", [self methodOne:str]);
 return "suc";
}

任何三个措施都有五个首要的性质:SEL是办法的编号 ,IMP是办法的落到实处,方法的调用进度实际上去依据SEL去索求IMP。
在此个事例中,假如在调换在此以前SEL为methodOne:的不二等秘书技指向着IMP1,SEL为methodTwo的方式指向着IMP2。
换来完结实际上是在尾部是换到了点子编号的指向,也正是让methodOne:指向了IMP2,methodTwo指向了IMP1。

利用途景

3_3.类对象的涉及对象

重临最上端关联对象不是为类目的增多属性大概成员变量(因为在安装关联后也心有余而力不足通过ivarList大概propertyList获得卡塔尔(英语:State of Qatar),而是为类增多一个有关的指标,平日用于存款和储蓄类音讯,举个例子存款和储蓄类的品质列表数组,为现在字典转模型的有利。 例如,将质量的称呼存到数组中装置关联

const char* propertiesKey = "propertiesKey";
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([Person class], &count);

NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:count];

for (unsigned int i = 0; i < count; ++i) {
    Ivar pty = ivars[i];
    const char *cname = ivar_getName(ivars[i]);
    NSString *name = [NSString stringWithUTF8String:cname];
    NSString *key = [name substringFromIndex:1]; // 去掉_
    [arrayM addObject:key];
}
free(ivars);
objc_setAssociatedObject(self, propertiesKey, arrayM, OBJC_ASSOCIATION_COPY_NONATOMIC);
NSLog(@"%@", arrayM);

输出是

(
    age,
    height,
    name
)

objc_setAssociatedObject主意的参数解释:

第三个参数id object, 当前目的
第三个参数const void *key, 关联的key,是c字符串
其多少个参数id value, 被提到的对象
第八个参数objc_AssociationPolicy policy关联引用的平整,取值有以下两种:

enum {
   OBJC_ASSOCIATION_ASSIGN = 0,
   OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,
   OBJC_ASSOCIATION_COPY_NONATOMIC = 3,
   OBJC_ASSOCIATION_RETAIN = 01401,
   OBJC_ASSOCIATION_COPY = 01403
};

尽管想要获取已经提到的靶子,通过key获得就可以

NSArray *pList = objc_getAssociatedObject(Person, propertiesKey);

能够将上述二种操作封装起来,为Person类扩张二个properties类方法,封装上面包车型客车操作,用于方便获取类的性质列表。

const char* propertiesKey = "propertiesKey";

@implementation Person
+ (NSArray *)properties {
    // 如果已经关联了,就依据key取出被关联的对象并返回
    NSArray *pList = objc_getAssociatedObject(self, propertiesKey);
    if (pList != nil) {
        return pList;
    }
    // 如果没有关联,则设置关联对象,并将对象返回
    unsigned int count = 0;
    Ivar *ivars = class_copyIvarList([self class], &count);

    NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:count];

    for (unsigned int i = 0; i < count; ++i) {
        Ivar pty = ivars[i];
        const char *cname = ivar_getName(ivars[i]);
        NSString *name = [NSString stringWithUTF8String:cname];
        NSString *key = [name substringFromIndex:1];
        [arrayM addObject:key];
    }
    free(ivars);
    objc_setAssociatedObject(self, propertiesKey, arrayM, OBJC_ASSOCIATION_COPY_NONATOMIC);
    return arrayM.copy;
}
@end

3_4.动态增加方法,拦截未贯彻的法门

归来最上端 种种类都有都有须臾间五个类措施(来自NSObject卡塔尔(قطر‎
+ (BOOL)resolveClassMethod:(SEL)sel
+ (BOOL)resolveInstanceMethod:(SEL)sel
以上五个多少个接收于类情势,多少个适用于对象方法。在代码中调用未有落到实处的章程时,也正是sel标志的措施未有完毕都会现调用这七个艺术中的叁个(借使是类措施就调用第二个,借使是指标方法就调用第二个卡塔尔国拦截。 平日的做法是在resolve的此中钦定sel对应的IMP,从而成就措施的动态创造和调用五个进程,也足以不点名IMP打字与印刷错误消息后一贯回到。

假如在Person类中从未-sayHi那几个措施,假诺对象p使用[p performSelector:@selector(sayHi) withObject:nil];那么就能必需通过Person类的resolveInstanceMethod:(SEL)sel主意,在那间为-sayHi钦定达成。

void abc(id self, SEL _cmd){
    NSLog(@"%@说了hello", [self name]);
}

@implementation Person

//动态添加方法:在resolve中添加相应的方法,注意是类方法还是对象方法。
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    if ([NSStringFromSelector(sel) isEqualToString:@"sayHi"]) {
        class_addMethod(self, sel, abc, "[email protected]:"); // 为sel指定实现为abc
    }
    return YES;
}
@end

对落到实处(abc卡塔尔的前多个参数的辨证

各样方法的个中都暗中认可满含三个参数,被称作隐式参数
id类型self(代表类或对象卡塔尔(قطر‎和SEL类型的_cmd(方法编号卡塔尔国

class_addMethod函数参数的意思:

率先个参数Class cls, 类型
第4个参数SEL name, 被解析的不二诀要
其七个参数 IMP imp, 内定的贯彻
第八个参数const char *types,方法的门类,具体参照类型的codeType那张图,但是要注意一点:Since the function must take at least two arguments—self and _cmd, the second and third characters must be “@:” (the first character is the return type卡塔尔.译为:因为函数必需至少有七个参数self和_cmd,第四个和第多个字符必须是“@:”。假设想要再追加参数,就足以从达成的第三个参数算起,看上边包车型的士例子就精晓。
返回值:YES if the method was found and added to the receiver, otherwise NO.

为-sayHi方法的落实扩展参数

调用时:

Person *p = [[Person alloc] init];

p.name = @"zhangsan";
p.age = 10;
[p performSelector:@selector(sayHi:) withObject:@"world"]; // 增加了一个参数,多了冒号

对Person类中的代码做了改善

void abc(id self, SEL _cmd, NSString *content){ // 增加了一个参数content
    NSLog(@"%@说了hello%@", [self name], content);
}

@implementation Person

//动态添加方法:在resolve中添加相应的方法,注意是类方法还是对象方法。
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    if ([NSStringFromSelector(sel) isEqualToString:@"sayHi:"]) {
        class_addMethod(self, sel, abc, "[email protected]:@"); // 增加了一个对象类型参数 增加了@
    }
    return YES;
}
@end

输出为:

zhangsan说了helloworld

3_5.动态成立二个类

归来最上部动态创立三个类,为那一个类增多成员变量和艺术,并创造那么些类型的指标:

#import "ViewController.h"
#import <objc/runtime.h>
#import <objc/message.h>
#import "Person.h"

static void printSchool(id self, SEL _cmd) {
    NSLog(@"我的学校是%@", [self valueForKey:@"schoolName"]);
}

@implementation ViewController

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    Class classStudent = objc_allocateClassPair(Person.class, "Student", 0);

    // 添加一个NSString的变量,第四个参数是对其方式,第五个参数是参数类型
    if (class_addIvar(classStudent, "schoolName", sizeof(NSString *), 0, "@")) {
        NSLog(@"添加成员变量schoolName成功");
    }

    // 为Student类添加方法 "[email protected]:"这种写法见参数类型连接
    if (class_addMethod(classStudent, @selector(printSchool), (IMP)printSchool, "[email protected]:")) {
        NSLog(@"添加方法printSchool:成功");
    }

    // 注册这个类到runtime系统中就可以使用他了
    objc_registerClassPair(classStudent); // 返回void



    // 使用创建的类
    id student = [[classStudent alloc] init];
    NSString *schoolName = @"清华大学";
    // 给刚刚添加的变量赋值
    // object_setInstanceVariable(student, "schoolName", (void *)&str);在ARC下不允许使用
    [student setValue:schoolName forKey:@"schoolName"];
    // 调用printSchool方法,也就是给student这个接受者发送printSchool:这个消息
//    objc_msgSend(student, "printSchool"); // 我尝试用这种方法调用但是没有成功
    [student performSelector:@selector(printSchool) withObject:nil]; // 动态调用未显式在类中声明的方法

}
@end

出口的结果是:

添加成员变量schoolName成功
添加方法printSchool成功
我的学校是清华大学

本文目录 1.Runtime简单介绍 2.Runtime连锁的头文件 3.技巧点和利用处景 3_1.收获属性分子变量列表 3_2.交换方...

编辑:计算机 本文来源:【奥门金沙手机娱乐网址】iOS-Runtime知识点整理,ios-runtime知识点

关键词: