gpt4 book ai didi

ios - delegate 在 urlSession 的操作中变为 nil。如何将委托(delegate)变量保存在单独的线程中?

转载 作者:搜寻专家 更新时间:2023-10-31 22:38:11 25 4
gpt4 key购买 nike

我正在使用 OperationQueue 使用 URLSession.dataTask 将文件一个一个地上传到远程服务器。委托(delegate)用于更新进度条,但在实现 OperationQueue 后,我的委托(delegate)变为零。它在没有 OperationQueues 的情况下工作。在程序运行时查看堆栈,我看不到进度条的 View Controller 。已经好几天了,我还是不太明白。我猜 View Controller 正在被释放,但我不确定如何防止它被释放。谢谢。

我在 NetWorkViewController 中将委托(delegate)设置为 self,但在我的 NetworkManager 类的 urlSession(didSendBodyData) 中,委托(delegate)变为 nil。委托(delegate)并不弱,是一个类变量。

但是,我的委托(delegate)在我的 BlockOperation 的完成 block 中再次变为 none-nil。这适用于通过委托(delegate)解除 ViewController。但是当我尝试在 urlSession(didSendBodyData) 中更新时,委托(delegate)为 nil...

2018 年 10 月 30 日更新

我的 urlSessions 委托(delegate)似乎在一个单独的线程上,并在调用时排入主线程,但我失去了对更新 UI 的自定义委托(delegate)的引用。我正在尝试阅读有关多线程的更多信息,但我们将不胜感激!

更新 2 10/30/2018

找到解决方案 问题是我在每个操作中创建了另一个 NetworkManager 实例。这会导致 delegatenil,因为每个操作都会创建一个新的 NetworkManager 实例。解决方法是从原始 NetworkManager 传递 self,以便保留 delegate

上传文件

    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!)
....
....
}

最佳答案

随着最新代码的共享,我建议将 NetworkManager 实例保留在 class 级别而不是 function 级别范围,因为这将确保 networkManager 实例未被释放。

class NetworkViewController: UIViewController, NetWorkManagerDelegate {

var localEntry: LocalEntry?

var progressBackground = UIView()

var progressBar = UIProgressView()

let networkManager = NetworkManager()

func uploadProgressWith(progress: Float) {
progressBar.progress = progress
view.layoutSubviews()
}

deinit {
print("deallocate")
}

override func viewDidLoad() {
super.viewDidLoad()

networkManager.delegate = self
networkManager.uploadFiles(item: self.localEntry!)
}

...

此外,您需要注意导致内存泄漏的retain-cycles。为避免保留循环,您需要将 delegate 变量声明为 weak

关于ios - delegate 在 urlSession 的操作中变为 nil。如何将委托(delegate)变量保存在单独的线程中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53057783/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com