最近在研究带参数的捷径。因为是SiriKit
相关,需要把Realm
放在应用组里。这样就不能通过Xcode下载容器了。几天时间里,已经有了两次不小心删除掉数据库,而不得不通过备份恢复手机的经历。我开始研究一下如何导出和恢复数据。
思路
因为目的只是为了方便开发,而不是交给用户操作,过程简便,代码容易是重点。
首先想到的是通过长按某个按钮实现导出,然后出了问题就将导出的数据库放在应用里,应用启动时检测是否有数据,如果有,就替换,然后再正常启动。
实现
具体实现的时候,遇到了一个问题,分享出来的URL
,并没有写成文件,而是写成了纯文本。
@objc private func exportRealm(_ sender:Any) {
let sourceURL = Realm.Configuration.defaultConfiguration.fileURL!
// copy realm to cache and rename it to current date and time
let fm = FileManager.default
let filename = { () -> String in
let df = DateFormatter()
df.dateFormat = "yyyy.MM.dd_HH.mm.ss"
return "any_counter_2.backup.at.\(df.string(from: Date())).realm"
}()
let cacheFolderURL = fm.urls(for: .cachesDirectory, in: .userDomainMask).first!
let destinationURL = URL(fileURLWithPath: filename, isDirectory: false, relativeTo: cacheFolderURL)
do {
try fm.copyItem(at: sourceURL, to: destinationURL)
} catch {
return
}
// export
let activityViewController = UIActivityViewController(activityItems: [destinationURL], applicationActivities: nil)
activityViewController.completionWithItemsHandler = { (_, isCompleted, _, activityError) -> Void in
guard activityError == nil || (activityError! as NSError).code == 3072 else { // Error Domain=NSCocoaErrorDomain Code=3072 \"操作已被取消。\"
fatalError("\(activityError!)")
}
// clear cache after success
try? fm.removeItem(at: destinationURL)
}
present(activityViewController, animated: true, completion: nil)
}
这个问题花费了我不少时间去寻找解决方案。最后我突发奇想解决了。实际上,就是和URL
有关。将12行
let destinationURL = URL(fileURLWithPath: filename, isDirectory: false, relativeTo: cacheFolderURL)
替换为
let destinationURL = URL(fileURLWithPath: cacheFolderURL.path + "/" + filename, isDirectory: false)
,问题解决。
类似的事情很早就遇到过,比如
import Foundation
let folder = "/foo"
let file = "bar"
let folderURL = URL(fileURLWithPath: folder, isDirectory: true)
let u1 = URL(fileURLWithPath: file, isDirectory: false, relativeTo: folderURL)
print(u1.path) // /foo/bar
let u2 = URL(fileURLWithPath: folder + "/" + file, isDirectory: false)
print(u2.path) // /foo/bar
print(u1 == u2) // false
print(u1.path == u2.path) // true
即两个path
相同的URL
,仅仅是因为构造方法的不同,它们就不相等。这其实是很不直观的,人们在没遇到之前,可能就会认为path
相等的两个URL
就是相等的,但是实际上系统认为不是。
这里也是这样,通过relativeTo
构造的URL
,iOS系统仅能将它存成一个纯文本。但是直接构造的URL
就没有这个问题。
我虽然不认同,但是只能记住。