关于 method_exchangeImplementations 不同 class 的交换方法

about method_exchangeImplementations exchange method in different class

@implementation zzFlowMonitor

......

void applicationFlowMonitor_original(id selfApp, SEL selector,UIApplication *app, CH_T completionHandler)
{
    NSLog(@"applicationFlowMonitor_original to do something...");
    completionHandler(UIBackgroundFetchResultNewData);
}

-(void) applicationFlowMonitor_swizzling:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {

    [[zzFlowMonitor shareInstance] refreshBackFetchHandle];
    NSLog(@"applicationFlowMonitor_swizzling to do something...");

    //call performFetchWithCompletionHandler delegate in  appDelegate.
    //an error occurred.*********************************************
    [self applicationFlowMonitor_swizzling:application performFetchWithCompletionHandler:completionHandler];

}

-(void)startFlowMonitor:(Class)cla NS_AVAILABLE_IOS(7_0)
{
    static dispatch_once_t oncetoken;
    dispatch_once(&oncetoken, ^{

        [[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];

        Method performFetchWCH  = class_getInstanceMethod(cla, @selector(application:performFetchWithCompletionHandler:));

        BOOL didAddMethod = class_addMethod(cla, @selector(application:performFetchWithCompletionHandler:), (IMP)applicationFlowMonitor_original, method_getTypeEncoding(performFetchWCH));
        if(!didAddMethod){

            SEL swizzledSelector = @selector(applicationFlowMonitor_swizzling:performFetchWithCompletionHandler:);
            Method swizzledMethod  = class_getInstanceMethod([zzFlowMonitor class], swizzledSelector);
            method_exchangeImplementations(performFetchWCH, swizzledMethod);
    }

});
}

@end

在AppDelegate.h文件中打击: @implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [[zzFlowMonitor shareInstance] startFlowMonitor:[AppDelegate class]];
    return YES;
}

- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)  (UIBackgroundFetchResult))completionHandler {    
    NSLog(@"application to do something...");
    completionHandler(UIBackgroundFetchResultNewData);
}

@end

报错信息一击:

2015-08-10 14:26:44.256 FlowHome[18120:3350484] -[AppDelegate applicationFlowMonitor_swizzling:performFetchWithCompletionHandler:]: unrecognized selector sent to instance 0x7fc8386077f0
2015-08-10 14:26:44.259 FlowHome[18120:3350484] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[AppDelegate applicationFlowMonitor_swizzling:performFetchWithCompletionHandler:]: unrecognized selector sent to instance 0x7fc8386077f0'
*** First throw call stack:
(
    0   CoreFoundation                      0x0000000105da0c65     __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x0000000105a39bb7 objc_exception_throw + 45
    2   CoreFoundation                      0x0000000105da80ad -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
    3   CoreFoundation                      0x0000000105cfe13c ___forwarding___ + 988
    4   CoreFoundation                      0x0000000105cfdcd8 _CF_forwarding_prep_0 + 120
    5   FlowHome                            0x00000001053dbfd5 -[zzFlowMonitor applicationFlowMonitor_swizzling:performFetchWithCompletionHandler:] + 197
    6   UIKit                               0x00000001061a8c59 -[UIApplication _handleNonLaunchSpecificActions:forScene:withTransitionContext:] + 671
    7   UIKit                               0x00000001061ace31 __88-[UIApplication _handleApplicationLifecycleEventWithScene:transitionContext:completion:]_block_invoke + 196
    8   UIKit                               0x00000001061acd5e -[UIApplication _handleApplicationLifecycleEventWithScene:transitionContext:completion:] + 349
    9   UIKit                               0x00000001061977ba -[UIApplication scene:didUpdateWithDiff:transitionContext:completion:] + 486
    10  FrontBoardServices                  0x00000001088485e5 __31-[FBSSerialQueue performAsync:]_block_invoke_2 + 21
    11  CoreFoundation                      0x0000000105cd441c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    12  CoreFoundation                      0x0000000105cca165 __CFRunLoopDoBlocks + 341
    13  CoreFoundation                      0x0000000105cc9f25 __CFRunLoopRun + 2389
    14  CoreFoundation                      0x0000000105cc9366 CFRunLoopRunSpecific + 470
    15  GraphicsServices                    0x00000001091b4a3e GSEventRunModal + 161
    16  UIKit                               0x00000001061998c0 UIApplicationMain + 1282
    17  FlowHome                            0x00000001053dc22f main + 111
    18  libdyld.dylib                       0x0000000107593145 start + 1
    19  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

我知道 AppDelegate.m 中没有 applicationFlowMonitor_swizzling 方法,但我不知道如何修复它,我需要在不同的界面中替换方法。 zzFlowMonitor 是一个库,我想在我的库中挂钩后台获取事件。非常感谢。

简而言之,如果你不想这样工作,你需要改成这样:

-(void) applicationFlowMonitor_swizzling:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {

    [[zzFlowMonitor shareInstance] refreshBackFetchHandle];
    NSLog(@"applicationFlowMonitor_swizzling to do something...");

    //call performFetchWithCompletionHandler delegate in  appDelegate.
    //an error occurred.*********************************************
    [[zzFlowMonitor sharedInstance] applicationFlowMonitor_swizzling:application performFetchWithCompletionHandler:completionHandler];    
}

您正在交换这两种方法的实现,因此 self 将成为您的应用程序委托,但不会有带有签名 -(void) applicationFlowMonitor_swizzling:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler 的方法,因为您从未添加该方法。该方法在 zzFlowMonitor 中退出,但其实现将是您的应用程序委托中定义的 - (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^) (UIBackgroundFetchResult))completionHandler 之一。