即使设置了操作的优先级和依赖关系,操作队列也不会按顺序执行

2023-11-29

我正在进行三个 api 调用,并希望 API1 应首先执行,完成后应执行 API2,然后执行 API3。 我为此使用了操作队列,并添加了对操作的依赖性。我也尝试设置优先级,但没有按顺序调用 api。帮我看看如何正确制作。

代码是这样的:

let op1 = Operation()
op1.completionBlock = {
    self.APICall(urlString: self.url1)
}
op1.queuePriority = .veryHigh

let op2 = Operation()
op2.completionBlock = {
    self.APICall(urlString: self.url2)
}
op2.queuePriority = .high

let op3 = Operation()
op3.completionBlock = {
    self.APICall(urlString: self.url3)
}

op3.queuePriority = .normal

op2.addDependency(op1)
op3.addDependency(op2)

queue.addOperations([op1, op2, op3], waitUntilFinished: false)

我将 API 调用方法放在 DispatchQueue.main.sync 中,如下所示:

func APICall(urlString: String) {

    let headers: HTTPHeaders = [
        "Accept": "text/html"
    ]
    print(urlString)
    DispatchQueue.main.sync {

        Alamofire.request(urlString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: headers).responseJSON {
            response in
            // self.stopActivityIndicator()
            print(response.result.value)
            switch response.result {
            case .success:
                break
            case .failure(let error):
                break
            }
        }

    }
}

