如果仍然相关,我可能会有答案。
这里的问题是你试图推迟初始化直到第一个操作完成。这是一个死胡同。操作意味着要尽早创建,并且使用依赖项来保证顺序。
所以让我们讨论一些解决这个极其常见的问题的方法。
(您可以注意到这些示例是用 WWDC-session 风格编写的。这实际上是因为我使用了基于该演讲的Operations library。如果您对基于操作的架构感兴趣,请查看它。 )
1。使用一些外部可变共享状态(Cocoa-way)
这基本上意味着,对于您的示例,您有一些 UserController,您将其实例传递给 LoginOperation 和 CountryOperation。 LoginOperation 将 userId 写入该控制器,CountryOperation 从中读取:
class UserController {
var userID: String?
}
class LoginOperation: Operation {
let userController: UserController
init(userController: UserController) {
self.userController = userController
}
override func execute() {
// do your networking stuff
userController.userID = receivedUserID
finish()
}
}
class CountryOperation: Operation {
let userController: UserController
init(userController: UserController) {
self.userController = userController
}
override func execute() {
let userID = userController.userID
// continue
}
}
然后:
let queue = OperationQueue()
let userController = UserController()
let login = LoginOperation(userController: userController)
let country = CountryOperation(userController: userController)
country.addDependency(login)
queue.addOperation(login)
queue.addOperation(country)
该解决方案的问题在于它非常复杂且难以测试。而且 Swift 也不太喜欢可变共享状态。
2。使用函数而不是值来初始化操作(Swifty-way)
嗯,这不是显而易见但非常优雅的解决方案。如您所见,值在初始化时被复制。我们真正需要的是检索所需的执行时间值(与前面的示例一样),但没有如此紧密的耦合。好吧,这很容易做到 - 只需将一个函数传递给初始化程序!
class LoginOperation: Operation {
private(set) var userID: String?
override func execute() {
// do your networking stuff
let receivedUserID = "1"
userID = receivedUserID
finish()
}
}
class CountryOperation: Operation {
private let getUserID: () -> String
init(getUserID: () -> String) {
self.getUserID = getUserID
}
override func execute() {
/* Because this operation depends on `LoginOperation`,
`getUserID()` is called after `LoginOperation` is finished. */
let userID = self.getUserID()
// continue
}
}
然后:
let queue = OperationQueue()
let login = LoginOperation()
// Force-unwrap is no good, of course, but for this example it's ok
let country = CountryOperation(getUserID: { login.userID! })
country.addDependency(login)
queue.addOperation(login)
queue.addOperation(country)
如您所见,没有紧密耦合,没有共享可变状态(CountryOperation 只能读,不能写——这很好)。而且它非常容易测试:只需将你想要的任何东西传递给 CountryOperation 初始化器,你根本不需要 LoginOperation 来测试它!
实际上,通过这种方法,NSOperation 的主要目标得以实现:独特、抽象的作品。 CountryOperation 本身对 LoginOperation 以及任何其他共享实例一无所知。
我实际上在我的项目中经常使用这种方法,并且效果非常好。
如果您有任何其他问题,请回复:)