在Swift中调度两个独立的异步线程

时间:2017-06-10 01:38:15

标签: swift multithreading

我正在尝试加载一组按钮,这些按钮将在加载菜单时一个接一个地滑动。所以我这样做了:

    buttonTimer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(MainMenu.enterButtons), userInfo: nil, repeats: true)
    buttonTimer.fire()

这将运行enterButtons()方法,该方法将运行按钮的移动操作。此计时器是在此菜单的初始化程序期间创建的,因为我希望按钮在init上加载。但是,在我的初始化程序中,我还初始化了一个性能很重的类,因为它保存了我所有的级别:

    DispatchQueue.main.asyncAfter(deadline: .now()) {
        self.initialLevel.levelHolder = LevelHolder(screenWidth: Float(self.initialLevel.size.width), scene: self.initialLevel, screenSize: self.initialLevel.frame, initialLevel: (1,1))
    }

所以我在异步中做了这个,因为如果我不这样做,它会占用初始化程序的所有其他功能。但是,我认为这两个线程实际上只是一个。异步任务的顺序是:

  1. 初始化关卡持有人
  2. 加载按钮
  3. 我希望这两项任务同时进行。但是,似乎不是我希望的三个线程(主线程,级别持有者和加载按钮),我相信只有两个:主线程和一个我创建的两个异步任务。在我的调试会话期间,我注意到加载按钮任务等待初始化级别持有者。但是,我想创建三个独立的异步线程。我怎么能这样做?

    修改

    我尝试为我尝试过的关卡持有者实现并发,@ UpholderOfTruth建议:

        DispatchQueue.global(qos: .background) {
            self.initialLevel.levelHolder = LevelHolder(screenWidth: Float(self.initialLevel.size.width), scene: self.initialLevel, screenSize: self.initialLevel.frame, initialLevel: (1,1))
        }
    

    但我收到的错误是:

      

    LevelHolder无法转换为'LevelHolder!'

    因为self.initialLevel.levelHolder属于LevelHolder类型!但我将它设置为LevelHolder。

    如何避免此错误?我试过这样做:

    self.initialLevel.levelHolder = LevelHolder(screenWidth: Float(self.initialLevel.size.width), scene: self.initialLevel, screenSize: self.initialLevel.frame, initialLevel: (1,1))!
    

    然后Xcode建议警告我

      

    无法强制解包为非可选类型'LevelHolder'

    initialLevel在初始化级别持有者的方法中初始化:

    func initializeLevelHolder() {
        initialLevel = InitialLevel()
        initialLevel.size = self.size
        DispatchQueue.main.asyncAfter(deadline: .now()) {
            self.initialLevel.levelHolder = LevelHolder(screenWidth: Float(self.initialLevel.size.width), scene: self.initialLevel, screenSize: self.initialLevel.frame, initialLevel: (1,1))
        }
    }
    

    这是定义为

    的此菜单的实例变量
    var initialLevel : InitialLevel!
    

1 个答案:

答案 0 :(得分:0)

您正在将levelHolder代码立即推回主线程,并将按钮时间设置为0.1秒后触发,然后手动触发,这在方法完成后发生。所以一切都发生在主线程上,你的levelHolder处理会阻止按钮处理。

您可以将levelHolder处理放到这样的后台线程中:

DispatchQueue.global(qos: .background).async {
    self.initialLevel.levelHolder = LevelHolder(screenWidth: Float(self.initialLevel.size.width), scene: self.initialLevel, screenSize: self.initialLevel.frame, initialLevel: (1,1))
}

但是不要忘记对UI的任何更新仍然需要返回主线程,如下所示:

DispatchQueue.main.async {
    // Update the UI
}

不幸的是,由于所有UI更新都必须在主线程上发生,所以无法做到这一点,因此会在某种程度上阻止彼此。