有几个问题:

  1. 如果您尝试管理操作之间的依赖关系,则不能使用操作的completionBlock对于依赖项所依赖的代码。直到操作完成后才会调用完成块(从而破坏了任何依赖项的目的)。

    所以下面将not按预期工作:

    let queue = OperationQueue()
    
    let op1 = Operation()
    op1.completionBlock = {
        print("starting op1")
        Thread.sleep(forTimeInterval: 1)
        print("finishing op1")
    }
    
    let op2 = Operation()
    op2.completionBlock = {
        print("starting op2")
        Thread.sleep(forTimeInterval: 1)
        print("finishing op2")
    }
    
    op2.addDependency(op1)
    
    queue.addOperations([op1, op2], waitUntilFinished: false)
    

    但如果你像这样定义操作,它就会起作用:

    let op1 = BlockOperation() {
        print("starting op1")
        Thread.sleep(forTimeInterval: 1)
        print("finishing op1")
    }
    
    let op2 = BlockOperation {
        print("starting op2")
        Thread.sleep(forTimeInterval: 1)
        print("finishing op2")
    }
    

    (但这只是因为我重新定义了同步操作才有效。请参阅下面的第 3 点。)

    值得注意的是,通常你从不使用Operation直接地。作为docs say:

    表示与单个任务关联的代码和数据的抽象类。 ...

    因为Operationclass 是一个抽象类,您不能直接使用它,而是子类化或使用系统定义的子类之一(NSInvocationOperation or BlockOperation)来执行实际任务。

    因此使用BlockOperation,上面,或对其进行子类化,如下面第 3 点所示。

  2. 如果必须严格遵守操作执行的顺序,则不应使用优先级来管理操作执行的顺序。作为queuePriority docs say(强调):

    该值用于影响操作出队和执行的顺序...

    您应该仅根据需要使用优先级值来对非相关操作的相对优先级进行分类。不应使用优先级值来实现不同操作对象之间的依赖关系管理。如果需要在操作之间建立依赖关系,请使用addDependency(_:)方法代替。

    因此,如果您将 100 个高优先级操作和 100 个默认优先级操作排队,那么您将not保证所有高优先级的程序将在低优先级的程序开始运行之前启动。它会倾向于优先考虑它们,但并非严格如此。

  3. 第一点是没有意义的,因为您正在调用异步方法。所以你不能使用简单的Operation or BlockOperation。如果您不希望在前一个网络请求完成之前启动后续网络请求,则需要将这些网络请求包装在自定义异步中Operation具有所有特殊 KVO 的子类,其中包括:

    class NetworkOperation: AsynchronousOperation {
        var request: DataRequest
    
        static var sessionManager: SessionManager = {
            let manager = Alamofire.SessionManager(configuration: .default)
            manager.startRequestsImmediately = false
            return manager
        }()
    
        init(urlString: String, parameters: [String: String]? = nil, completion: @escaping (Result<Any>) -> Void) {
            let headers: HTTPHeaders = [
                "Accept": "text/html"
            ]
    
            let string = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
            let url = URL(string: string)!
            request = NetworkOperation.sessionManager.request(url, parameters: parameters, headers: headers)
    
            super.init()
    
            request.responseJSON { [weak self] response in
                completion(response.result)
                self?.finish()
            }
        }
    
        override func main() {
            request.resume()
        }
    
        override func cancel() {
            request.cancel()
        }
    }
    

    然后你可以这样做:

    let queue = OperationQueue()
    
    let op1 = NetworkOperation(urlString: ...) { result in
        ...
    }
    
    let op2 = NetworkOperation(urlString: ...) { result in
        ...
    }
    
    let op3 = NetworkOperation(urlString: ...) { result in
        ...
    }
    
    op2.addDependency(op1)
    op3.addDependency(op2)
    
    queue.addOperations([op1, op2, op3], waitUntilFinished: false)
    

    因为那是使用AsynchronousOperation子类(如下所示),直到异步请求完成后操作才会完成。

    /// Asynchronous operation base class
    ///
    /// This is abstract to class performs all of the necessary KVN of `isFinished` and
    /// `isExecuting` for a concurrent `Operation` subclass. You can subclass this and
    /// implement asynchronous operations. All you must do is:
    ///
    /// - override `main()` with the tasks that initiate the asynchronous task;
    ///
    /// - call `completeOperation()` function when the asynchronous task is done;
    ///
    /// - optionally, periodically check `self.cancelled` status, performing any clean-up
    ///   necessary and then ensuring that `finish()` is called; or
    ///   override `cancel` method, calling `super.cancel()` and then cleaning-up
    ///   and ensuring `finish()` is called.
    
    public class AsynchronousOperation: Operation {
    
        /// State for this operation.
    
        @objc private enum OperationState: Int {
            case ready
            case executing
            case finished
        }
    
        /// Concurrent queue for synchronizing access to `state`.
    
        private let stateQueue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".rw.state", attributes: .concurrent)
    
        /// Private backing stored property for `state`.
    
        private var _state: OperationState = .ready
    
        /// The state of the operation
    
        @objc private dynamic var state: OperationState {
            get { stateQueue.sync { _state } }
            set { stateQueue.sync(flags: .barrier) { _state = newValue } }
        }
    
        // MARK: - Various `Operation` properties
    
        open         override var isReady:        Bool { return state == .ready && super.isReady }
        public final override var isAsynchronous: Bool { return true }
        public final override var isExecuting:    Bool { return state == .executing }
        public final override var isFinished:     Bool { return state == .finished }
    
        // KVN for dependent properties
    
        open override class func keyPathsForValuesAffectingValue(forKey key: String) -> Set<String> {
            if ["isReady", "isFinished", "isExecuting"].contains(key) {
                return [#keyPath(state)]
            }
    
            return super.keyPathsForValuesAffectingValue(forKey: key)
        }
    
        // Start
    
        public final override func start() {
            if isCancelled {
                state = .finished
                return
            }
    
            state = .executing
    
            main()
        }
    
        /// Subclasses must implement this to perform their work and they must not call `super`. The default implementation of this function throws an exception.
    
        open override func main() {
            fatalError("Subclasses must implement `main`.")
        }
    
        /// Call this function to finish an operation that is currently executing
    
        public final func finish() {
            if !isFinished { state = .finished }
        }
    }
    
  4. 作为一个非常小的观察,您的代码指定了带有 JSON 参数的 GET 请求。这没有道理。 GET 请求没有可以包含 JSON 的正文。 GET 请求仅使用 URL 编码。此外,您没有传递任何参数。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

