Runtime系列:常用API(附示例)【06】

简介: Runtime系列:常用API

一、Runtime API


1、类

1、动态创建一个类(参数:父类,类名,额外的内存空间)


Class objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes)

2、注册一个类(要在类注册之前添加成员变量)


void objc_registerClassPair(Class cls) 

3、销毁一个类


void objc_disposeClassPair(Class cls)

4、设置和获取isa指向的Class


Class object_setClass(id obj, Class cls)
Class object_getClass(id obj)

5、判断一个OC对象是否为类和元类


BOOL object_isClass(id obj)
BOOL class_isMetaClass(Class cls)

6、获取父类


Class class_getSuperclass(Class cls)

2、成员变量


1、获取一个实例变量信息


Ivar class_getInstanceVariable(Class cls, const char *name)

2、拷贝实例变量列表(最后需要调用free释放)


Ivar *class_copyIvarList(Class cls, unsigned int *outCount)

3、动态添加成员变量(已经注册的类是不能动态添加成员变量的)


BOOL class_addIvar(Class cls, const char * name, size_t size, uint8_t alignment, const char * types)

4、获取成员变量的相关信息


const char *ivar_getName(Ivar v)
const char *ivar_getTypeEncoding(Ivar v)


5、设置成员变量的值


void object_setIvar(id obj, Ivar ivar, id value)

6、获取成员变量的对象


id object_getIvar(id obj, Ivar ivar)

3、属性

1、获取一个属性


objc_property_t class_getProperty(Class cls, const char *name)

2、拷贝属性列表(最后需要调用free释放)


objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)

3、动态添加属性


BOOL class_addProperty(Class cls, const char *name, const objc_property_attribute_t *attributes,
                  unsigned int attributeCount)


4、动态替换属性


void class_replaceProperty(Class cls, const char *name, const objc_property_attribute_t *attributes,
                      unsigned int attributeCount)


5、获取属性的一些信息


const char *property_getName(objc_property_t property)
const char *property_getAttributes(objc_property_t property)

4、方法

1、获得一个实例方法、类方法


Method class_getInstanceMethod(Class cls, SEL name)
Method class_getClassMethod(Class cls, SEL name)


2、方法实现相关操作


IMP class_getMethodImplementation(Class cls, SEL name) 
IMP method_setImplementation(Method m, IMP imp)
void method_exchangeImplementations(Method m1, Method m2) 

3、拷贝方法列表(最后需要调用free释放)


Method *class_copyMethodList(Class cls, unsigned int *outCount)

4、动态添加方法


BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)

5、动态替换方法


IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)

6、获取方法的相关信息(带有copy的需要调用free去释放)


SEL method_getName(Method m)
IMP method_getImplementation(Method m)
const char *method_getTypeEncoding(Method m)
unsigned int method_getNumberOfArguments(Method m)
char *method_copyReturnType(Method m)
char *method_copyArgumentType(Method m, unsigned int index)


6、选择器相关


const char *sel_getName(SEL sel)
SEL sel_registerName(const char *str)

7、用block作为方法实现


IMP imp_implementationWithBlock(id block)
id imp_getBlock(IMP anImp)
BOOL imp_removeBlock(IMP anImp)


二、示例


1、动态创建类、添加成员变量、添加方法

#import <Foundation/Foundation.h>
void run(id self, SEL _cmd) {
    NSLog(@"_____ %@ - %@", self, NSStringFromSelector(_cmd));
}
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // 1、创建类【类型可动态赋值】
        NSString *className = [NSString stringWithFormat:@"ZMDog"];
        Class newClass = objc_allocateClassPair([NSObject class], className, 0);
        // 添加成员变量
        class_addIvar(newClass, "_age", 4, 1, @encode(int));
        class_addIvar(newClass, "_weight", 8, 1, @encode(int));
        // 添加方法
        class_addMethod(newClass, @selector(run), (IMP)run, "v@:");
        // 2、注册类
        objc_registerClassPair(newClass);
        {
           // 初始化
            id dog = [[newClass alloc] init];
            // 赋值
            [dog setValue:@10 forKey:@"_age"];
            [dog setValue:@20 forKey:@"_weight"];
            // 方法实现
            [dog run];
            // 打印结果
            NSLog(@"%@ %@", [dog valueForKey:@"_age"], [dog valueForKey:@"_weight"]);
        }
        // 3、释放类
        objc_disposeClassPair(newClass);
    }
    return 0;
}


注意:

1、成员变量一定要在注册类之前实现

2、方法objc_disposeClassPair,如果这个类或子类的实例存在,不要调用。


2、设置isa指向的类

ZMPerson.m:


#import "ZMPerson.h"
@implementation ZMPerson
- (void)run {
    NSLog(@"%s", __func__);
}
@end


ZMCar.m:


#import "ZMCar.h"
@implementation ZMCar
- (void)run {
    NSLog(@"%s", __func__);
}
@end


