美文网首页
OC 启动任务执行实践 2023-04-28 周五

OC 启动任务执行实践 2023-04-28 周五

作者: 勇往直前888 | 来源:发表于2023-04-27 11:51 被阅读0次

    简介

    由于更熟悉OC一点,所以新工程仍然用OC,但是常见的第三方库,比如SVProgressHUD都会报错,说是找不到window
    然后再试了一下,就会发现以前理所当然的[[[UIApplication sharedApplication] delegate] window]都会报错。怎么回事?

    SceneDelegate

    企业微信截图_0516fa97-ec90-40e0-adf8-46599ea57c67.png
    • 如图所示,除了通常的AppDelegate,又多了SceneDelegate

    • 很重要的window属性,从往常的AppDelegate移到了SceneDelegate

    • 这个又继承了苹果蠢猪式的升级,连基本的兼容性都不考虑了。苹果的工程师质量是一代不如一代啊

    • 引入SceneDelegate,是学习Android的多进程。随着手机屏幕越来越大,也算有点道理。不过,把手机整得和PC一样,真的好吗?无脑抄袭Android,有未来吗?

    • 吐槽再多也没用。不管未来有多辉煌,至少现在,所谓的“多进程”,没有丝毫收益,只有麻烦,直接旁路掉是最省事的做法。

    如何找回windows

    • window被移到了SceneDelegate中
    #import <UIKit/UIKit.h>
    
    @interface SceneDelegate : UIResponder <UIWindowSceneDelegate>
    
    @property (strong, nonatomic) UIWindow * window;
    
    @end
    
    • 在AppDelegate把移走的window加回来
    #import <UIKit/UIKit.h>
    
    @interface AppDelegate : UIResponder <UIApplicationDelegate>
    
    // 与SceneDelegate中的window是同一个;
    // 很多第三方库,比如SVProgressHUD要用到;
    // 自己以view的方式做弹窗也要用到;
    @property (nonatomic, strong) UIWindow *window;
    
    @end
    
    • 在SceneDelegate.m进行桥接,将两个window联系起来
    - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
        
        /// 兼容以前的用法
        [UIApplication sharedApplication].delegate.window = self.window;
    }
    

    入口点

    • 把SceneDelegate和AppDelegate连接起来后,就可以沿用以前的做法,在AppDelegate.m中进行程序初始化操作。

    • 可以直接在AppDelegate.m写初始化操作,也可以新建一个文件,把散落的代码集中在一起,保持AppDelegate.m的简洁。

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        
        /// 初始化
        [WGBInitial start];
        
        return YES;
    }
    

    初始化方法

    • 本工程比较简单,初始化的内容不多,只有一些三方库的初始化,一些辅助接口的数据访问。

    • 为了简洁,仍然是封装成静态方法

    #import "WGBInitial.h"
    #import <Sentry/Sentry.h>
    
    @implementation WGBInitial
    
    /// 开始初始化;从AppDelegate迁移到这里
    + (void)start {
        /// 初始化内容放入子线程中,防止拖慢启动速度
        NSOperationQueue *initialQueue = [[NSOperationQueue alloc] init];
        initialQueue.name = @"初始化队列";
        [initialQueue addOperationWithBlock:^{
            NSLog(@"子线程初始开始……");
            
            /// 友盟统计
            [WGBStatistics setupYouMeng];
            
            /// 腾讯Bugly
            [WGBStatistics setupBugly];
            
            /// AvoidCrash
            [WGBStatistics setupAvoidCrash];
            
            /// 阿里云鉴权参数
            [WGBUploader getStsInfo];
            
            /// 需要放主线程的初始化
            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                NSLog(@"主线程初始开始……");
                
                /// 初始化Sentry
                [WGBStatistics setupSentry];
            }];
        }];
    }
    
    @end
    

    关于多线程

    • 以前一直用GCD,也一直很好用;关于GCD可以参考下面的文章:
      OC多线程GCD

    • 这次尝试用NSOperationQueue,感觉更简洁;

    以前一直不用,估计是被那么多的概念搞怕了,习惯性使用GCD;所以,准备简化使用NSOperationQueue,当做今后多线程的主要使用方式。

    • GCD中有串行队列,并行队列;同步执行,异步执行;这些内容不能迁移到NSOperationQueue中;这样做的话就导致了复杂性,不好用。

    • 简单处理的话,就用两种区分:
      (1)如果是耗时工作,并且不涉及界面,就用 NSOperationQueue *queue = [[NSOperationQueue alloc] init];
      (2)如果涉及到界面,就用主线程:[NSOperationQueue mainQueue]

    至于queue.maxConcurrentOperationCount = 1;千万不要用,没有意义,还增加了理解上的复杂程度

    • NSBlockOperationNSInvocationOperation也增加了使用的复杂性,选择困难症困扰很多人。

    简单起见,果断扔掉NSInvocationOperation,只考虑NSBlockOperation

    • 至于继承NSOperation进行自定义,80%的情况都不要有这种考虑,大多数情况只是自寻烦恼。

    • 真正使用的时候,设置都不需要考虑NSBlockOperation这个概念,直接使用如下方法就可以了。

    - (void)addOperationWithBlock:(void (^)(void))block;
    
    • 至于依赖关系,80%的情况也不需要考虑,直接使用如下方法将更简单
    - (void)addBarrierBlock:(void (^)(void))barrier
    

    这个相当于dispatch_barrier_async,使用得当,完全可以替代dispatch_group

    • 小结:综上所述,只要理解了NSOperationQueue这个概念,只需要使用2个方法就能解决80%的多线程需求,比直接使用GCD简单多了

    相关文章

      网友评论

          本文标题:OC 启动任务执行实践 2023-04-28 周五

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