我有一个AsyncOperation类定义为
import Foundation
class ASyncOperation: NSOperation {
enum State: String {
case Ready, Executing, Finished
private var keyPath: String {
return "is" + rawValue
}
}
var state = State.Ready {
willSet {
willChangeValueForKey(newValue.keyPath)
willChangeValueForKey(state.keyPath)
}
didSet {
didChangeValueForKey(oldValue.keyPath)
didChangeValueForKey(state.keyPath)
}
}
override var ready: Bool {
return super.ready && state == .Ready
}
override var executing: Bool {
return super.ready && state == .Executing
}
override var finished: Bool {
return super.ready && state == .Finished
}
override var asynchronous: Bool {
return true
}
override func start() {
if cancelled {
state = .Finished
return
}
main()
state = .Executing
}
override func cancel() {
state = .Finished
}
}
及其ImageLoadOperation的子类。
import Foundation
import UIKit
import Firebase
class ImageLoadOperation: ASyncOperation {
var imagePath: String?
var image: UIImage?
override func main(){
let storage = FIRStorage.storage()
let storageRef = storage.referenceForURL("gs://salisbury-zoo- 91751.appspot.com")
if let path = imagePath {
let imageReference = storageRef.child(path)
imageReference.dataWithMaxSize(3 * 1024 * 1024) { (data, error) -> Void in
if (error != nil) {
self.image = nil
} else {
self.image = UIImage(data: data!)
self.state = .Finished
}
}
}
}
}
所以我去调用队列中的操作
let queue = NSOperationQueue()
let imageLoad = ImageLoadOperation()
queue.addOperation(imageLoad)
let img:UIImage? = imageLoad.image
但它总是返回零。当我在ImageLoadOperation的回调中放置一个print语句时,图像就在那里,状态设置为finished。当我添加
queue.waitUntilAllOperationsAreFinished()
介于queue.addOperation并让img:UIImage? = imageLoad.load然后整个应用程序在主线程被阻止时停止。关于如何让图像在回调范围之外的任何其他想法?我也尝试过没有NSOperationQueue,只是作为一个没有运气的NSOperation。
答案 0 :(得分:1)
queue.addOperation
函数添加操作,并在后台线程中开始执行。因此它在后台线程完成之前很好地返回,这就是图像为零的原因。
正如文档所述,waitUntilAllOperationsAreFinished
将阻止线程,直到操作完成。这在主线程上是非常不受欢迎的。
imageReference.dataWithMaxSize
是一个异步操作,它有一个完成处理程序(你当前正在设置self.image
)。你需要一些东西来触发运行代码才能使用imageLoad.image
。如何执行此操作取决于应用程序的体系结构。
例如,如果要在UITableViewCell中显示图像,则需要将图像存储在图像数组中,可能是索引与表行匹配的位置,然后至少重新加载tableView的那一行。这是因为到接收图像时,该行可能不再存在。显然,您不希望此代码位于ImageLoadOperation
类中。相反,它应作为完成处理程序传递给main()
。