实现:


int main(int argc, const char * argv[]) {
    @autoreleasepool {
        ZMPerson *person = [[ZMPerson alloc] init];
        [person run];
        object_setClass(person, [ZMCar class]);
        [person run];
    }
    return 0;
}


打印结果:

[29582:563758] -[ZMPerson run]
[29582:563758] -[ZMCar run]


3、判断类和元类

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        ZMPerson *person = [[ZMPerson alloc] init];
        NSLog(@"%d %d %d",
              object_isClass(person),
              object_isClass([ZMPerson class]),
              object_isClass(object_getClass([ZMPerson class]))
              );
    }
    return 0;
}

打印结果:


[28681:543229] 0 1 1

4、成员变量【获取成员变量信息、成员变量赋值和取值、拷贝成员变量列表】

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // 1、获取成员变量信息
        Ivar ageIvar = class_getInstanceVariable([ZMPerson class], "_age");
        NSLog(@"ageIvar:%s %s", ivar_getName(ageIvar), ivar_getTypeEncoding(ageIvar));
        Ivar nameIvar = class_getInstanceVariable([ZMPerson class], "_name");
        ZMPerson *person = [[ZMPerson alloc] init];
        // 2、设置成员变量的值
        object_setIvar(person, nameIvar, @"123");
        object_setIvar(person, ageIvar, (__bridge id)(void *)10);
        // 3、获取成员变量的值
        NSLog(@"person.name:%@", person.name);
        NSLog(@"person.age:%d",person.age);
        NSLog(@"==================");
        // 成员变量的数量
        unsigned int count;
        // 拷贝成员变量数组
        Ivar *ivars = class_copyIvarList([ZMPerson class], &count);
        for (int i = 0; i < count; i++) {
            // 取出i位置的成员变量
            Ivar ivar = ivars[i];
            NSLog(@"%s %s", ivar_getName(ivar), ivar_getTypeEncoding(ivar));
        }
        // 释放成员变量
        free(ivars);
    }
    return 0;
}


self.textF.placeholder = @"请填写";
// 直接修改私有成员变量,在iOS13以后被禁止
//  [self.textF setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];
// =================
// 要改成如下方式实现:
// 获取成员变量
Ivar placeholderIvar =  class_getInstanceVariable([UITextField class], "_placeholderLabel");
UILabel *placeholderLabel = object_getIvar(self.textF, placeholderIvar);
//给变量赋值
placeholderLabel.textColor = [UIColor redColor];


5、数模转换

NSObject+Json.h:
#import <Foundation/Foundation.h>
@interface NSObject (Json)
+ (instancetype)zm_objectWithJson:(NSDictionary *)json;
@end


NSObject+Json.m:


#import "NSObject+Json.h"
#import <objc/runtime.h>
@implementation NSObject (Json)
+ (instancetype)zm_objectWithJson:(NSDictionary *)json
{
    id obj = [[self alloc] init];
    unsigned int count;
    // 拷贝示例变量列表
    Ivar *ivars = class_copyIvarList(self, &count);
    for (int i = 0; i < count; i++) {
        // 取出i位置的成员变量
        Ivar ivar = ivars[i];
        // 获取成员变量名称
        NSMutableString *name = [NSMutableString stringWithUTF8String:ivar_getName(ivar)];
        // 移除成员变量首个下划线【_】
        [name deleteCharactersInRange:NSMakeRange(0, 1)];
        // 设值
        id value = json[name];
        if ([name isEqualToString:@"ID"]) {
            value = json[@"id"];
        }
        // 通过KVC赋值
        [obj setValue:value forKey:name];
    }
    // 释放变量
    free(ivars);
    return obj;
}
@end


ZMPerson.h:


#import <Foundation/Foundation.h>
@interface ZMPerson : NSObject
@property (assign, nonatomic) int ID;
@property (assign, nonatomic) int weight;
@property (assign, nonatomic) int age;
@property (copy, nonatomic) NSString *name;
- (void)run;
@end


ZMPerson.m:


#import "ZMPerson.h"
@implementation ZMPerson
- (void)run {
    NSLog(@"%s", __func__);
}
@end


【main.m】实现:


#import <Foundation/Foundation.h>
#import "ZMPerson.h"
#import "NSObject+Json.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // 字典转模型
        NSDictionary *json = @{
                               @"id" : @10,
                               @"age" : @20,
                               @"weight" : @80,
                               @"name" : @"Tony"
                               };
        ZMPerson *person = [ZMPerson zm_objectWithJson:json];
    }
    return 0;
}


6、方法交换

ZMPerson.h:


#import <Foundation/Foundation.h>
@interface ZMPerson : NSObject
- (void)run;
- (void)test;
@end
#import "ZMPerson.h"
@implementation ZMPerson
- (void)run {
    NSLog(@"%s", __func__);
}
- (void)test {
    NSLog(@"%s", __func__);
}
@end


