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)];
}
动态创建类和元类在实际业务中的应用场景主要集中在以下方面:
- 框架封装与底层实现:如 KVO、AOP、热修复。
- 插件化与组件化:按需加载模块,提升扩展性。
- 跨平台 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);
}
以上,自己实操,看看效果更好一些