- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在进行三个 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
}
}
}
}
最佳答案
有几个问题:
如果您尝试管理操作之间的依赖关系,则不能将操作的 completionBlock
用于依赖关系所依赖的代码。直到操作完成后才会调用完成 block (因此破坏了任何依赖项的目的)。
因此以下内容不会按预期工作:
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 :
An abstract class that represents the code and data associated with a single task. ...
Because the
Operation
class is an abstract class, you do not use it directly but instead subclass or use one of the system-defined subclasses (NSInvocationOperation
orBlockOperation
) to perform the actual task.
因此使用上面的 BlockOperation
,或如下面第 3 点所示对其进行子类化。
如果必须严格遵守顺序,则不应使用优先级来管理操作执行的顺序。作为 queuePriority
docs say (强调):
This value is used to influence the order in which operations are dequeued and executed...
You should use priority values only as needed to classify the relative priority of non-dependent operations. Priority values should not be used to implement dependency management among different operation objects. If you need to establish dependencies between operations, use the
addDependency(_:)
method instead.
因此,如果您将 100 个高优先级操作和 100 个默认优先级操作排队,您不能保证所有高优先级操作都会在低优先级操作开始运行之前启动。它会倾向于优先考虑它们,但并非严格如此。
第一点没有实际意义,因为您正在调用异步方法。所以你不能使用简单的 Operation
或 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 }
}
}
作为非常细微的观察,您的代码指定了带有 JSON 参数的 GET 请求。那没有意义。 GET 请求没有可以包含 JSON 的正文。 GET 请求仅使用 URL 编码。此外,您没有传递任何参数。
关于ios - 即使在设置了操作的优先级和依赖性之后,操作队列也没有按顺序执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57246580/
我正在使用 puppet 在云基础设施上自动配置服务器。我将 list 分成几个 .pp。 我有以下错误: Could not find dependency Mehc_module::Filestr
我开始学习 Angular ,但我在管理依赖项时遇到麻烦,并且不明白为什么这不起作用。 我的html: Title
我正在尝试编写一个使用 jnetpcap 并适合 Linux 和 Windows 的程序。我使用 Maven 编译我的程序。 目前对 jnetpcap 的依赖是: jnetpcap
我很难弄清楚这一点,我首先提到类结构: 汽车经销商 汽车工厂 汽车(界面) BlueCar(汽车实现) RedCar(汽车实现) 轮胎 CarFactory 类有一个返回 Car 的工厂方法。在 Sp
我正在研究一些示例,并提出了这个可行的答案 - 文档测试中设置的挑战: def remove(sub, s): """ >>> remove('an', 'banana')
当创建一个由其他类组成的类时,是否值得通过使用指针而不是值来减少依赖性(从而减少编译时间)? 例如,下面使用值。 // ThingId.hpp class ThingId { // ... }
我在为 debug 和 release 构建类型以及维度指定不同的依赖项时遇到问题。 在我的 app.gradle 中,我指定了 1 个维度 和 2 个 productFlavors,如下所示: an
我试图从Grails的默认依赖项中排除Apache Commons库1.4.0版,因为它有一个错误。 https://github.com/grails/grails-core/issues/9000
我使用我的 MacBook 开发了一个 Node.JS 小应用程序。一切都很好,我将把它部署到 Heroku。 git push heroku master 命令退出并出现错误: 9045 info
我在数据库中有几行。我创建了一个 Windows 服务,它每 5 分钟更新一次数据库中的新行。 现在我想跟踪新行,如果有任何......在 WCF 服务中,并向客户端发送有关它的通知。 数据库是SQL
我的程序依赖于 USER32.dll、SHELL32.dll、ADVAPI32.dll、WS2_32.dll、GDI32.dll 和 KERNEL32.dll。都在system32文件夹中。有什么方法
我有 3 个 dag A、B 和 C。只有在 dag A 和 B 中的任务完成后,才应触发 Dag C。有没有办法在 Airflow 中实现这一点?我能够使用 Triggerdagrun Operat
为了编写可重用的 QML 代码,我正在寻找一个(静态代码)检查器,它可以检测不同 qml 文件之间不需要的依赖关系。 举一个例子,其中 B.qml 依赖于 A.qml 中的标识符: A.qml Ite
我创建了 pom.ml 文件,如下所述: 4.0.0 friendr-core friendr-core 0.0.1-SNAPSHOT jar fri
下图中,左边是C代码,右边是未优化的LLVM IR形式。 The Figure 在 IR 上运行 MemoryDependenceAnalysis 可查找内存依赖性。原始代码及其 IR 等效代码中
我有所有必要的依赖: ch.qos.logback logback-classic 1.0.13 org.slf4j slf4j-api 1.7.
我使用 wsimport 从 WSDL 文件生成客户端代码,我已成功测试此生成的代码并且它可以工作,但有一个问题,该代码像这样引用 WSDL 文件, static { URL url = nu
我正在制作一个检查库依赖性的 configure.ac 文件。 完整的代码是, AC_CONFIG_AUX_DIR([build-aux]) AC_INIT([myprogram], [0.1], [
我正面临这个似乎无法解决的问题。这是场景: 我正在构建使用 gradle 依赖项的 apk,并且此依赖项是特定于体系结构的,因此对于 x86 的 apk,我需要不同的依赖项,对于 arm 也需要不同的
我正在使用 npm 安装依赖项。安装这些之后,我想与非技术人员且没有 npm 的人共享我的项目,因此我想在应用程序中发布 node_modules。 但是,由于 node 嵌套了依赖关系,它创建的文件
我是一名优秀的程序员,十分优秀!