You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Objective-C使用method_exchangeImplementations交换NSMutableArray方法结果异常

问题成因解答
  • 核心原因是NSMutableArray属于Foundation的类簇设计:NSMutableArray本身是抽象父类,仅定义方法接口,没有具体实现。我们通过[[NSMutableArray alloc] init]得到的实例,本质是它的私有具体子类(常见为__NSArrayM)的实例,且这个私有子类已经重写了addObject:、removeObject:等所有核心方法。
  • 你代码中调用class_getInstanceMethod时传入的是NSMutableArray.class抽象父类,最终交换的是父类的方法实现。根据OC的方法查找规则,子类实例调用方法时会优先匹配自身类的方法列表中的实现,只有自身没有实现时才会查找父类的实现,因此你对父类的方法交换无法影响子类重写过的方法。
  • 你观察到removeObject:调用符合预期、addObject:调用不符合的现象,是因为NSMutableArray父类本身没有实现addObject:方法,你拿到的addMethod并不是实际运行时数组实例的addObject:实现,导致仅removeObject:的实现被替换为父类层级拿到的添加逻辑,而子类的addObject:实现完全没有被修改。
  • 交换NSString方法生效的原因:NSString同样是类簇,但你测试用的字符串实例对应的私有子类没有重写uppercaseString、lowercaseString方法,方法查找时会走到父类NSString的实现,因此你对父类的交换操作会生效。
可选解决方案

如果需要实现交换NSMutableArray的两个方法,需要针对实际运行时的私有子类做交换,示例代码如下:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // 取NSMutableArray实际对应的私有子类做交换
        Class mutableArrayClass = NSClassFromString(@"__NSArrayM");
        Method removeMethod = class_getInstanceMethod(mutableArrayClass, @selector(removeObject:));
        Method addMethod = class_getInstanceMethod(mutableArrayClass, @selector(addObject:));
        method_exchangeImplementations(addMethod, removeMethod);
        
        NSMutableArray *array = [[NSMutableArray alloc] init];
        NSObject *obj = [[NSObject alloc] init];
        [array removeObject:obj];
        NSLog(@"%lu", (unsigned long)array.count); // 输出1
        [array addObject:obj];
        NSLog(@"%lu", (unsigned long)array.count); // 输出0
    }
    return 0;
}

内容的提问来源于stack exchange,提问作者Rylaris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 17:06:04