iOS Swift多文件本地下载问题:文件存在却提示不存在
问题排查与修复方案
1. 强制解包clientUrl引发的URL失效问题
你在循环中直接用clientUrl!强制解包,若传入的"File location url"格式无效(比如缺少http/https前缀、字符串格式错误),URL(string:)会返回nil,强制解包不仅会触发崩溃,还会传入无效URL执行下载,直接导致“文件不存在”的错误。
修复代码:
if let screens = ServerDrivenUIComponent.sharedInstance.appGenericUIModel?.screens { for aScreen in screens { // 替换硬编码字符串,从aScreen中获取真实文件URL guard let clientUrl = URL(string: aScreen.fileUrlString) else { print("无效文件URL: \(aScreen.fileUrlString)") continue } FileDownloader.loadFileAsync(folder: self.selectedClient, url: clientUrl) { destinationPath, error in if let path = destinationPath { print("文件下载完成: \(path)") } else if let err = error { print("下载失败: \(err.localizedDescription)") } } } }
2. 未使用folder参数,文件存储路径不符合预期
loadFileAsync方法接收了folder参数,但完全没用到,所有文件都直接下载到documentDirectory根目录,而非你预期的selectedClient子文件夹。如果业务逻辑要求文件存放在对应folder下,自然会出现找不到文件的情况。
修复代码:
static func loadFileAsync(folder: String, url: URL, completion: @escaping (String?, Error?) -> Void) { guard let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { completion(nil, NSError(domain: "FileDownloadError", code: -1, userInfo: [NSLocalizedDescriptionKey: "无法获取文档目录"])) return } // 构建带目标文件夹的路径 let folderUrl = documentsUrl.appendingPathComponent(folder) // 确保文件夹存在,不存在则创建 do { try FileManager.default.createDirectory(at: folderUrl, withIntermediateDirectories: true) } catch { completion(nil, error) return } let destinationUrl = folderUrl.appendingPathComponent(url.lastPathComponent) // 后续原有逻辑保持不变... }
3. HTTP状态码判断逻辑错误
当状态码不是200时,你直接传递error,但此时error是nil(因为前面判断了error == nil),导致上层无法获取真实错误原因,且打印的"File is not present"表述不准确(比如500服务器错误、403权限错误都不是文件不存在)。
修复代码:
if let statusCode = (response as? HTTPURLResponse)?.statusCode { if statusCode == 200 { do { try FileManager.default.copyItem(at: tempLocalUrl, to: destinationUrl) completion(destinationUrl.path, nil) } catch let writeError { print("文件保存失败: \(writeError)") completion(nil, writeError) } } else { let error = NSError(domain: "HTTPError", code: statusCode, userInfo: [NSLocalizedDescriptionKey: "请求失败,状态码: \(statusCode)"]) print("请求失败: \(url.absoluteString),状态码: \(statusCode)") completion(nil, error) } }
4. 关键错误处理缺失
- 删除已有文件的
catch块为空,无法感知删除失败的问题; - 下载任务的
else块为空,未将下载错误传递给completion,导致上层无法知晓失败原因。
修复代码:
// 处理文件删除错误 if FileManager.default.fileExists(atPath: destinationUrl.path) { print("文件已存在,删除旧文件: \(destinationUrl.path)") do { try FileManager.default.removeItem(at: destinationUrl) } catch let deleteError { print("删除旧文件失败: \(deleteError)") completion(nil, deleteError) return } } // 处理下载任务错误 else { print("下载失败: \(error?.localizedDescription ?? "未知错误")") completion(nil, error) }
5. 重复创建URLSession浪费资源
每次调用loadFileAsync都新建URLSession,会造成资源浪费,并发下载时可能出现异常,应复用URLSession.shared单例。
修复代码:
// 替换原session创建代码,使用共享单例 let task = URLSession.shared.downloadTask(with: request) { (tempLocalUrl, response, error) in // 后续逻辑不变... }
内容的提问来源于stack exchange,提问作者Juno
相关产品推荐
相关产品推荐

