Xcode代码报错求助:多个SwiftUI编译错误排查修复
SwiftUI项目编译错误修复方案
逐个错误排查与修复
1. Invalid redeclaration of ContentView
- 问题:项目中存在重复的
ContentView定义,或Xcode缓存导致识别错误。 - 修复:
- 检查所有.swift文件,删除其他定义
ContentView的代码; - 执行Xcode清理操作:
Cmd + Shift + K清除缓存后重新编译。
- 检查所有.swift文件,删除其他定义
2. Instance will be immediately deallocated because property navigationDelegate is weak
- 问题:
WKWebView的navigationDelegate是弱引用,直接创建的WebViewCoordinator没有强引用持有,会被立即释放。 - 修复:在
BrowserView中用@State持有WebViewCoordinator实例,确保生命周期匹配:struct BrowserView: View { @State private var webView = WKWebView() @State private var coordinator: WebViewCoordinator? var body: some View { WebView(webView: $webView) .onAppear { if let url = URL(string: "https://youtube.com") { webView.load(URLRequest(url: url)) } coordinator = WebViewCoordinator() webView.navigationDelegate = coordinator } } }
3. weak may only be applied to class and class-bound protocol types, not FilesView
- 问题:
FilesView是SwiftUI值类型(struct),weak仅适用于类类型。 - 修复:将
FilesView的状态抽离到ObservableObject类中,让Coordinator持有该类的弱引用:class FilesViewModel: ObservableObject { @Published var downloadedFiles = [String]() @Published var storageTaken: String = "" func loadFiles() { // 原loadFiles逻辑 } } struct FilesView: View { @StateObject private var viewModel = FilesViewModel() var body: some View { VStack { List(viewModel.downloadedFiles, id: \.self) { Text($0) } Text("Storage Taken: \(viewModel.storageTaken)") } .onAppear(perform: viewModel.loadFiles) } } class WebViewCoordinator: NSObject, WKNavigationDelegate { weak var filesViewModel: FilesViewModel? init(filesViewModel: FilesViewModel? = nil) { self.filesViewModel = filesViewModel } }
4. Value of type WebViewCoordinator has no member getDocumentsDirectory
- 问题:
getDocumentsDirectory是全局函数,类中调用需确保作用域。 - 修复:将全局函数转为
FileManager扩展,调用更规范:extension FileManager { static func getDocumentsDirectory() -> URL { let paths = self.default.urls(for: .documentDirectory, in: .userDomainMask) return paths[0] } } // Coordinator中调用方式 let destinationURL = FileManager.getDocumentsDirectory().appendingPathComponent("\(sanitizeFileName(fileName: title)).mp4")
5. Value of type WebViewCoordinator has no member sanitizeFileName
- 问题:同全局函数调用问题,直接调用全局函数即可,无需修改函数本身。
6. Value of type [URLResourceKey: Any] has no member totalFileAllocatedSize
- 问题:原
NSURL的fileSize()方法未完成,获取文件大小的方式错误。 - 修复:完善
URL扩展的fileSize()方法:extension URL { func fileSize() -> Int { guard let attributes = try? FileManager.default.attributesOfItem(atPath: path) else { return 0 } return attributes[.size] as? Int ?? 0 } } // 计算存储占用的调用方式 let size = files.reduce(0, { $0 + $1.fileSize() })
完整修复后的代码
import SwiftUI import WebKit // 统一通知名称定义 extension Notification.Name { static let downloadCompleted = Notification.Name("DownloadCompleted") } @main struct UDOWNLOADERZApp: App { var body: some Scene { WindowGroup { ContentView() } } } struct ContentView: View { var body: some View { TabView { BrowserView() .tabItem { Label("Browser", systemImage: "globe") } FilesView() .tabItem { Label("Files", systemImage: "folder") } SettingsView() .tabItem { Label("Settings", systemImage: "gearshape") } } } } struct BrowserView: View { @State private var webView = WKWebView() @State private var coordinator: WebViewCoordinator? var body: some View { WebView(webView: $webView) .onAppear { if let url = URL(string: "https://youtube.com") { webView.load(URLRequest(url: url)) } coordinator = WebViewCoordinator() webView.navigationDelegate = coordinator } } } struct WebView: UIViewRepresentable { @Binding var webView: WKWebView func makeUIView(context: Context) -> WKWebView { webView } func updateUIView(_ uiView: WKWebView, context: Context) {} } class WebViewCoordinator: NSObject, WKNavigationDelegate { weak var filesViewModel: FilesViewModel? init(filesViewModel: FilesViewModel? = nil) { self.filesViewModel = filesViewModel } func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { let jsCode = """ (function() { var video = document.querySelector('video'); var audio = document.querySelector('audio'); var mediaElement = video || audio; if (mediaElement) { return { src: mediaElement.src, title: document.title || mediaElement.getAttribute('title') || 'Unknown' }; } return null; })(); """ webView.evaluateJavaScript(jsCode) { [weak self] result, error in guard let resultDict = result as? [String: String], let urlString = resultDict["src"], let title = resultDict["title"], let url = URL(string: urlString) else { return } self?.downloadContent(url: url, title: title) } } func downloadContent(url: URL, title: String) { DispatchQueue.global().async { let destinationURL = FileManager.getDocumentsDirectory().appendingPathComponent("\(sanitizeFileName(fileName: title)).mp4") URLSession.shared.downloadTask(with: url) { tempURL, _, error in guard let tempURL = tempURL, error == nil else { return } do { try FileManager.default.moveItem(at: tempURL, to: destinationURL) DispatchQueue.main.async { NotificationCenter.default.post(name: .downloadCompleted, object: nil) self.filesViewModel?.reloadFilesList() } } catch { print("Download failed: \(error.localizedDescription)") } }.resume() } } } class FilesViewModel: ObservableObject { @Published var downloadedFiles = [String]() @Published var storageTaken: String = "" func loadFiles() { DispatchQueue.global().async { do { let files = try FileManager.default.contentsOfDirectory(at: FileManager.getDocumentsDirectory(), includingPropertiesForKeys: nil, options: []) DispatchQueue.main.async { self.downloadedFiles = files.map { $0.lastPathComponent } self.calculateStorageTaken(files: files) } } catch { print("Failed to load files: \(error.localizedDescription)") } } } func reloadFilesList() { loadFiles() } private func calculateStorageTaken(files: [URL]) { let size = files.reduce(0, { $0 + $1.fileSize() }) storageTaken = ByteCountFormatter.string(fromByteCount: Int64(size), countStyle: .file) } } struct FilesView: View { @StateObject private var viewModel = FilesViewModel() var body: some View { VStack { List(viewModel.downloadedFiles, id: \.self) { Text($0) } Text("Storage Taken: \(viewModel.storageTaken)") } .onAppear(perform: viewModel.loadFiles) .onReceive(NotificationCenter.default.publisher(for: .downloadCompleted)) { _ in viewModel.reloadFilesList() } } } struct SettingsView: View { var body: some View { VStack { Text("Contact: Udownloaderz2@proton.me") Text("Twitter: N/A") } } } extension FileManager { static func getDocumentsDirectory() -> URL { let paths = self.default.urls(for: .documentDirectory, in: .userDomainMask) return paths[0] } } func sanitizeFileName(fileName: String) -> String { let invalidCharacters = CharacterSet(charactersIn: "\\/:*?\"<>|") return fileName.components(separatedBy: invalidCharacters).joined(separator: "_") } extension URL { func fileSize() -> Int { guard let attributes = try? FileManager.default.attributesOfItem(atPath: path) else { return 0 } return attributes[.size] as? Int ?? 0 } }
内容的提问来源于stack exchange,提问作者rights4a
相关产品推荐
相关产品推荐

