MXRuntimeUtils,替代 [NSObject performSelector object object ]的工具

MXRuntimeUtils是一款开源工具,旨在替代-[NSObject performSelector:],解决其仅限传两个id类型参数的问题。该工具支持多种数据类型及任意数量参数的传递,简化复杂方法调用,适用于Objective-C开发。

代码demo已在Github开源, MXRuntimeUtils, 如果能帮助到您,请帮忙点个星star哈,谢谢!

MXRuntimeUtils 是用于替换 -[NSObject performSelector:object:object:]的工具,非常容易使用!

-[NSObject performSelector:object:object:] 出现哪些问题?

如果你想使用以下方法

- (id)testMethodWithIntValue:(int)aIntValue floatValue:(float)aFloatValue charValue:(char)aCharValue sizeValue:(CGSize)aCGSizeValue pointValue:(CGPoint)aCGPointValue edgeInsetsValue:(UIEdgeInsets)anUIEdgeInsetsValue stringValue:(NSString *)aStringValue idValue:(id)anIdValue {
    
    return @[@(aIntValue), @(aFloatValue), @(aCharValue), [NSValue valueWithCGSize:aCGSizeValue], [NSValue valueWithCGPoint:aCGPointValue], [NSValue valueWithUIEdgeInsets:anUIEdgeInsetsValue], aStringValue, anIdValue];
}
复制代码

而且你想调用 -[self testMethodWithIntValue:floatValue:charValue:sizeValue:pointValue: edgeInsetsValue: stringValue:idValue:]但是用另一种方式来表达 -[self performSelector:object:object:] , 你可能感到懵逼, 因为 -[NSObject performSelector:withObject:withObject:]] 最高仅仅允许传两个值,而且还只能是id类型,那么,你怎么传基本数据类型,比如像 BOOL, char, int, float ,甚至超过两个参数的上限呢!

//[self performSelector:@selector(testMethodWithIntValue:floatValue:charValue:sizeValue:pointValue:edgeInsetsValue:stringValue:idValue:) withObject:one withObject:two ....];
复制代码

如何使用

仅仅一行代码

[MXRuntimeUtils callMethodWithTarget:self selector:@selector(testMethodWithIntValue:floatValue:charValue:
sizeValue:pointValue:edgeInsetsValue:stringValue:idValue:) argumemts:@[@1, @2.0f, [NSNumber numberWithChar:'3'], [NSValue valueWithCGSize:CGSizeMake(4, 4)], 
[NSValue valueWithCGPoint:CGPointMake(5, 5)], [NSValue valueWithUIEdgeInsets:UIEdgeInsetsMake(6, 6, 6, 6)], @"7", @"8"] returnValue:&returnValue];
复制代码

如果你的原始方法有一个返回值,那么就传一个返回值类型的指针,就像这样,如果你的返回值是一个OC对象, 注意要传一个 __autoreleasing 变量就像 这样 __autoreleasing NSString stringReturnValue, __autoreleasing id idReturnValue 而不是***NSString stringReturnValue, id idReturnValue*, 理由你可以看看这篇文章 memory management

//int returnValue 
int sumReturnValue = 0;
[MXRuntimeUtils callMethodWithTarget:self selector:@selector(sumWithAnIntValue:anotherIntValue) argumemts:@[@1, @2] returnValue:&returnValue];
//sumReturnValue = 3;

//id returnValue 
__autoreleasing id idReturnValue = nil;//avoid idReturnValue is dealloc after method invoking
[MXRuntimeUtils callMethodWithTarget:self selector:@selector(ConvertIntValueToIdType:) argumemts:@[@1] returnValue:&idReturnValue];
//idReturnValue = @1;
复制代码

之后你就可以从sumReturnValue中得到数字3, idReturnValue中得到1

屏幕截图

示例代码中的demo 截图就像这样, 但是你会有点疑惑,为什么我传的值是字符类型char 3,转换成数字类型咋变成了51了,事实上, 在 ASCIIchar value '3' 就是 数字 51, 就像 'A'65, 'a' 是 97 一样

特性

  • 自动类型检查

