是否有可能调剂addObject:在NSMutableArray中?

是否有可能改变NSMutableArray的addObject:方法?

这是我正在尝试。

#import <Foundation/Foundation.h> #import <objc/runtime.h> @implementation NSMutableArray (LoggingAddObject) + (void)load { Method addObject = class_getInstanceMethod(self, @selector(addObject:)); Method logAddObject = class_getInstanceMethod(self, @selector(logAddObject:)); method_exchangeImplementations(addObject, logAddObject); Method original = class_getInstanceMethod(self, @selector(setObject:atIndexedSubscript:)); Method swizzled = class_getInstanceMethod(self, @selector(swizzled_setObject:atIndexedSubscript:)); method_exchangeImplementations(original, swizzled); } - (void)logAddObject:(id)anObject { [self logAddObject:anObject]; NSLog(@"Added object %@ to array %@", anObject, self); } -(void)swizzled_setObject:(id)obj atIndexedSubscript:(NSUInteger)idx { NSLog(@"This gets called as expected!!-----"); [self swizzled_setObject:obj atIndexedSubscript:idx]; } 

我可以调用像setObject:atIndexedSubscript一些方法:但我担心,我不能做的addObject:和其他人。 我认为下面不能混淆? 有人能解释为什么吗? 我做错了什么和/或解决这个问题?

 /**************** Mutable Array ****************/ @interface NSMutableArray : NSArray - (void)addObject:(id)anObject; - (void)insertObject:(id)anObject atIndex:(NSUInteger)index; - (void)removeLastObject; - (void)removeObjectAtIndex:(NSUInteger)index; - (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject; @end 

你可以试试NSProxy ,但是我不build议你在生产代码中使用它,因为:

  • 破坏一些东西(一些框架可能需要NSMutableArray在添加nil时候抛出exception,以防止更严重的错误,即快速失败 )
  • 它很慢

如果你真的想避免nil检查,我build议你做一个NSMutableArray的子类,并在你的代码中的任何地方使用它。 但真的吗? 有很多使用NSMutableArray ObjC代码,其中大多数不需要这个function。 那么为什么你这么特别?

 #import <objc/runtime.h> @interface XLCProxy : NSProxy + (id)proxyWithObject:(id)obj; @end @implementation XLCProxy { id _obj; } + (void)load { Method method = class_getClassMethod([NSMutableArray class], @selector(allocWithZone:)); IMP originalImp = method_getImplementation(method); IMP imp = imp_implementationWithBlock(^id(id me, NSZone * zone) { id obj = ((id (*)(id,SEL,NSZone *))originalImp)(me, @selector(allocWithZone:), zone); return [XLCProxy proxyWithObject:obj]; }); method_setImplementation(method, imp); } + (id)proxyWithObject:(id)obj { XLCProxy *proxy = [self alloc]; proxy->_obj = obj; return proxy; } - (void)forwardInvocation:(NSInvocation *)invocation { [invocation setTarget:_obj]; [invocation invoke]; const char *selname = sel_getName([invocation selector]); if ([@(selname) hasPrefix:@"init"] && [[invocation methodSignature] methodReturnType][0] == '@') { const void * ret; [invocation getReturnValue:&ret]; ret = CFBridgingRetain([XLCProxy proxyWithObject:CFBridgingRelease(ret)]); [invocation setReturnValue:&ret]; } } -(NSMethodSignature *)methodSignatureForSelector:(SEL)sel { return [_obj methodSignatureForSelector:sel]; } - (Class)class { return [_obj class]; } - (void)addObject:(id)obj { [_obj addObject:obj ?: [NSNull null]]; } - (BOOL)isEqual:(id)object { return [_obj isEqual:object]; } - (NSUInteger)hash { return [_obj hash]; } // you can add more methods to "override" methods in `NSMutableArray` @end 

 @interface NSMutableArrayTests : XCTestCase @end @implementation NSMutableArrayTests - (void)testExample { NSMutableArray *array = [NSMutableArray array]; [array addObject:nil]; [array addObject:@1]; [array addObject:nil]; XCTAssertEqualObjects(array, (@[[NSNull null], @1, [NSNull null]])); } @end 

你可以遍历所有注册的类,检查当前类是否是NSMutableArray的子类,如果是的话,debugging。

我会build议反对它,而不是在个案的基础上采取行动,有更多的可预测的行为 – 你永远不知道哪些其他的系统框架依赖于这种特定的行为(例如,我可以看到CoreData如何依靠这种特定的行为)

您可以按照以下方式调整任何NSMutableArray方法:

 @implementation NSMutableArray (Swizzled) + (void)load { Method orig = class_getInstanceMethod(NSClassFromString(@"__NSArrayM"), NSSelectorFromString(@"addObject:")); Method override = class_getInstanceMethod(NSClassFromString(@"__NSArrayM"), @selector(addObject_override:)); method_exchangeImplementations(orig, override); } - (void)addObject_override:(id)anObject { [self addObject_override:anObject]; NSLog(@"addObject called!"); }