一次方法调配的非理想使用

一次方法调配的非理想使用

问题

在已有工程中,如何实现在数组添加数据的同时打印此数据?

答案

可以使用子类或方法调配(method swizzled),然而,对于本问题两者都不理想,旨在讨论使用方法调配时的考虑因素

讨论

此问题最直观的思路为继承子类覆写addObject方法,但是对于已有的大型项目,很多地方使用了NSMutablearray,需要一一替换,显然并不现实。

可以使用运行时中的方法调配,方法调配的作用是将两个方法名对应的指针互换,从而实现,调用老方法(A)实现新方法(B)。同理,调用方法B,会实现方法A.

新方法可以使用分类来添加:

@implementation NSMutableArray (PrintandAddObject)
-(void)printAndAddObject:(id)object{

    NSLog(@"添加数据:%@",object);
    [self printAndAddObject:object];

}

@end

貌似递归,然而在运行期,经过方法调配后,printAndAddObject这个Method实际上对应于addObject:方法

在启动时进行方法调配,代码如下:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    Method addObject = class_getInstanceMethod([[NSMutableArray array] class], @selector(addObject:));
    Method printAndAddObject = class_getInstanceMethod([NSMutableArray class], @selector(printAndAddObject:));

    method_exchangeImplementations(addObject, printAndAddObject);

    return YES;
}

代码添加完毕,有必要讲解一处知识点,如果细看两个Method的第一个参数,是不一样的,老方法的是[[NSMutableArray array] class],新方法的是[NSMutableArray class].

新方法是使用类目为NSMutalbeArray添加的,必然是NSMutalbeArray这个类的方法,使用没有歧义.

对于老方法为什么使用[[NSMutableArray array] class],而不是[NSMutableArray class]呢?这是因为两者获取到的类并不一样,[[NSMutableArray array] class]是获取到的实例化的对象的类,这个类并不是NSMutableArry 而是__NSArrayM,这个类并没有暴露给你,这就涉及到了类簇的概念。简单讲就是NSMutableArray是抽象类工厂,隐藏了很多真正的类。

这一点很重要,很多人初学方法调配时,很有可能调入这个坑里,所以特意提出。

到此为止,貌似可以实现需求,但是前面说过这个效果也并不理想,为什么这么说呢?因为系统很多地方用到了NSMutablearray,譬如手势,Gesture,等,这样控制台会打印很多噪音,使我们想要的东西埋没其中。我拷贝一份打印信息,放在最后,可以参考。

小小总结:正常使用方法调配,是能实现个性化需求的,但是一些类,并非只有我们手动调用,内部也会调用,使用时,需要考虑一下。

以下是点击button,为一个数组添加字符串@“####first”时的打印,确实打印了相关数据:

2016-07-06 00:08:06.991 PrintData[18983:1725090]添加数据:####first

但是由于系统调用的缘故,噪音太多,所以说使用效果不理想

2016-07-06 00:08:06.883 PrintData[18983:1725090] 添加数据:<UIStatusBarWindow: 0x7f8922c18ab0; frame = (0 0; 414 736); opaque = NO; gestureRecognizers = <NSArray: 0x7f8922c1e7e0>; layer = <UIWindowLayer: 0x7f8922c1a3d0>>
2016-07-06 00:08:06.883 PrintData[18983:1725090] 添加数据:<UIWindow: 0x7f8922f11000; frame = (0 0; 414 736); autoresize = W+H; gestureRecognizers = <NSArray: 0x7f8922f123c0>; layer = <UIWindowLayer: 0x7f8922f10670>>
2016-07-06 00:08:06.885 PrintData[18983:1725090] 添加数据:<UIStatusBar: 0x7f8924801000; frame = (0 0; 414 20); opaque = NO; autoresize = W+BM; layer = <CALayer: 0x7f8922f04df0>>
2016-07-06 00:08:06.886 PrintData[18983:1725090] 添加数据:<UITouchData: 0x7f8922e8d020>
2016-07-06 00:08:06.887 PrintData[18983:1725090] 添加数据:<_UISystemGestureGateGestureRecognizer: 0x7f8922f118e0; state = Possible; delaysTouchesEnded = NO; view = <UIWindow 0x7f8922f11000>>
2016-07-06 00:08:06.887 PrintData[18983:1725090] 添加数据:<_UISystemGestureGateGestureRecognizer: 0x7f8922f11e70; state = Possible; delaysTouchesBegan = YES; delaysTouchesEnded = NO; view = <UIWindow 0x7f8922f11000>>
2016-07-06 00:08:06.890 PrintData[18983:1725090] 添加数据:<UITouch: 0x7f8922f16fd0> phase: Began tap count: 1 window: <UIWindow: 0x7f8922f11000; frame = (0 0; 414 736); autoresize = W+H; gestureRecognizers = <NSArray: 0x7f8922f123c0>; layer = <UIWindowLayer: 0x7f8922f10670>> view: <UIButton: 0x7f8922c0b5c0; frame = (100 100; 100 100); opaque = NO; layer = <CALayer: 0x7f8922c20550>> location in window: {139, 167} previous location in window: {139, 167} location in view: {39, 67} previous location in view: {39, 67}
2016-07-06 00:08:06.891 PrintData[18983:1728813] 添加数据:<__NSMallocBlock__: 0x7f8922d25560>
2016-07-06 00:08:06.900 PrintData[18983:1725090] 添加数据:<UIStatusBarWindow: 0x7f8922c18ab0; frame = (0 0; 414 736); opaque = NO; gestureRecognizers = <NSArray: 0x7f8922c1e7e0>; layer = <UIWindowLayer: 0x7f8922c1a3d0>>
2016-07-06 00:08:06.900 PrintData[18983:1725090] 添加数据:<UIWindow: 0x7f8922f11000; frame = (0 0; 414 736); autoresize = W+H; gestureRecognizers = <NSArray: 0x7f8922f123c0>; layer = <UIWindowLayer: 0x7f8922f10670>>
2016-07-06 00:08:06.951 PrintData[18983:1725090] 添加数据:<UIStatusBarWindow: 0x7f8922c18ab0; frame = (0 0; 414 736); opaque = NO; gestureRecognizers = <NSArray: 0x7f8922c1e7e0>; layer = <UIWindowLayer: 0x7f8922c1a3d0>>
2016-07-06 00:08:06.951 PrintData[18983:1725090] 添加数据:<UIWindow: 0x7f8922f11000; frame = (0 0; 414 736); autoresize = W+H; gestureRecognizers = <NSArray: 0x7f8922f123c0>; layer = <UIWindowLayer: 0x7f8922f10670>>
2016-07-06 00:08:06.991 PrintData[18983:1725090] 添加数据:####first
2016-07-06 00:08:06.991 PrintData[18983:1725090] 添加数据:<UITouch: 0x7f8922c0c6f0> phase: Ended tap count: 1 window: <UIWindow: 0x7f8922f11000; frame = (0 0; 414 736); autoresize = W+H; gestureRecognizers = <NSArray: 0x7f8922f123c0>; layer = <UIWindowLayer: 0x7f8922f10670>> view: <UIButton: 0x7f8922c0b5c0; frame = (100 100; 100 100); opaque = NO; layer = <CALayer: 0x7f8922c20550>> location in window: {139, 167} previous location in window: {139, 167} location in view: {39, 67} previous location in view: {39, 67}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值