美文网首页
Runloop Run 的疑惑

Runloop Run 的疑惑

作者: 游城十代2dai | 来源:发表于2020-12-13 22:42 被阅读0次

最近项目中有个需求 ---- 选择多个内容然后进入打印预览页面(公司自己的打印机需要预览然后打印)

碰到的问题是, 选择列表中的多个数据, 我只能拿到数据的 id, 因为列表就是简单的列表没有那么多详情数据在里面, 而后详情数据中还有图片需要下载, 下载完图片才可以进入打印预览页面, 相当于把数据都拿到后再给用户展示打印预览的样子

等同于多个详情的接口请求到结果后下载详情内的图片然后再去做一件事情

此时考虑用到选择内容较多的时候用户反正也是要 loading 等待, 所以请求接口就是异步但是按照同步去处理, 这样就不需要根据选好的 id 排序一遍, 如果是异步的话需要重新排序

但是图片还是要异步下载的, 异步下载的时候根据图片数量判断是否下载成功, 成功后才算数据完整, 这里又需要阻塞等待了

最终我的构思是这样的:

  1. for 循环一下选择的 id 构成的数组, 并创建一个变量 var cango = false
  2. 使用网络请求框架(比如 AF)进行详情请求
  3. 请求到结果后, 将图片整理在一起(合并成一个数组), 这里就不需要特意找下载框架了, let data = try? Data(contentsOf: url) let image = UIImage(data: data), 系统的这个请求本身是同步的, 自己创建一个队列进行异步操作就好了
  4. 图片异步下载的时候需要用一个 标志 来判断是否下载完成
  5. 下载的时候使用信号量来处理, 进行阻塞网络请求的那个线程, 等下载所有图片,
    signal 一下就把网络请求彻底处理完成了, 此时再将 cangomain async 中修改一为 true
  6. 这里是重点, 使用 Runloop 将主线程阻塞, 但是并不阻塞 UI, 使用方式如下面的测试代码
func test() {
        let count = 2
        // 展示 loading, 这是我自己封装的可以无视
        Toast.showLoading()
        (0..<count).forEach { (i) in
            // 用于控制主线程是否阻塞用
            var cango = false
            // 模拟网络请求
            GCD.globalAsync {
                print("当前第 \(i + 1) 个任务")
                (1...3).forEach { k in
                    sleep(1)
                    print("等待\(k)秒")
                }
                let semaphore = DispatchSemaphore(value: 0)
                let queue = DispatchQueue(label: "com.mb.study.download.image")
                (1...4).forEach { j in
                    queue.async {
                        print("下载图片: \(j)")
                        if j == 4 {
                            semaphore.signal()
                        }
                    }
                }
                semaphore.wait()
                
                GCD.mainAsync {
                    cango = true
                }
                print("completion")
            }
            
            while !cango {
                print("等待任务完成")
                RunLoop.current.run(mode: .default, before: .distantFuture)
            }
            
            print("配置完成")
        }
        
        print("回归主任务")
        Toast.hideLoading()
}

疑惑: 现在这确实可以通透, 但是, 为什么要在 main async 中修改 cango 才能让代码执行下去, 否则会卡在 while 那里, 直到触碰了屏幕(其实就是回到主线程)才可以继续任务, 这个我不清楚, 如有有更好的设计或者直到原因的大佬希望可以为我解惑, 谢谢~

相关文章

  • Runloop Run 的疑惑

    最近项目中有个需求 ---- 选择多个内容然后进入打印预览页面(公司自己的打印机需要预览然后打印) 碰到的问题是,...

  • runloop 面试题

    runloop 面试题 基于最近的几次面试,整理了runloop 的相关知识 1、Runloop 是什么?Run ...

  • NSRunLoop

    【iOS程序启动与运转】- RunLoop个人小结 RunLoop总结:RunLoop的应用场景(三) 走进Run...

  • [翻译] Run, RunLoop, Run!

    注:这篇文章翻译自 http://bou.io/RunRunLoopRun.html ,仅供学习参考,谢绝转载,已...

  • 09--Runloop01--runloop 文档解读

    runloop 官网 Introduction to Run Loops image 很有意思的是,runloop...

  • RunLoop

    RunLoop 文章已经很多了,结合各大文章做个总结 什么是 RunLoop RunLoop 人如其名,run 跑...

  • iOS RunLoop小结

    原文链接:http://yupeng.fun/2019/05/30/runloop/ RunLoop 简介 Run...

  • 备战2020——iOS面试题汇总!(栏目将持续更新)

    runloop 推荐相关文章 iOS 对于Run Loop的理解? 2019 iOS面试题-----RunLoop...

  • runloop

    runloop概念 Run loops are part of the fundamental infrastru...

  • RunLoop

    什么是RunLoop 简单地说RunLoop的作用是,通过RunLoop对象接收事件,执行处理事件。苹果通过Run...

网友评论

      本文标题:Runloop Run 的疑惑

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