Я использую OperationQueue для загрузки файлов по одному на удаленный сервер, используя URLSession.dataTask. Делегат используется для обновления индикатора выполнения, но после реализации OperationQueue мой делегат становится равным нулю. Это работало без OperationQueues. Глядя на стек во время работы программы, я не вижу контроллер представления моего индикатора выполнения. Прошло несколько дней, и я до сих пор не могу понять это. Я предполагаю, что контроллер представления освобождается, но я не уверен, как предотвратить его освобождение. Спасибо.
Мой делегат установлен в self в NetWorkViewController, но внутри urlSession моего класса NetworkManager (didSendBodyData) делегат становится нулевым. Делегат не является слабым и является переменной класса.
Однако мой делегат снова становится не равным нулю в блоке завершения моей операции BlockOperation. Это работает для отклонения ViewController через делегирование. Но делегат равен нулю, когда я пытаюсь обновить внутри urlSession (didSendBodyData) ...
ОБНОВЛЕНИЕ 10/30/2018
Кажется, что мои делегаты urlSessions находятся в отдельном потоке и записываются в основной поток при вызове, но я теряю ссылку на мой пользовательский делегат, который обновляет пользовательский интерфейс. Я пытаюсь прочитать больше о многопоточности, но любая помощь будет признательна!
ОБНОВЛЕНИЕ 2 10/30/2018
Решение найдено Проблема заключалась в том, что я создавал еще один экземпляр NetworkManager
внутри каждой операции. Это заставляет delegate
быть nil
, потому что для каждой операции создается новый экземпляр NetworkManager
. Исправление должно передать self
от исходного NetworkManager
, поэтому delegate
сохраняется.
uploadFiles
func uploadFiles(item: LocalEntry) {
let mainOperation = UploadMainFileOperation(file: item)
// This is where I need to give the operation its
// networkManager so the proper delegate is transferred.
mainOperation.networkManager = self
mainOperation.onDidUpload = { (uploadResult) in
if let result = uploadResult {
self.result.append(result)
}
}
if let lastOp = queue.operations.last {
mainOperation.addDependency(lastOp)
}
queue.addOperation(mainOperation)
....
....
let finishOperation = BlockOperation { [unowned self] in
self.dismissProgressController()
for result in self.result {
print(result)
}
self.delegate?.popToRootController()
}
if let lastOp = queue.operations.last {
finishOperation.addDependency(lastOp)
}
queue.addOperation(finishOperation)
queue.isSuspended = false
}
UploadMainFileOperation
class UploadMainFileOperation: NetworkOperation {
let file: LocalEntry
// First issue is here. I re-declared another NetworkManager that doesn't have its delegate properly set.
private let networkManager = NetworkManager()
// I have since have this class receive the original networkManager after it's declared.
var networkManager: NetworkManager?
var onDidUpload: ((_ uploadResult: String?) -> Void)!
init(file: LocalEntry) {
self.file = file
}
override func execute() {
uploadFile()
}
private func uploadFile() {
networkManager.uploadMainFile(item: file) {
(httpResult) in
self.onDidUpload(httpResult)
self.finished(error: "upload main")
}
}
}
urlSession (didSendBodyData)
func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {
// This is wrong.
let uploadProgress: Float = Float(totalBytesSent) / Float(totalBytesExpectedToSend)
updateDelegateWith(progress: uploadProgress)
// This is the correct way for my situation.
// Because each operation on the queue is on a separate thread. I need to update the UI from the main thread.
DispatchQueue.main.async {
let uploadProgress: Float = Float(totalBytesSent) / Float(totalBytesExpectedToSend)
self.updateDelegateWith(progress: uploadProgress)
}
}
updateDelegateWith (прогресс: Float)
func updateDelegateWith(progress: Float) {
delegate?.uploadProgressWith(progress: progress)
}
NetworkManagerViewController где находится индикатор выполнения
class NetworkViewController: UIViewController, NetWorkManagerDelegate {
var localEntry: LocalEntry?
var progressBackground = UIView()
var progressBar = UIProgressView()
func uploadProgressWith(progress: Float) {
progressBar.progress = progress
view.layoutSubviews()
}
deinit {
print("deallocate")
}
override func viewDidLoad() {
super.viewDidLoad()
let networkManager = NetworkManager()
networkManager.delegate = self
networkManager.uploadFiles(item: self.localEntry!)
....
....
}
}