main.m 实现:


#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import "ZMPerson.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        ZMPerson *person = [[ZMPerson alloc] init];
        Method runMethod = class_getInstanceMethod([ZMPerson class], @selector(run));
        Method testMethod = class_getInstanceMethod([ZMPerson class], @selector(test));
        method_exchangeImplementations(runMethod, testMethod);
        [person run];
    }
    return 0;
}


打印结果:


// 代码执行的是[person run];,结果实际执行到了test中
[31079:590617] -[MJPerson test]


7、方法替代

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
void myrun() {
    NSLog(@"---myrun");
}
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        MJPerson *person = [[MJPerson alloc] init];
        class_replaceMethod([MJPerson class], @selector(run), (IMP)myrun, "v");
        class_replaceMethod([MJPerson class], @selector(run), imp_implementationWithBlock(^{
            NSLog(@"123123");
        }), "v");
        [person run];
    }
    return 0;
}
相关文章
|
22天前
|
JSON API 数据安全/隐私保护
淘宝评论API接口操作步骤详解,代码示例参考
淘宝评论API接口是淘宝开放平台提供的一项服务,通过该接口,开发者可以访问商品的用户评价和评论。这些评论通常包括评分、文字描述、图片或视频等内容。商家可以利用这些信息更好地了解消费者的需求和偏好,优化产品和服务。同时,消费者也可以从这些评论中获得准确的购买参考,做出更明智的购买决策。
|
1月前
|
API Python
【Azure Developer】分享一段Python代码调用Graph API创建用户的示例
分享一段Python代码调用Graph API创建用户的示例
51 11
|
2月前
|
API 开发工具 开发者
探究亚马逊国际获得AMAZON商品详情 API 接口功能、作用与实际应用示例
亚马逊提供的Amazon Product Advertising API或Selling Partner API,使开发者能编程访问亚马逊商品数据,包括商品标题、描述、价格等。支持跨境电商和数据分析,提供商品搜索和详情获取等功能。示例代码展示了如何使用Python和boto3库获取特定商品信息。使用时需遵守亚马逊政策并注意可能产生的费用。
|
2月前
|
JSON API 数据安全/隐私保护
拍立淘按图搜索API接口返回数据的JSON格式示例
拍立淘按图搜索API接口允许用户通过上传图片来搜索相似的商品,该接口返回的通常是一个JSON格式的响应,其中包含了与上传图片相似的商品信息。以下是一个基于淘宝平台的拍立淘按图搜索API接口返回数据的JSON格式示例,同时提供对其关键字段的解释
|
2月前
|
JSON API 数据格式
Amazon商品详情API,json数据格式示例参考
亚马逊商品详情API接口返回的JSON数据格式通常包含丰富的商品信息,以下是一个简化的JSON数据格式示例参考
|
3月前
|
机器学习/深度学习 PyTorch 算法框架/工具
揭秘深度学习中的微调难题:如何运用弹性权重巩固(EWC)策略巧妙应对灾难性遗忘,附带实战代码详解助你轻松掌握技巧
【10月更文挑战第1天】深度学习中,模型微调虽能提升性能,但常导致“灾难性遗忘”,即模型在新任务上训练后遗忘旧知识。本文介绍弹性权重巩固(EWC)方法,通过在损失函数中加入正则项来惩罚对重要参数的更改,从而缓解此问题。提供了一个基于PyTorch的实现示例,展示如何在训练过程中引入EWC损失,适用于终身学习和在线学习等场景。
162 4
揭秘深度学习中的微调难题:如何运用弹性权重巩固(EWC)策略巧妙应对灾难性遗忘,附带实战代码详解助你轻松掌握技巧
|
2月前
|
JSON API 数据格式
店铺所有商品列表接口json数据格式示例(API接口)
当然,以下是一个示例的JSON数据格式,用于表示一个店铺所有商品列表的API接口响应
|
2月前
|
JSON API 数据库
电商拍立淘按图搜索API接口,数据格式示例
电商拍立淘按图搜索API接口系列为电商平台和购物应用提供了强大的图像搜索功能,以下是其文档说明的详细参考
|
2月前
|
JSON API 数据格式
携程API接口系列,酒店景点详情请求示例参考
携程API接口系列涵盖了酒店预订、机票预订、旅游度假产品预订、景点门票预订等多个领域,其中酒店和景点详情请求是较为常用的功能。以下提供酒店和景点详情请求的示例参考
|
3月前
|
JSON API 数据安全/隐私保护
拍立淘按图搜索json数据格式示例(API接口)
拍立淘按图搜索API接口为电商平台和购物应用提供了强大的图像搜索功能,能够显著提升用户的购物体验和搜索效率。开发者可以根据自己的需求调用此接口,并处理返回的JSON格式数据来展示推荐商品