我在使用Operation
和OperationQueue
的Alamofire時遇到問題。Alamofire在應用程序生命週期中阻止請求
我有一個名爲OperationQueue
和NetworkingQueue
我推一些操作(包裝AlamofireRequest)進去,一切工作正常,但在應用程序生活,在某一時刻都Alamofire請求不被髮送。我的隊列越來越大,沒有任何要求結束。
我沒有計劃隨時重現它。
有沒有人有幫助我的線索?
下面是代碼的示例
的BackgroundAlamoSession
let configuration = URLSessionConfiguration.background(withIdentifier: "[...].background")
self.networkingSessionManager = Alamofire.SessionManager(configuration: configuration)
AbstractOperation.swift
import UIKit
import XCGLogger
class AbstractOperation:Operation {
private let _LOGGER:XCGLogger = XCGLogger.default
enum State:String {
case Ready = "ready"
case Executing = "executing"
case Finished = "finished"
var keyPath: String {
get{
return "is" + self.rawValue.capitalized
}
}
}
override var isAsynchronous:Bool {
get{
return true
}
}
var state = State.Ready {
willSet {
willChangeValue(forKey: self.state.rawValue)
willChangeValue(forKey: self.state.keyPath)
willChangeValue(forKey: newValue.rawValue)
willChangeValue(forKey: newValue.keyPath)
}
didSet {
didChangeValue(forKey: oldValue.rawValue)
didChangeValue(forKey: oldValue.keyPath)
didChangeValue(forKey: self.state.rawValue)
didChangeValue(forKey: self.state.keyPath)
}
}
override var isExecuting: Bool {
return state == .Executing
}
override var isFinished:Bool {
return state == .Finished
}
}
的具體操作實施
import UIKit
import XCGLogger
import SwiftyJSON
class FetchObject: AbstractOperation {
public let _LOGGER:XCGLogger = XCGLogger.default
private let _objectId:Int
private let _force:Bool
public var object:ObjectModel?
init(_ objectId:Int, force:Bool) {
self._objectId = objectId
self._force = force
}
convenience init(_ objectId:Int) {
self.init(objectId, force:false)
}
override var desc:String {
get{
return "FetchObject(\(self._objectId))"
}
}
public override func start(){
self.state = .Executing
_LOGGER.verbose("Fetch object operation start")
if !self._force {
let objectInCache:objectModel? = Application.main.collections.availableObjectModels[self._objectId]
if let objectInCache = objectInCache {
_LOGGER.verbose("object with id \(self._objectId) founded on cache")
self.object = objectInCache
self._LOGGER.verbose("Fetch object operation end : success")
self.state = .Finished
return
}
}
if !self.isCancelled {
let url = "[...]\(self._objectId)"
_LOGGER.verbose("Requesting object with id \(self._objectId) on server")
Application.main.networkingSessionManager.request(url, method : .get)
.validate()
.responseJSON(
completionHandler: { response in
switch response.result {
case .success:
guard let raw:Any = response.result.value else {
self._LOGGER.error("Error while fetching json programm : Empty response")
self._LOGGER.verbose("Fetch object operation end : error")
self.state = .Finished
return
}
let data:JSON = JSON(raw)
self._LOGGER.verbose("Received object from server \(data["bId"])")
self.object = ObjectModel(objectId:data["oId"].intValue,data:data)
Application.main.collections.availableobjectModels[self.object!.objectId] = self.object
self._LOGGER.verbose("Fetch object operation end : success")
self.state = .Finished
break
case .failure(let error):
self._LOGGER.error("Error while fetching json program \(error)")
self._LOGGER.verbose("Fetch object operation end : error")
self.state = .Finished
break
}
})
} else {
self._LOGGER.verbose("Fetch object operation end : cancel")
self.state = .Finished
}
}
}
Ť他NetworkQueue
class MyQueue {
public static let networkQueue:SaootiQueue = SaootiQueue(name:"NetworkQueue", concurent:true)
}
我如何使用它的另一個操作,等待的結果
let getObjectOperation:FetchObject = FetchObject(30)
SaootiQueue.networkQueue.addOperations([getObjectOperation], waitUntilFinished: true)
我如何使用它使用志願
let getObjectOperation:FetchObject = FetchObject(30)
operation.addObserver(self, forKeyPath: #keyPath(Operation.isFinished), options: [.new], context: nil)
operation.addObserver(self, forKeyPath: #keyPath(Operation.isCancelled), options: [.new], context: nil)
queue.addOperation(operation)
//[...]
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if let operation = object as? FetchObject {
operation.removeObserver(self, forKeyPath: #keyPath(Operation.isFinished))
operation.removeObserver(self, forKeyPath: #keyPath(Operation.isCancelled))
if keyPath == #keyPath(Operation.isFinished) {
//Do something
}
}
一些澄清的基本操作:
我的應用程序陽離子是一個收音機,我需要,當播放音樂和背景時,獲取正在播放的節目。這就是爲什麼我需要背景Session。
事實上,我也使用後臺會話來處理應用程序在前臺時執行的所有聯網。我應該避免嗎?
我正在使用的等待來自另一個隊列,並且從不在主隊列中使用(我知道這是一個線程反模式並且我會照顧它)。
事實上,當我做兩個網絡操作時使用,第二個取決於第二個的結果。我在第一次手術後等待,以避免KVO觀察。我應該避免嗎?
附加編輯:
當我說「我的隊列越來越大,並沒有要求去年底」,這意味着,在應用程序的LiveCycle一個時刻,隨機的時刻(我無法找到每次重現的方法),Alamofire請求沒有達到響應方法。
因爲Operation
包裝不會結束並且隊列正在增長。
順便說一下,我正在努力將Alamofire請求轉換爲URLRequest
以獲取線索,並且我在使用主隊列時遇到了一些問題。我必須對Alamofire使用主隊列進行響應方法的事實進行排序,我會看看是否發現潛在的死鎖
我會隨時向您通報。謝謝
感謝您的評論。我添加了一些示例代碼。我希望它會提供更多的信息,如果有什麼問題在檢測它。 –
'operation.first'是什麼?我沒有看到任何'第一個'屬性... – Rob
當我試圖刪除所有業務代碼以專注於問題時,這是我的錯。首先是業務代碼的一部分。事實上,所有的操作都是超載的,以提出不同的請求。第一個參數在重載類上。我將它從示例代碼 –