美文网首页
AFNetworking - _AFURLSessionTask

AFNetworking - _AFURLSessionTask

作者: ASkyWatcher | 来源:发表于2020-06-17 15:01 被阅读0次

    _AFURLSessionTaskSwizzling的作用就是为了解决不同iOS版本的NSURLSessionTask的继承链不一样,对resume和suspend方法作用的类也不一样而导致可能崩溃的问题

    原理是在+load方法中对各个层次的类只要实现了resume和suspend都进行方法交换,并发送出相应的通知以便我们进行处理

    + (void)load {
        /**
         WARNING: Trouble Ahead
         https://github.com/AFNetworking/AFNetworking/pull/2702
         */
        if (NSClassFromString(@"NSURLSessionTask")) {
            NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
            NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wnonnull"
            NSURLSessionDataTask *localDataTask = [session dataTaskWithURL:nil];
    #pragma clang diagnostic pop
            //获取af_resume的实现指针
            IMP originalAFResumeIMP = method_getImplementation(class_getInstanceMethod([self class], @selector(af_resume)));
            Class currentClass = [localDataTask class];
            
            //检查当前类是否有resume方法的实现
            while (class_getInstanceMethod(currentClass, @selector(resume))) {
                //获取当前类的父类
                Class superClass = [currentClass superclass];
                //当前类resume的实现
                IMP classResumeIMP = method_getImplementation(class_getInstanceMethod(currentClass, @selector(resume)));
                //父类resume的实现
                IMP superclassResumeIMP = method_getImplementation(class_getInstanceMethod(superClass, @selector(resume)));
                //如果当前类的resume实现和父类不一样,并且af_resume的方法实现和当前类的resume实现不一样(没有被交换过方法),才交换方法
                if (classResumeIMP != superclassResumeIMP &&
                    originalAFResumeIMP != classResumeIMP) {
                    [self swizzleResumeAndSuspendMethodForClass:currentClass];
                }
                currentClass = [currentClass superclass];
            }
            
            [localDataTask cancel];
            [session finishTasksAndInvalidate];
        }
    }
    

    利用runtime进行方法交换的方法

    + (void)swizzleResumeAndSuspendMethodForClass:(Class)theClass {
        Method afResumeMethod = class_getInstanceMethod(self, @selector(af_resume));
        Method afSuspendMethod = class_getInstanceMethod(self, @selector(af_suspend));
    
        // 给theClass添加一个名为af_resume的方法,使用@selector(af_resume)获取方法名,使用afResumeMethod作为方法实现
        if (af_addMethod(theClass, @selector(af_resume), afResumeMethod)) {
            af_swizzleSelector(theClass, @selector(resume), @selector(af_resume));
        }
        // 给theClass添加一个名为af_suspend的方法,使用@selector(af_suspend)获取方法名,使用afSuspendMethod作为方法实现
        if (af_addMethod(theClass, @selector(af_suspend), afSuspendMethod)) {
            af_swizzleSelector(theClass, @selector(suspend), @selector(af_suspend));
        }
    }
    
    

    相关的两个静态内联函数,一个是为类添加方法,一个是实现方法交换

    static inline void af_swizzleSelector(Class theClass, SEL originalSelector, SEL swizzledSelector) {
        Method originalMethod = class_getInstanceMethod(theClass, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(theClass, swizzledSelector);
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
    
    static inline BOOL af_addMethod(Class theClass, SEL selector, Method method) {
        return class_addMethod(theClass, selector,  method_getImplementation(method),  method_getTypeEncoding(method));
    }
    

    自己实现的af_resume和af_suspend方法

    - (void)af_resume {
        NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state");
        NSURLSessionTaskState state = [self state];
        //经过method swizzling后,af_resume已经变成之前的resume,所以此处调用af_resume就是调用系统的resume
        [self af_resume];
        
        if (state != NSURLSessionTaskStateRunning) {
            [[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidResumeNotification object:self];
        }
    }
    
    - (void)af_suspend {
        NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state");
        NSURLSessionTaskState state = [self state];
        //经过method swizzling后,af_suspend已经变成之前的suspend,所以此处调用af_suspend就是调用系统的suspend
        [self af_suspend];
        
        if (state != NSURLSessionTaskStateSuspended) {
            [[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidSuspendNotification object:self];
        }
    }
    

    相关文章

      网友评论

          本文标题:AFNetworking - _AFURLSessionTask

          本文链接:https://www.haomeiwen.com/subject/lmhsxktx.html