我有以下代码来为 URL 添加书签以供将来访问:
private func checkForSQLiteFiles(at containerURL: URL, appName: String) {
do {
viewModel.connect(strConnect: selectedSQLiteFile!.path)
viewModel.fetchAllTables()
// Save selected SQLite file to UserDefaults
UserDefaults.standard.set(selectedSQLiteFile, forKey: "selectedSQLiteFile")
saveBookmark(for: selectedSQLiteFile!, key: "SQLiteBookmark")
}
} catch {
errorMessages.append("Error")
}
}
func saveBookmark(for url: URL, key: String) {
do {
let bookmarkData = try url.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil)
UserDefaults.standard.set(bookmarkData, forKey: key)
} catch {
print("Failed to create bookmark for \(url.path): \(error)")
}
}
上面的代码运行良好。顺便说一句,我可以使用
NSOpenPanel
访问我选择的文件/目录。
在另一个地方,我有代码从书签恢复 URL,尝试连接,并使用我之前使用的相同文件再次请求数据库。
private func openExistingProject() {
if let sqliteURL = resolveBookmark(for: "SQLiteBookmark") {
if sqliteURL.startAccessingSecurityScopedResource() {
// Check if file is readable and exists
if FileManager.default.isReadableFile(atPath: sqliteURL.path) {
print("SQLite file is readable at path: \(sqliteURL.path)")
// Proceed to connect and load entities
viewModel.connect(strConnect: sqliteURL.path)
viewModel.fetchAllTables()
} else {
print("Failed to access the SQLite file at \(sqliteURL.path)")
}
} else {
print("Failed to access the security-scoped resource for \(sqliteURL.path)")
}
defer { sqliteURL.stopAccessingSecurityScopedResource() }
} else {
print("No valid bookmark for SQLite file")
}
}
func resolveBookmark(for key: String) -> URL? {
if let bookmarkData = UserDefaults.standard.data(forKey: key) {
var isStale = false
do {
let url = try URL(resolvingBookmarkData: bookmarkData, options: .withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &isStale)
if isStale {
print("Bookmark data is stale for \(url.path)")
}
return url
} catch {
print("Failed to resolve bookmark for key \(key): \(error)")
}
}
return nil
}
但是当我在 ViewModel 中调用
fetchAllTables()
时:
class SQLiteEntityManager: ObservableObject {
@Published var isConnected: Bool = false
private var db: Connection?
func connect(strConnect: String) {
// Define the path to the SQLite database file
let dbPath = strConnect
// Create a connection to the database
do {
db = try Connection(dbPath)
isConnected = true
} catch {
print("Unable to open database. Error: \(error)")
}
}
func fetchAllTables() -> [String] {
guard let db = db else {
print("Database is not connected")
return []
}
do {
let tables = try db.prepare("SELECT name FROM sqlite_master WHERE type='table'")
return tables.map { "\($0[0]!)" }
} catch {
print("Error fetching tables: \(error)")
return []
}
}
}
失败并显示
"Error fetching tables: access denied (code:23)"
。但它仍然可以使用该书签 URL 成功连接到该数据库,没有任何问题。
仅当我尝试执行 db.prepare(".....") 时才会发生错误。
如有任何建议,我们将不胜感激
尝试检查竞争条件问题,我认为您应该仅在建立连接后调用 fetchAllTables()
作为快速测试,您可以尝试在
func fetchAllTables()
之后致电
db = try Connection(dbPath)