如果你传一个 CGPoint类型的值给一个 声明为int类型的方法参数,断言会触发,你会在Xcode控制台中得到以下截图信息

  • 允许传两个以上的参数

  • 得到任何类型的返回值

转载于:https://juejin.im/post/5c19f8a2e51d452d2e7a984f

<think> 我们正在讨论的是在C++代码中内联Objective-C代码的方法。根据引用内容,Objective-C是C语言的超集,因此理论上可以在C++中混合Objective-C代码,但需要注意一些技术细节。 关键点: 1. 文件扩展名:在苹果的开发环境中,通常使用.mm扩展名来表示Objective-C++文件(即支持C++和Objective-C混合编译)。 2. 语法兼容性:Objective-C的语法在C++中并不直接支持,但通过.mm文件,编译器(Clang)能够同时处理两种语言的语法。 3. 内联方法:在C++函数中直接编写Objective-C代码需要确保编译器能够识别,通常需要将包含Objective-C代码的部分放在.mm文件中,并且注意包含必要的头文件和框架。 步骤: 1. 将文件扩展名改为.mm:这样Xcode(或其他支持的工具)会使用Objective-C++编译器来编译该文件。 2. 在需要内联Objective-C代码的地方,可以直接编写Objective-C代码,但要注意作用域和内存管理(如果使用手动引用计数)。 3. 如果要在C++头文件中声明涉及Objective-C的类型,需要使用前置声明,并注意避免在C++头文件中直接包含Objective-C头文件(可以使用@class等)。 示例: 参考引用[3]中的代码,这是一个典型的在同一个.mm文件中混合使用Objective-C和C++的例子。 具体实现: 假设我们有一个C++类,我们想在其中调用一个Objective-C的方法。我们可以这样安排: MyCPPClass.cpp (实际上应该是.mm文件,例如MyCPPClass.mm) ```objectivec #include "MyCPPClass.h" #import <Foundation/Foundation.h> // 引入Objective-C头文件 class MyCPPClass { public: void doSomethingWithObjectiveC() { // 在这里内联Objective-C代码 @autoreleasepool { NSString *str = @"Hello from Objective-C"; NSLog(@"%@", str); } } }; ``` 注意: - 必须将文件保存为.mm扩展名,以便编译器启用Objective-C++支持。 - 在方法内部,我们使用了Objective-C的字符串字面量(@"...")和NSLog函数。 - 使用@autoreleasepool来管理内存(如果开启了自动引用计数ARC,则不需要显式的释放池,但为了兼容性,这里加上)。 高级用法: 如果需要在C++类中持有Objective-C对象,需要使用不透明类型(如void*)或者使用Objective-C的运行时特性。但更推荐使用C++的包装类来管理。 例如,在头文件中: ```cpp class MyCPPClass { private: void* objectiveCObject; // 指向一个Objective-C对象 public: MyCPPClass(); ~MyCPPClass(); void doSomething(); }; ``` 在.mm文件中: ```objectivec #include "MyCPPClass.h" #import "MyObjectiveCClass.h" MyCPPClass::MyCPPClass() { objectiveCObject = (__bridge_retained void*)[[MyObjectiveCClass alloc] init]; } MyCPPClass::~MyCPPClass() { // 释放Objective-C对象 if (objectiveCObject) { MyObjectiveCClass* obj = (__bridge_transfer MyObjectiveCClass*)objectiveCObject; obj = nil; // 实际上在转换时已经释放所有权 } } void MyCPPClass::doSomething() { // 使用Objective-C对象 MyObjectiveCClass* obj = (__bridge MyObjectiveCClass*)objectiveCObject; [obj doSomething]; } ``` 注意:这里使用了ARC的桥接转换(__bridge_retained, __bridge_transfer)来管理所有权。如果没有使用ARC,则需要使用retain和release。 总结: 在C++中内联Objective-C代码,主要通过将文件扩展名改为.mm,然后在文件中混合编写两种代码。但需要注意内存管理和类型转换。 相关问题: 1. 在混合使用Objective-C和C++时,内存管理需要注意哪些问题? 2. 如何在Objective-C++文件中同时包含C++和Objective-C的头文件? 3. 如何设计一个同时暴露给Objective-C和C++的接口? 4. Objective-C++有哪些常见的使用场景? 根据用户要求,我们需要在回答末尾添加相关问题,并且引用标记要自然地添加在相关内容的末尾。 注意:引用标记应放在引用内容的末尾,例如引用[3]中展示了混合编程的例子,我们在提到那个例子时在末尾添加[^3]。 </think> ### 在 C++ 中内联 Objective-C 代码的方法 在 C++ 中直接内联 Objective-C 代码需要特殊的文件格式和语法处理,主要通过 **Objective-C++**(文件扩展名 `.mm`)实现。以下是具体步骤和示例: --- #### 1. **使用 `.mm` 文件扩展名** Objective-C++ 文件必须使用 `.mm` 扩展名(而非 `.cpp`),让编译器识别混合语法: ```cpp // 文件名: example.mm #include <iostream> #import <Foundation/Foundation.h> // Objective-C 头文件 ``` --- #### 2. **在 C++ 函数中内联 Objective-C 代码** 通过 Objective-C 的 `@autoreleasepool` 块管理内存,并在内部编写 Objective-C 代码: ```cpp void cppFunction() { // Objective-C 代码内联 @autoreleasepool { NSString *objcStr = @"Hello from Objective-C"; NSLog(@"%@", objcStr); // 调用 Objective-C 方法 // 访问 C++ 变量 int cppVar = 42; NSString *combined = [NSString stringWithFormat:@"C++ var: %d", cppVar]; NSLog(@"%@", combined); } } ``` --- #### 3. **混合使用 C++ 类和 Objective-C 对象** 在 C++ 类中持有 Objective-C 对象时,需要使用 `void*` 类型转换(需配合 ARC 内存管理): ```cpp class CppClass { private: void* objectiveCObject; // 存储 Objective-C 对象指针 public: CppClass() { // 创建 Objective-C 对象 objectiveCObject = (__bridge_retained void*)[[NSObject alloc] init]; } ~CppClass() { // 释放 Objective-C 对象 (ARC) id obj = (__bridge_transfer id)objectiveCObject; obj = nil; } void callObjectiveCMethod() { id obj = (__bridge id)objectiveCObject; [obj performSelector:@selector(description)]; // 调用 ObjC 方法 } }; ``` --- #### 4. **在 Objective-C 中调用 C++ 代码** 反向调用时,直接在 Objective-C 方法中使用 C++ 代码: ```objectivec // Objective-C++ (.mm 文件) @implementation MyObjCClass - (void)objcMethod { // 内联 C++ 代码 std::vector<int> cppVector = {1, 2, 3}; std::cout << "Vector size: " << cppVector.size() << std::endl; } @end ``` --- #### ⚠️ 关键注意事项 1. **内存管理**: - 使用 `@autoreleasepool` 避免内存泄漏 - C++ 析构函数中需显式释放 Objective-C 对象(如上例的 `__bridge_transfer`) - 推荐启用 **ARC (Automatic Reference Counting)** 2. **类型转换**: - Objective-C 对象 → C++:`void* obj = (__bridge_void*)objectiveCObject` - C++ → Objective-C:`id obj = (__bridge id)cppPointer` 3. **头文件隔离**: - 在 `.h` 头文件中避免混合语法,仅声明接口 - 在 `.mm` 实现文件中编写混合逻辑[^3] 4. **命名规范**: - C++ 代码使用 `snake_case` - Objective-C 使用 `camelCase`(方法名以 `-` 或 `+` 开头)[^3] --- ### 典型应用场景 1. **跨平台库开发**:C++ 核心逻辑 + Objective-C 实现平台特定功能(如 macOS/iOS 的 GUI)[^3] 2. **游戏引擎**:C++ 游戏逻辑内调用 Objective-C 的 Metal 图形 API 3. **性能优化**:关键路径用 C++ 编写,通过 Objective-C 调用系统服务 > 通过 Objective-C++ 混合编程,既能利用 C++ 的性能和跨平台能力,又能直接调用 Apple 的原生 API[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值