主线程上的 NSOperation 运行
NSOperation running on main thread
我已经使用 this 指南让我的应用程序使用 NSOperationQueue 和 NSOperations。但是我的代码仍然在主线程上运行,不管 :S?我必须说我是 NSOperation 的新手,我认为这是我错过的一件小事。
class CountryFetcher: NSObject{
var operation: NSOperation?
var alamoFireQueue: NSOperationQueue{
let val = NSOperationQueue()
val.maxConcurrentOperationCount = 10
val.name = "Alamofire Downloading Queue"
return val
}
func getCountries(){
operation = CountryProcessor(URLString: (BASE_URL + "countries/"+CAT_STAMPS))
alamoFireQueue.addOperation(operation!)
}
}
class CountryProcessor : ConcurrentOperation {
let URLString: String
weak var request: Alamofire.Request?
init(URLString: String) {
self.URLString = URLString
super.init()
}
override func main() {
request = Alamofire.request(.GET, URLString).responseJSON { response in
if let dataResponse = response.data{
var test: NSArray?
do{
test = try NSJSONSerialization.JSONObjectWithData(dataResponse, options: NSJSONReadingOptions()) as! NSArray
}catch let error as NSError{
print(error.localizedDescription)
}
for _ in 1...100{
NSLog("main thread? %@", NSThread.isMainThread() ? "YES" : "NO");
}
}
self.completeOperation()
}
}
override func cancel() {
request?.cancel()
super.cancel()
}
}
这是 ConcurrentOperation class。我是从上面link中的post复制过来的
class ConcurrentOperation : NSOperation {
override var asynchronous: Bool {
return true
}
override var concurrent: Bool{
return true
}
private var _executing: Bool = false
override var executing: Bool {
get {
return _executing
}
set {
if (_executing != newValue) {
self.willChangeValueForKey("isExecuting")
_executing = newValue
self.didChangeValueForKey("isExecuting")
}
}
}
private var _finished: Bool = false;
override var finished: Bool {
get {
return _finished
}
set {
if (_finished != newValue) {
self.willChangeValueForKey("isFinished")
_finished = newValue
self.didChangeValueForKey("isFinished")
}
}
}
/// Complete the operation
///
/// This will result in the appropriate KVN of isFinished and isExecuting
func completeOperation() {
executing = false
finished = true
}
override func start() {
if (cancelled) {
finished = true
return
}
executing = true
main()
}
}
当我执行这段代码时,它一直说它在主线程上运行:2016-08-12 18:25:45.799 Stamp Catalague Preloader[1807:31357] 主线程?是的。
这是怎么回事?感谢您的帮助;
问题在于 Alamofire 将其完成处理程序分派到主队列(理论上他们想让您更轻松地更新 UI and/or 模型)。
如果要为完成处理程序使用不同的队列,请将队列参数提供给 response
或 responseJSON
方法。
例如,有一些 属性:
var completionHandlerQueue = dispatch_queue_create("com.domain.completionhandler", nil)
然后,当您执行请求时:
Alamofire.request(.GET, URLString).responseJSON(queue: completionHandlerQueue) { response in
guard let test = response.result.value else {
print("no data")
print(response.result.error)
return
}
// do something with `test` here
print(test)
NSLog("main thread? %@", NSThread.isMainThread() ? "YES" : "NO");
}
这提出了一个问题,即您是否真的关心是否在主队列上调用了完成处理程序。当然,如果你在那里做一些计算密集型的事情,那么一定要指定一个不同的队列。但是没有理由说一个操作不能在主队列上执行它的一些任务。事实上,有时仅在主队列上设置完成处理程序 运行 非常有用,这样您就无需同步模型更新 and/or 将 UI 更新分派到主队列.
更进一步,我们不得不问使用NSOperation
的意图是什么。如果目标仅仅是享受请求的异步处理,则不需要 NSOperation
。但是,如果 (a) 您正在使用 NSOperation
来管理不同操作的依赖关系; (b) 您没有使用后台会话,那么请务必将您的请求包装在操作中。
我已经使用 this 指南让我的应用程序使用 NSOperationQueue 和 NSOperations。但是我的代码仍然在主线程上运行,不管 :S?我必须说我是 NSOperation 的新手,我认为这是我错过的一件小事。
class CountryFetcher: NSObject{
var operation: NSOperation?
var alamoFireQueue: NSOperationQueue{
let val = NSOperationQueue()
val.maxConcurrentOperationCount = 10
val.name = "Alamofire Downloading Queue"
return val
}
func getCountries(){
operation = CountryProcessor(URLString: (BASE_URL + "countries/"+CAT_STAMPS))
alamoFireQueue.addOperation(operation!)
}
}
class CountryProcessor : ConcurrentOperation {
let URLString: String
weak var request: Alamofire.Request?
init(URLString: String) {
self.URLString = URLString
super.init()
}
override func main() {
request = Alamofire.request(.GET, URLString).responseJSON { response in
if let dataResponse = response.data{
var test: NSArray?
do{
test = try NSJSONSerialization.JSONObjectWithData(dataResponse, options: NSJSONReadingOptions()) as! NSArray
}catch let error as NSError{
print(error.localizedDescription)
}
for _ in 1...100{
NSLog("main thread? %@", NSThread.isMainThread() ? "YES" : "NO");
}
}
self.completeOperation()
}
}
override func cancel() {
request?.cancel()
super.cancel()
}
}
这是 ConcurrentOperation class。我是从上面link中的post复制过来的
class ConcurrentOperation : NSOperation {
override var asynchronous: Bool {
return true
}
override var concurrent: Bool{
return true
}
private var _executing: Bool = false
override var executing: Bool {
get {
return _executing
}
set {
if (_executing != newValue) {
self.willChangeValueForKey("isExecuting")
_executing = newValue
self.didChangeValueForKey("isExecuting")
}
}
}
private var _finished: Bool = false;
override var finished: Bool {
get {
return _finished
}
set {
if (_finished != newValue) {
self.willChangeValueForKey("isFinished")
_finished = newValue
self.didChangeValueForKey("isFinished")
}
}
}
/// Complete the operation
///
/// This will result in the appropriate KVN of isFinished and isExecuting
func completeOperation() {
executing = false
finished = true
}
override func start() {
if (cancelled) {
finished = true
return
}
executing = true
main()
}
}
当我执行这段代码时,它一直说它在主线程上运行:2016-08-12 18:25:45.799 Stamp Catalague Preloader[1807:31357] 主线程?是的。
这是怎么回事?感谢您的帮助;
问题在于 Alamofire 将其完成处理程序分派到主队列(理论上他们想让您更轻松地更新 UI and/or 模型)。
如果要为完成处理程序使用不同的队列,请将队列参数提供给 response
或 responseJSON
方法。
例如,有一些 属性:
var completionHandlerQueue = dispatch_queue_create("com.domain.completionhandler", nil)
然后,当您执行请求时:
Alamofire.request(.GET, URLString).responseJSON(queue: completionHandlerQueue) { response in
guard let test = response.result.value else {
print("no data")
print(response.result.error)
return
}
// do something with `test` here
print(test)
NSLog("main thread? %@", NSThread.isMainThread() ? "YES" : "NO");
}
这提出了一个问题,即您是否真的关心是否在主队列上调用了完成处理程序。当然,如果你在那里做一些计算密集型的事情,那么一定要指定一个不同的队列。但是没有理由说一个操作不能在主队列上执行它的一些任务。事实上,有时仅在主队列上设置完成处理程序 运行 非常有用,这样您就无需同步模型更新 and/or 将 UI 更新分派到主队列.
更进一步,我们不得不问使用NSOperation
的意图是什么。如果目标仅仅是享受请求的异步处理,则不需要 NSOperation
。但是,如果 (a) 您正在使用 NSOperation
来管理不同操作的依赖关系; (b) 您没有使用后台会话,那么请务必将您的请求包装在操作中。