美文网首页
iOS:如果将dispatch_once写在头文件...

iOS:如果将dispatch_once写在头文件...

作者: 笑出zhu声 | 来源:发表于2020-05-03 20:29 被阅读0次

    开发小王:我用dispatch_once创建了一个串行Queue,我的代码都是在这个queue中执行的,为什么线上还会有线程安全的问题?

    看了下,在Common.h头文件中有这么段代码:

    
    #ifndef Common_h
    #define Common_h
    
    static dispatch_queue_t myQueue() {
        static dispatch_once_t onceToken;
        static dispatch_queue_t __myQueue;
        dispatch_once(&onceToken, ^{
           __myQueue = dispatch_queue_create("com.my.queue", DISPATCH_QUEUE_SERIAL);
        });
        return __myQueue;
    }
    
    #endif /* Common_h */
    

    从上面的代码看,通过dispatch_once创建了一个串行Queue,那为什么还是会创建多个线程呢,我们demo下:

    在本地创建demo工程,创建Common.h头文件,分别在AppDelegate.mSceneDelegate.m 文件中引入Common.h,为了测试系统是否真的创建了两个线程,做如下修改:

    //AppDelegate.m
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        dispatch_async(myQueue(), ^{
            while (1) {   
            }
        });
        return YES;
    }
    
    
    //SceneDelegate.m
    - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
        dispatch_async(myQueue(), ^{
            while (1) {
            }
        });
    }
    

    分别在两个文件中起两个任务,用while(1) 保证线程不退出,App运行后,使用Xcode的暂停功能运行中的线程如下:

    运行中的线程

    验证后发现,确实创建了两个线程,那到底是什么原因呢?

    我们知道#import 是预编译处理的,那么我们使用Xcode工具自带的预编译工具(Assistant-Preprocess)看下这两个文件预处理后的文件,发现都有这样一段代码:

    # 1 "/Users/my/Desktop/demo/demo/Common.h" 1
    
    
    #pragma clang module import Foundation /* clang -E: implicit import for #import <Foundation/Foundation.h> */
    
    
    static dispatch_queue_t myQueue() {
        static dispatch_once_t onceToken;
        static dispatch_queue_t __myQueue;
        _dispatch_once(&onceToken, ^{
           __myQueue = dispatch_queue_create("com.my.queue", ((void*)0));
        });
        return __myQueue;
    }
    

    是的,在AppDelegate.m 和 SceneDelegate.m有两份拷贝,这也就解释了为什么会有多个线程。

    在平时的开发过程中,很多同学不注意会将方法实现写到头文件中(除了有明确需要内联方式的情况),这样做轻则增大可执行文件大小(被import的越多,拷贝的越多),重则影响程序逻辑错误。

    相关文章

      网友评论

          本文标题:iOS:如果将dispatch_once写在头文件...

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