即使设置了操作的优先级和依赖关系,操作队列也不会按顺序执行 的相关文章

  • 如何在 Swift 中枚举 OptionSetType?

    我在 Swift 中有一个自定义的 OptionSetType 结构 如何枚举一个实例的所有值 这是我的选项集类型 struct WeekdaySet OptionSetType let rawValue UInt8 init rawVal
  • Swift 3 - 如何从另一个视图插入 TableView 单元格?

    我正在使用 Swift 3 Xcode 8 2 我试图弄清楚如何从选项卡式视图控制器的另一个选项卡将单元格插入到表视图中 我的表视图 class MyTableView UITableViewController var items Ite
  • 记录使用 OpenAL 播放的样本

    我在 iOS 上使用 OpenAL 同时播放 9 个循环 为了使循环 100 同步 它们开始在不同的线程上运行 有关使用 OpenAL 记录正在播放的内容的任何指示 教程 如果我使用不同的线程 我会遇到录制问题吗 iOS 上的 OpenAL
  • 尝试在 Xcode 中为 OS X 应用程序设置 Tab 键顺序

    我正在使用 Xcode 7 3 构建 OS X 桌面应用程序 并尝试为其中一个表单设置 Tab 键顺序 我发现有几篇文章解释了 Xcode 4 的类似问题 但没有任何进展 https www youtube com watch v SRrE
  • 从呈现的视图控制器访问呈现的视图控制器?

    我有一个视图控制器 包含我的菜单 显示在另一个视图控制器 我的应用程序 之上 我需要从呈现的视图控制器 我的菜单 访问呈现的视图控制器 在我的菜单下方 例如访问某些变量或使呈现的视图控制器执行其segues之一 但是 我就是不知道该怎么做
  • 在 Alamofire 中快速发送 GET 请求中的 json 对象

    我正在尝试执行一个绑定了 json 对象的 GET 请求 这就是我生成 JSON 对象的方式 let jsonObject String AnyObject ean code type match value 16743799 然后我执行了
  • 如何在 SKAction 中途反转精灵所遵循的路径方向?

    我有一个 SKSpriteNode 它使用 SKAction 沿着圆形路径移动 create the path our sprite will travel along let circlePath CGPathCreateWithElli
  • 为什么快速枚举中的可选项会导致无限循环?

    评估以下代码 我希望打印一次Hello World 相反 它会导致无限循环 有人可以解释为什么吗 let array what for text String in array print Hello World 删除可选的 显然让它只打印
  • 当 iPhone 设备方向朝上/朝下时,我可以判断它是横向还是纵向吗?

    我得到这个代码 如果设备处于左 右横向或上下颠倒状态 它会旋转并显示另一个视图控制器 但如果它的方向朝上或朝下 那么我如何判断它是横向模式还是纵向模式 因为我只想在它面朝上或朝下以及横向模式下旋转 void viewDidAppear BO
  • 使用捏合手势;如何放大用户手指实际“捏”的位置?

    我已经在我的应用程序中的 UIImageView 上实现了 UIPinchGestureRecognizer 但是无论我在图像的哪个位置捏合 它似乎都会放大到同一个位置 有谁知道我如何让它放大到用户实际 捏 的地方 请参阅下面的代码 视图控
  • iOS 复合谓词

    我正在编写一个具有照片数据库的应用程序 每张照片都有多个与之关联的标签 并且该应用程序有一个带有大量切换的搜索页面 允许用户仅根据他们感兴趣的标签搜索照片 每个标签都存储了integerID 是因为它们对应于外部数据库的 ID 所以我尝试简
  • 在 iPhone 和 Cocos2d 中从类类型(+)方法访问对象?

    我有一个类方法 在其中创建并返回类对象 但我想访问同一类中该对象的某些属性 作为一个类方法 我无法在 h 文件中声明该变量 然后在其他方法中访问它 以下是代码 我如何在下面的实例方法中访问 backsprite 或 hudlayer 对象的
  • 如何将 #ifdef DEBUG 添加到 Xcode?

    我的项目中有一些代码永远不应该在发布版本中使用 但在测试时很有用 我想做这样的事情 ifdef DEBUG Run my debugging only code endif 在 Xcode 4 中哪里添加 DEBUG 设置 我尝试将其放入
  • 将多个数组合并为一个数组

    如何将多个数组合并为一个二维数组 鉴于我有以下输入 var arr1 1 2 3 var arr2 a b c var arr3 aa bb cc 我需要这样的输出 1 a aa 2 b bb 1 c cc 我认为你想要的是将三个数组组合成
  • Xcode 本地化设置中没有加号或减号按钮

    我需要在两天内翻译 iOS 应用程序 但我的 XCode 版本 4 4 和 4 5 Developer Preview 都没有给我添加其他语言的选项 我只能选择单击 Make localized 但我只能选择英语 选择它后 Xcode 中的
  • 获取 Swift 子目录中资源的所有 URL

    我正在尝试为 iOS 应用程序的子目录中的所有资源创建 URL 数组 我似乎无法到达正确的路径 即使我不知道名称 我也希望能够检索 URL 即我不想将文件名硬编码到代码中 Below is a screen shot of the hier
  • iOS 11 getUserMedia 不起作用?

    苹果公司发表声明称getUserMedia将在 iOS 11 上完全正常运行 安装 iOS 11 Beta 版本 5 后 我确实收到一条消息 表明我的网站请求访问我的相机和麦克风 但似乎是这样的 video src window URL c
  • 将 Facebook 图片 URL 上传到 Firebase 存储

    我正在尝试将用户的 Facebook 个人资料图片上传到 Firebase 存储 let dictionary result as NSDictionary let data dictionary objectForKey data let
  • 使用 NSOutlineView 作为文件系统目录浏览器的 Swift 代码

    我已经在这段 Swift 代码上苦苦挣扎了一段时间 但没有发现问题 代码 下面应该提供文件目录作为 NSOutlineView 的数据源 GUI 非常简单 只是一个带有 NSOutlineView 和 OutlineViewControll
  • 您可以严格泛型类型或为一个参数指定多个类型吗?

    例如我想指定一个类型可能是Integer or String并将其用作特殊类型func我试过typealias但它不会解决这个问题 因为类型别名不能有or参数作为其唯一用途 因此请考虑下面的情况 typealias alis StringP

