如何从Swift命令行工具写入配置文件至plist?
解决Swift命令行工具plist配置持久化问题
你猜的完全没错!Xcode在运行命令行工具时,会把构建产物放到一个临时的沙盒目录里,进程结束后这个目录就会被自动清理,所以你修改的只是临时副本,原始plist自然不会有任何变化。要实现配置的持久化,得把plist文件放到系统指定的用户持久化存储目录中,下面是具体的实现步骤:
1. 确定正确的持久化目录
macOS有专门的目录用于存储应用的用户数据,最适合存放配置文件的是Application Support目录,你可以通过FileManager获取这个目录的路径:
import Foundation func getApplicationSupportDirectory() -> URL? { guard let appSupportDir = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first else { return nil } // 为你的命令行工具创建专属子目录,避免和其他应用的文件冲突 let toolDir = appSupportDir.appendingPathComponent("YourToolUniqueName", isDirectory: true) // 如果目录不存在就创建它 do { try FileManager.default.createDirectory(at: toolDir, withIntermediateDirectories: true) return toolDir } catch { print("创建持久化目录失败:\(error)") return nil } }
2. 初始化配置文件(第一次运行时)
把你原来的plist文件作为项目资源保留(不要再用Copy Files Phase复制到产品目录),在工具第一次运行时,将初始plist复制到上面获取的Application Support目录中:
func initializeConfigPlist() -> URL? { guard let appSupportDir = getApplicationSupportDirectory() else { return nil } let targetPlistURL = appSupportDir.appendingPathComponent("UserConfig.plist") // 如果目标文件已经存在,直接返回路径 if FileManager.default.fileExists(atPath: targetPlistURL.path) { return targetPlistURL } // 从项目资源中获取初始plist的路径 guard let sourcePlistURL = Bundle.main.url(forResource: "UserConfig", withExtension: "plist") else { print("找不到初始配置文件") return nil } // 复制初始文件到持久化目录 do { try FileManager.default.copyItem(at: sourcePlistURL, to: targetPlistURL) return targetPlistURL } catch { print("复制初始配置失败:\(error)") return nil } }
3. 读写持久化的plist文件
现在你可以直接操作initializeConfigPlist()返回的URL对应的文件,所有修改都会被持久化保存:
// 读取用户配置 func readUserConfig() -> [String: Any]? { guard let plistURL = initializeConfigPlist() else { return nil } do { let data = try Data(contentsOf: plistURL) return try PropertyListSerialization.propertyList(from: data, options: [], format: nil) as? [String: Any] } catch { print("读取配置失败:\(error)") return nil } } // 更新用户配置 func updateUserConfig(with newConfig: [String: Any]) -> Bool { guard let plistURL = initializeConfigPlist() else { return false } do { let data = try PropertyListSerialization.data(fromPropertyList: newConfig, format: .xml, options: 0) try data.write(to: plistURL) return true } catch { print("更新配置失败:\(error)") return false } }
额外提示:用UserDefaults简化操作
如果你不需要手动管理plist文件,也可以直接用UserDefaults,它会自动把配置存储到用户的偏好设置目录中(底层也是plist文件),用法更简洁:
// 读取配置 let userName = UserDefaults.standard.string(forKey: "UserName") // 写入配置 UserDefaults.standard.set("Jay Wang", forKey: "UserName") // 立即同步(可选,系统会自动定时同步) UserDefaults.standard.synchronize()
内容的提问来源于stack exchange,提问作者Jay Wang
相关产品推荐
相关产品推荐

