使用 SwiftUI 显示 SessionDownloadDelegate 的进度
Displaying progress from SessionDownloadDelegate with SwiftUI
我正在尝试使用 SwiftUI 组合一个杂志浏览应用程序,但是 运行 在尝试创建下载进度指示器时遇到了麻烦。我似乎无法找到一种方法来制作 ProgressBar
我在 URLSessionDownloadDelegate
.
中从 urlSession(didWriteData)
进行了更新
我有一个 DownloadManager
作为环境对象传递到主视图,它处理所有杂志期的下载。
class DownloadManager: NSObject, URLSessionDownloadDelegate, ObservableObject {
var activeDownloads: [URL: Download] = [:]
lazy var downloadSession: URLSession = {
let config = URLSessionConfiguration.default
return URLSession(configuration: config, delegate: self, delegateQueue: nil)
}()
/*downloading and saving the issues is handled here*/
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
guard
let url = downloadTask.originalRequest?.url,
let download = activeDownloads[url]
else {
return
}
//this is the value that needs to be indicated by the UI
download.progress = (Float(totalBytesWritten) / Float(totalBytesExpectedToWrite))
}
}
自定义 Download
class 包含以下内容:
class Download {
var issue: Issue
var url: URL
var progress: Float = 0.0
var task: URLSessionDownloadTask?
var resumeData: Data?
init(issue: Issue) {
self.issue = issue
self.url = issue.webLocation
}
}
要下载的可用问题在 List
中的行中显示,并且在下载它们时,进度应该由 ProgressBar
显示。行布局代码的相关部分在这里:
struct IssueRow: View {
var issue: Issue
@EnvironmentObject var downloadManager: DownloadManager
@State var downloadProgress: Float = 0.0
var body: some View {
//the progress bar that needs to continuously update
ProgressBar(value: $downloadProgress)
.frame(height: 4)
}
private func downloadIssue() {
downloadManager.startDownload(issue: issue)
downloadProgress = downloadManager.activeDownloads[issue.webLocation]!.progress
//This does not actually change as the download progresses
}
在 ProgressBar
中,进度存储为 @Binding
浮点数。
struct ProgressBar: View {
@Binding var value: Float
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .leading) {
Rectangle().frame(width: geometry.size.width, height:
geometry.size.height)
.opacity(0.3)
.foregroundColor(Color(UIColor.systemTeal))
Rectangle().frame(width: CGFloat(self.value)*geometry.size.width, height: geometry.size.height)
.foregroundColor(Color.navy)
.animation(.linear)
}
}
}
}
我真的不确定如何将 SwiftUI 的行为及其各种元素与 Swift 中的旧内容同步。非常感谢任何帮助!
方法是在你的下载中注入进度回调闭包,作为桥梁使用。
1) 下载
class Download {
var issue: Issue
var url: URL
var callback: (Float) -> () // << here !!
var progress: Float = 0.0 {
didSet {
self.callback(progress) // << here !!
}
}
// ... other your code here ...
}
2) 在 SwiftUI 中
private func downloadIssue() {
downloadManager.startDownload(issue: issue) { value in // << here !!
DispatchQueue.main.async {
self.downloadProgress = value // make sure on main queue
}
}
}
3) 在 startDownload
中(未提供)将回调闭包传递到创建的 Download
实例中,例如(只是沙哑)
func startDownload(issue: Issue, progress: @escaping (Float) -> ()) {
let download = Download(issue: issue, url: issue.url, callback: progress)
...
}
我正在尝试使用 SwiftUI 组合一个杂志浏览应用程序,但是 运行 在尝试创建下载进度指示器时遇到了麻烦。我似乎无法找到一种方法来制作 ProgressBar
我在 URLSessionDownloadDelegate
.
urlSession(didWriteData)
进行了更新
我有一个 DownloadManager
作为环境对象传递到主视图,它处理所有杂志期的下载。
class DownloadManager: NSObject, URLSessionDownloadDelegate, ObservableObject {
var activeDownloads: [URL: Download] = [:]
lazy var downloadSession: URLSession = {
let config = URLSessionConfiguration.default
return URLSession(configuration: config, delegate: self, delegateQueue: nil)
}()
/*downloading and saving the issues is handled here*/
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
guard
let url = downloadTask.originalRequest?.url,
let download = activeDownloads[url]
else {
return
}
//this is the value that needs to be indicated by the UI
download.progress = (Float(totalBytesWritten) / Float(totalBytesExpectedToWrite))
}
}
自定义 Download
class 包含以下内容:
class Download {
var issue: Issue
var url: URL
var progress: Float = 0.0
var task: URLSessionDownloadTask?
var resumeData: Data?
init(issue: Issue) {
self.issue = issue
self.url = issue.webLocation
}
}
要下载的可用问题在 List
中的行中显示,并且在下载它们时,进度应该由 ProgressBar
显示。行布局代码的相关部分在这里:
struct IssueRow: View {
var issue: Issue
@EnvironmentObject var downloadManager: DownloadManager
@State var downloadProgress: Float = 0.0
var body: some View {
//the progress bar that needs to continuously update
ProgressBar(value: $downloadProgress)
.frame(height: 4)
}
private func downloadIssue() {
downloadManager.startDownload(issue: issue)
downloadProgress = downloadManager.activeDownloads[issue.webLocation]!.progress
//This does not actually change as the download progresses
}
在 ProgressBar
中,进度存储为 @Binding
浮点数。
struct ProgressBar: View {
@Binding var value: Float
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .leading) {
Rectangle().frame(width: geometry.size.width, height:
geometry.size.height)
.opacity(0.3)
.foregroundColor(Color(UIColor.systemTeal))
Rectangle().frame(width: CGFloat(self.value)*geometry.size.width, height: geometry.size.height)
.foregroundColor(Color.navy)
.animation(.linear)
}
}
}
}
我真的不确定如何将 SwiftUI 的行为及其各种元素与 Swift 中的旧内容同步。非常感谢任何帮助!
方法是在你的下载中注入进度回调闭包,作为桥梁使用。
1) 下载
class Download {
var issue: Issue
var url: URL
var callback: (Float) -> () // << here !!
var progress: Float = 0.0 {
didSet {
self.callback(progress) // << here !!
}
}
// ... other your code here ...
}
2) 在 SwiftUI 中
private func downloadIssue() {
downloadManager.startDownload(issue: issue) { value in // << here !!
DispatchQueue.main.async {
self.downloadProgress = value // make sure on main queue
}
}
}
3) 在 startDownload
中(未提供)将回调闭包传递到创建的 Download
实例中,例如(只是沙哑)
func startDownload(issue: Issue, progress: @escaping (Float) -> ()) {
let download = Download(issue: issue, url: issue.url, callback: progress)
...
}