随机推荐

  • Mongodb 查询特定的月份|年份而不是日期

    如何查询 mongodb 中的特定月份 而不是日期范围 我需要月份来列出当月的客户生日列表 在 SQL 中会是这样的 SELECT FROM customer WHERE MONTH bday 09 现在我需要在 mongodb 中翻译它
  • 从 Play 商店 xamarin 获取最新的应用程序版本

    如何从 Google Play 商店获取最新的 Android 应用程序版本 之前曾使用下面的代码来做到这一点 using var webClient new System Net WebClient var searchString it
  • eclipse插件代码在指定位置创建IProject

    IProgressMonitor progressMonitor new NullProgressMonitor IWorkspaceRoot root ResourcesPlugin getWorkspace getRoot IProje
  • JButton 的不透明度/半透明度?

    我有如下简单的 GUI 代码 我想在其中制作JButton一个是半透明的 这样后面的图像JButton是可见的 package dealORnodeal import java awt BorderLayout import java aw
  • 如何选择并删除每第三列

    我有一组数据 其中每第三列都是相同的 我只想保留第一列 其他相同的列必须删除 起初我尝试了这段代码 但它删除了错误的列 因为在每个循环中其他列的位置都被改变了 Sub DeleteMultipleColumns Dim i As Integ
  • Rails 模型字段未更新到数据库

    使用型号 class Car lt ActiveRecord Base attr accessor model edition attr accessible model edition has many wheels end class
  • Google Actions 返回抱歉,尚不支持电源控制

    我通过扩展助手来实现我的设备 如中所述指示 我可以看到我的设备注册了以下特征 googlesamples assistant devicetool 列表 model Device Model Id assistant 19etc Proje
  • .NET:如何获取空对象的类型?

    我有一个带有 out 参数的方法 尝试进行类型转换 基本上 public void GetParameterValue out object destination object paramVal I want to return this
  • Android 地图、标记和内存泄漏

    我正在阅读 android 文档http developer android com reference com google android gms maps MapFragment html我看到了这句话 从 GoogleMap 获取的
  • R Shiny 中的反应式数据框

    我有一个由多个类别和月份组成的数据框 每行是参与者的 1 次交互 因此我想通过热图按月份和不同类别显示他们全年的交互计数 总共 490 万行 这意味着全年总共有 490 万次交互 我尝试使用输入来指示列名称 并尝试被动地更改 X 轴 但它似
  • 如何组合相等的序列元素(函数式编程)?

    我想编写一个函数 它接受序列 并返回具有相同元素分组的序列 如 gt 我使用的是序列 而不是列表 但有些功能是相似的 我正在考虑使用的一些功能是map reduce tabulate filter append等 Reduce 接受一个关联
  • 使用 Berkshelf 解决递归 git Cookbook 依赖关系

    TL 博士版本 Berkshelf 是否能够解决基于 Git 的说明书中的递归依赖关系 如果可以 如何解决 我尝试使用 Berkshelf 管理我的 Chef 食谱依赖项 这些食谱都存储在内部 Git 存储库中 依赖关系如下 env doc
  • 在mac 10.12上构建aosp

    我曾经在我的Mac上构建aosp 最近我升级了 mac os Mac Sierra 10 12 我在构建项目时收到此错误消息 找不到支持的 mac sdk 10 8 10 9 10 10 10 11 mac sdk 版本已升级到 10 12
  • 如何使用 NSString 的 sizeWithFont 和 drawInRect 来确定要绘制的字符串大小

    我正在使用 iOS 中的 CGContext 绘制多个图像 页面 我在我的应用程序中广泛使用了 sizeWithFont 和 drawInRect 组合 我需要做的是将一大块文本拆分到多个页面上 我可以调整它的大小并确定它是否需要另一页 但
  • Object.keys() 复杂性?

    有人知道 ECMAScript5 的 Object keys 在常见实现中的时间复杂度吗 是吗O n for n钥匙 假设采用哈希实现 时间与哈希表的大小成正比吗 我正在寻找语言实现者的保证或一些现实世界的基准测试 看来是O n 在 V8
  • 将小三角形水平居中在 div 底部并按响应和比例调整大小

    使用 CSS 我试图实现以下响应屏幕大小调整的效果 用于响应式设计 具体来说 我希望随着浏览器窗口变小 三角形也按比例变小 我将其模拟为 PNG 不是 HTML CSS 到目前为止 我使用此代码作为基础 其中 2 个 div 堆叠在一起 C
  • linq 查询表单

    如何将以下代码转换为 linq 或谓词表达式 List
  • RoboSpice 使用 OrmLite 持久保存 JSON 数组

    我正在将 RoboSpice 与 Spring for Android 结合使用 并希望使用 OrmLite 持久保存对象的 JSON 数组 GSON 用于 JSON 编组 使用默认缓存 一切都按预期工作 但OrmLite似乎不喜欢对象数组
  • 'multiprocessing.resource_sharer' 中的 AttributeError 'DupFd' | Python 多处理 + 线程

    我正在尝试在多个人之间进行通信threading Thread s 执行 I O 密集型任务和多个multiprocessing Process es 执行 CPU 密集型任务 每当一个线程为一个进程找到工作时 它就会被放到一个进程上mul
  • 即使设置了操作的优先级和依赖关系,操作队列也不会按顺序执行

    我正在进行三个 api 调用 并希望 API1 应首先执行 完成后应执行 API2 然后执行 API3 我为此使用了操作队列 并添加了对操作的依赖性 我也尝试设置优先级 但没有按顺序调用 api 帮我看看如何正确制作 代码是这样的 let