You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Swift开发:如何列出iPhone及iCloud Drive的PDF/文本文件?代码返回nil

解决获取设备及iCloud Drive中PDF/文本文件的问题

首先,咱们先拆解你现有代码返回nil的核心问题,再一步步实现完整需求:

一、原代码返回Nil的关键原因

  1. 错误被静默吞掉:你用try?调用contentsOfDirectory,如果读取目录时遇到权限不足、目录不存在等问题,会直接返回nil,但你看不到具体错误原因,没法排查问题。
  2. 缺乏安全判断:直接取urls(for:directory, in:.userDomainMask)[0],如果这个数组为空(虽然概率极低,但严谨性不足),会直接触发崩溃。
  3. 仅覆盖本地目录:你的代码只处理了本地documentDirectory,完全没涉及iCloud Drive的内容,不符合你“设备及iCloud Drive”的需求。

二、修复并实现完整需求的代码

第一步:修复本地目录读取,添加错误捕获

先修改FileManager扩展,让它能抛出错误,方便我们定位问题:

extension FileManager {
    func urls(for directory: FileManager.SearchPathDirectory, skipsHiddenFiles: Bool = true) throws -> [URL] {
        guard let baseURL = urls(for: directory, in: .userDomainMask).first else {
            throw NSError(domain: "FileManagerError", code: -1, userInfo: [NSLocalizedDescriptionKey: "指定目录不存在"])
        }
        let options: FileManager.DirectoryEnumerationOptions = skipsHiddenFiles ? .skipsHiddenFiles : []
        return try contentsOfDirectory(at: baseURL, includingPropertiesForKeys: nil, options: options)
    }
}

调用时用do-catch捕获错误:

do {
    let localFiles = try FileManager.default.urls(for: .documentDirectory)
    print("本地文件列表:\(localFiles)")
} catch {
    print("读取本地目录出错:\(error.localizedDescription)")
}

第二步:添加iCloud Drive文件读取能力

要访问iCloud Drive,先完成项目配置:

  • 打开Xcode项目的Signing & Capabilities,添加iCloud能力,勾选iCloud Documents
  • Info.plist里添加NSUbiquitousContainers配置,指定你的iCloud容器ID(格式一般是iCloud.你的BundleID

然后添加读取iCloud Drive的方法:

extension FileManager {
    func iCloudDriveDocumentsURL() -> URL? {
        return url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents")
    }
    
    func urlsIniCloudDrive(skipsHiddenFiles: Bool = true) throws -> [URL] {
        guard let iCloudURL = iCloudDriveDocumentsURL() else {
            throw NSError(domain: "FileManagerError", code: -2, userInfo: [NSLocalizedDescriptionKey: "未开启iCloud Drive或权限不足"])
        }
        let options: FileManager.DirectoryEnumerationOptions = skipsHiddenFiles ? .skipsHiddenFiles : []
        return try contentsOfDirectory(at: iCloudURL, includingPropertiesForKeys: nil, options: options)
    }
}

第三步:过滤PDF和文本文件

添加筛选逻辑,只保留.pdf.txt(可按需添加.md等其他文本格式)的文件:

func filterPDFAndTextFiles(from urls: [URL]) -> [URL] {
    let validExtensions = Set(["pdf", "txt", "md"]) // 可根据需求扩展格式
    return urls.filter { url in
        guard let ext = url.pathExtension.lowercased() else { return false }
        return validExtensions.contains(ext)
    }
}

第四步:整合调用逻辑

// 读取本地PDF/文本文件
do {
    let localFiles = try FileManager.default.urls(for: .documentDirectory)
    let localTargetFiles = filterPDFAndTextFiles(from: localFiles)
    print("本地PDF/文本文件:\(localTargetFiles)")
} catch {
    print("读取本地目录失败:\(error)")
}

// 读取iCloud Drive的PDF/文本文件
do {
    let iCloudFiles = try FileManager.default.urlsIniCloudDrive()
    let iCloudTargetFiles = filterPDFAndTextFiles(from: iCloudFiles)
    print("iCloud Drive的PDF/文本文件:\(iCloudTargetFiles)")
} catch {
    print("读取iCloud Drive失败:\(error)")
}

三、额外注意事项

  • 权限请求:第一次访问iCloud Drive时,系统会自动弹出权限请求,用户需要允许才能访问
  • 递归遍历子目录:如果需要读取子文件夹里的文件,把contentsOfDirectory换成enumerator(at:includingPropertiesForKeys:options:errorHandler:)实现递归遍历
  • iCloud同步状态:iCloud Drive的文件可能处于同步中,可通过URLResourceKey.isUbiquitousItemKeyURLResourceKey.ubiquitousItemDownloadingStatusKey检查同步状态,确保文件已下载到本地再处理

内容的提问来源于stack exchange,提问作者Mr Abbasi

火山引擎 最新活动