当前位置: 首页 > news >正文

iOS主要知识点梳理回顾-4-运行时类和实例的操作

类和实例的操作

iOS 运行时(Objective-C Runtime)提供了丰富的 API 来对类进行动态操作,包括创建类、修改类的结构、添加方法、替换方法等。这对于实现动态特性、AOP(面向切面编程)、方法拦截等功能非常重要。以下举例

  • 创建并注册类(objc_allocateClassPair、objc_registerClassPair)
  • 关联对象(objc_setAssociatedObject、objc_getAssociatedObject)
  • 添加、替换方法(class_addMethod、class_replaceMethod
  • 获取类的信息(class_copyPropertyList、class_copyMethodList)

1. 创建类和元类

API:

  • objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes)创建一个新的类,并指定其父类及额外的内存空间。

  • objc_registerClassPair(Class cls)注册类以使其能够使用。

#import <objc/runtime.h>

void dynamicMethodIMP(id self, SEL _cmd) {
    NSLog(@"Dynamic method invoked!");
}

- (void)createDynamicClass {
    // 创建一个新类,继承自NSObject
    Class newClass = objc_allocateClassPair([NSObject class], "DynamicClass", 0);
    
    // 为类添加一个方法
    class_addMethod(newClass, @selector(dynamicMethod), (IMP)dynamicMethodIMP, "v@:");
    
    // 注册类
    objc_registerClassPair(newClass);
    
    // 创建实例并调用动态方法
    id instance = [[newClass alloc] init];
    [instance performSelector:@selector(dynamicMethod)];
}

动态创建类和元类在实际业务中的应用场景主要集中在以下方面:

  1. 框架封装与底层实现:如 KVO、AOP、热修复。
  2. 插件化与组件化:按需加载模块,提升扩展性。
  3. 跨平台 UI 框架支持:动态生成控件映射类。

 2. 添加属性或者关联对象

通过class_addProperty(Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount) 添加属性。

- (void)addDynamicProperty {
    objc_property_attribute_t type = { "T", "@\"NSString\"" }; // 属性类型
    objc_property_attribute_t ownership = { "C", "" }; // C代表copy
    objc_property_attribute_t backingivar = { "V", "_dynamicProperty" }; // 关联ivar

    objc_property_attribute_t attrs[] = { type, ownership, backingivar };
    
    class_addProperty([self class], "dynamicProperty", attrs, 3);
}

需要注意的是,这样添加完成之后,并不能访问属性,因为它不会自动生成访问方法(getter、setter),如果要用,还需要通过前面的添加方法来配置getter、setter。真想不通,这玩意有啥用,反正我没用过。

倒不如咱们经常用的借助类别+属性关联来的直接,不过这不是动态特性了。

/// .h文件
@interface UIImage (Help)

/// name
@property (nonatomic, copy) NSString *imageName;

@end

/// .m文件
@implementation UIViewController(Help)


- (NSString *)imageName {
    return objc_getAssociatedObject(self, @selector(imageName));
}

- (void)setImageName:(NSString *)imageName {
    objc_setAssociatedObject(self, @selector(imageName), imageName, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

@end

3. 添加、替换方法

API:

  • class_addMethod(Class cls, SEL name, IMP imp, const char *types),添加方法。

  • class_replaceMethod(Class cls, SEL name, IMP imp, const char *types),替换方法,如果方法不存在则添加。

  • method_setImplementation(Method m, IMP imp),修改方法实现。

void newMethodIMP(id self, SEL _cmd) {
    NSLog(@"New method implementation called!");
}

- (void)addOrReplaceMethod {
    Class cls = [TestClass class];
    
    SEL originalSelector = @selector(oldMethod);
    SEL newSelector = @selector(newMethod);

    // 替换方法
    Method originalMethod = class_getInstanceMethod(cls, originalSelector);
    class_replaceMethod(cls, originalSelector, (IMP)newMethodIMP, method_getTypeEncoding(originalMethod));
}

以上,替换后,我们再执行TestClass的oldMethod就会打印"New method implementation called!"

4. 获取类和方法信息

API:

  • class_getName(Class cls) 获取类名
  • class_getSuperclass(Class cls) 获取父类
  • class_getInstanceMethod(Class cls, SEL name) 获取实例方法
  • class_getClassMethod(Class cls, SEL name) 获取类方法
  • class_copyMethodList(Class cls, unsigned int *outCount) 获取方法列表
- (void)listMethodsOfClass:(Class)cls {
    unsigned int methodCount = 0;
    Method *methodList = class_copyMethodList(cls, &methodCount);
    
    for (unsigned int i = 0; i < methodCount; i++) {
        SEL methodName = method_getName(methodList[i]);
        NSLog(@"Method: %@", NSStringFromSelector(methodName));
    }
    free(methodList);
}

以上,自己实操,看看效果更好一些

相关文章:

  • MAC 系统关屏幕后电量消耗极快 Wake Requests
  • 服务器中部署大模型DeepSeek-R1 | 本地部署DeepSeek-R1大模型 | deepseek-r1部署详细教程
  • Win10环境借助DockerDesktop部署Open web UI集成DeepSeek
  • 【二叉树学习7】
  • 【NLP 21、实践 ③ 全切分函数切分句子】
  • webpack打包优化策略
  • SpringMVC环境搭建
  • 数据库——韩顺平(每日进行更新,直至更完)
  • 【Git】三、远程管理
  • Java 大视界 -- 深度洞察 Java 大数据安全多方计算的前沿趋势与应用革新(52)
  • MySQL数据库误删恢复_mysql 数据 误删
  • 物联网领域的MQTT协议,优势和应用场景
  • 大模型参数规模解析:32B中的“B“代表什么?如何影响AI性能?
  • C# CultureInfo 地区影响字符串
  • 如何通过腾讯 ima.copilot 训练自己的知识库
  • Repo、manifest以及Gerrit分别是什么?
  • C#的async异步方法里如果使用了await,那么它跟同步方法有什么区别?
  • KubeSphere 和 K8s 高可用集群离线部署全攻略
  • 解决No matching client found for package name xxx编译报错的问题
  • 软考高级《系统架构设计师》知识点(二)
  • 国家能源局通报上月投诉情况:赤峰有群众反映电费异常增高,已退费
  • 证据公布!菲律宾6人非法登上铁线礁活动
  • 烟花、美食和购物优惠都安排上了,上海多区开启热闹模式
  • 青海省林业和草原局副局长旦增主动投案,正接受审查调查
  • 流浪猫给车主造成困扰,长春一小区拟投药应对?律师:此举欠妥
  • 商超展销延长、专区专柜亮相……上海“外贸拓内销”商品与市民见面