iOS 注入三种方式详解

在 iOS 开发中,经常会遇到需要注入代码或者资源的情况。常见的注入方式有三种:运行时注入、类目注入和动态库注入。在这篇文章中,我们将通过一个小白的角度,逐步了解这三种注入方式的基本流程、实例代码及注意事项。

注入流程概览

下面是注入的基本流程及每种方法的步骤:

步骤 运行时注入 类目注入 动态库注入
1 获取目标类 创建类目文件 创建动态库项目
2 编写注入函数 在类目中实现方法 实现注入的功能
3 调用注入函数 使用该类目 加载动态库
4 测试验证 测试验证 测试验证

注入方式详解

1. 运行时注入

步骤详解:

  1. 获取目标类。
  2. 编写注入函数。
  3. 调用注入函数。
  4. 测试验证。

示例代码:

#import <objc/runtime.h>

// 目标类的方法
@interface MyTargetClass : NSObject
- (void)originalMethod;
@end

@implementation MyTargetClass
- (void)originalMethod {
    NSLog(@"Original Method");
}
@end

// 注入的方法
void myInjectedMethod(id self, SEL _cmd) {
    NSLog(@"Injected Method Called");
    // 调用原方法
    ((void (*)(id, SEL))objc_msgSend)(self, @selector(originalMethod));
}

// 注入函数
void injectMethod() {
    Class targetClass = [MyTargetClass class];
    SEL originalSelector = @selector(originalMethod);
    SEL swizzledSelector = @selector(myInjectedMethod);
    
    Method originalMethod = class_getInstanceMethod(targetClass, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(targetClass, swizzledSelector);
    
    method_exchangeImplementations(originalMethod, swizzledMethod);
}

// 在合适的地方调用注入函数
// injectMethod();

2. 类目注入

步骤详解:

  1. 创建类目文件。
  2. 在类目中实现方法。
  3. 使用该类目。
  4. 测试验证。

示例代码:

// MyTargetClass+Swizzle.h
#import "MyTargetClass.h"

@interface MyTargetClass (Swizzle)
- (void)swizzledMethod;
@end

// MyTargetClass+Swizzle.m
#import "MyTargetClass+Swizzle.h"

@implementation MyTargetClass (Swizzle)

- (void)swizzledMethod {
    NSLog(@"Swizzled Method Called");
    // 调用原方法
    [self swizzledMethod]; // 注意:会调用到自己
}

// 在使用到MyTargetClass的地方
// [MyTargetClass new].swizzledMethod();

3. 动态库注入

步骤详解:

  1. 创建动态库项目。
  2. 实现注入的功能。
  3. 加载动态库。
  4. 测试验证。

示例代码:

// DynamicLibrary.m
#import <Foundation/Foundation.h>

__attribute__((constructor))
void dynamicLibraryEntryPoint() {
    NSLog(@"Dynamic library loaded");
    // 做一些注入操作
}

// 加载动态库
// dlopen("/path/to/DynamicLibrary.dylib", RTLD_NOW);

类图说明

以下是我们讨论的三个注入方式的类图示意:

classDiagram
    class MyTargetClass {
        +void originalMethod()
    }
    class MyDynamicLibrary {
        +void dynamicLibraryEntryPoint()
    }
    class MyCategory {
        +void swizzledMethod()
    }
    MyTargetClass --> MyCategory : Injects
    MyTargetClass --> MyDynamicLibrary : Depends on

结论

通过以上步骤,我们简单了解了 iOS 三种注入方式的实现过程。每种方式都有其独特的优缺点和适用场景。在实际开发中,选择合适的注入方法对于构建高效、稳定的应用至关重要。希望以上内容能够帮助刚入行的小白开发者快速掌握 iOS 注入的相关知识与技巧。