我爱编程

ios强制在主线程上运行方法

2018-05-29  本文已影响1110人  继续向前冲

您知道有多少次, 作为 iOS 开发人员, 您希望确保在主线程上发生某些方法或代理调用吗?我们尝试了无数次, 虽然它是看是简单, 但它中间还是有很多坑。
这里有一个简单的方法来保持线程安全,而不必在这个过程中编写大量代码。
在我的代码中,我通常为我的selectors创建一个私有代理包装方法。这样我就不会在我的类中到处乱扔逻辑了。有一个需要注意对方, 如果我的代理被调用, 这意味着我不能使它崩溃。这些包装方法类似于以下内容:
- (void)delegate_willShowViewController:(UIViewController*)controller {
    if ([self.delegate respondsToSelector:@selector(pagedCellController:willShowViewController:)]) {
        [self.delegate pagedCellController:self willShowViewController:controller];
    }
}

这样,在代理不采用selector的情况下,我有一种处理默认值的整洁方法,我的代码要简单得多。但是,有许多UI相关的调用应该只在主线程上执行。我有很多样板代码来处理这个问题,但是我想要一个简单的方法来自动化这个过程。
无需进一步说明,如果没有调用主线程,这里有一个C函数和C宏,它简化了主线程上的任何本地 selector的调用。

#import <Foundation/Foundation.h>

extern NSInvocation * DNInvocationForCall(id object, SEL selector, ...);

#define FORCE_MAIN_THREAD(...) if (![NSThread isMainThread]) { 
    NSInvocation *inv = DNInvocationForCall(self, _cmd, ##__VA_ARGS__); 
    dispatch_async(dispatch_get_main_queue(), ^{ 
        [inv invoke]; 
    }); 
    return; 
}
#import "Defines.h"

NSInvocation * DNInvocationForCall(id object, SEL selector, ...) {
    NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[NSMethodSignature methodSignatureForSelector:selector]];
    [inv setTarget:object];
    [inv setSelector:selector];

    va_list arglist;
    va_start(arglist, selector);

    NSInteger nextArgIndex = 2;
    NSObject *arg = nil;
    do {
        arg = va_arg(arglist, NSObject*);
        if (arg && arg != [NSNull null]) {
            [inv setArgument:&arg atIndex:nextArgIndex];
        }

        nextArgIndex++;
    } while (arg != nil);

    va_end(arglist);

    [inv retainArguments];
    return inv;
}

这个函数 NSInvocation 对象是基于object对象,selector 。宏包装这个,并且只在不在主线程上调用它。更重要的是, 宏具有从当前方法返回的功能, 在当前线程上停止执行。现在,我需要做的就是改变我的代理包装看起来像下面这样:

- (void)delegate_willShowViewController:(UIViewController*)controller {
    FORCE_MAIN_THREAD(controller)
    if ([self.delegate respondsToSelector:@selector(pagedCellController:willShowViewController:)]) {
        [self.delegate pagedCellController:self willShowViewController:controller];
    }
}

传送门:

上一篇 下一篇

猜你喜欢

热点阅读