I have an app that uses NSPersistentCloudKitContainer
stored in a shared location via App Groups so my widget can fetch data to display. It works. But if you reset your iPhone and restore it from a backup, an error occurs:
The file "Name.sqlite" couldn't be opened
. I suspect this happens because the widget is created before the app's data is restored. Restarting the iPhone is the only way to fix it though, opening the app and reloading timelines does not. Anything I can do to fix that to not require turning it off and on again?
I confirmed upon restore the sqlite file exists but sqlite-wal does not - it won’t open without that file.
Correct. For context, "WAL" stands for "Write-Ahead Logging" and is part of the architecture sqlite uses to maintain data integrity. I guess/suspect that it's not be backed up because, assuming the database is being properly managed, it should generally be "empty" anytime it would have been backed up (because the contents were merged into the file at close/suspend). You can read more about it here:
https://www.sqlite.org/wal.html
But the critical point is:
...Beginning with version 3.22.0 (2018-01-22), a read-only WAL-mode database file can be opened if the -shm and -wal files already exist or those files can be created or the database is immutable.
SO, basically, yes, what you're seeing is expected behavior.
Shifting to the workaround side, I would to three things:
(1) Implement a fallback "there's a problem, open the app" UI. It's likely that you've identified the primary (possibly "only") issue here, but I'm a big believer in having "fallback" plans in place. The critical benefit here is that if/when your users start seeing this UI, you "know" that the solution below didn't cover what ever happened
So I can work around the issue by setting isReadOnly only when the sqlite-wal file exists.
(2) I would actually just try opening the file read only and going to #3 if it fails. You might think about checking for the WAL file as a secondary diagnostic, but I'd avoid relying on the EXACT details* of the configuration.
*For example, I can't guarantee that their aren't cases where the WAL file does exist, r/o opens will fail, and which a r/w open will resolve. If you specifically check for the WAL file, then you'll end up "skipping" cases you'd other wise fix.
That means it would be in read/write mode until the user restarts the iPhone then it’ll be read-only. I’m wondering if that's a bad idea.
Yes, that's a bad idea, as it creates a situation where your widget is sometimes read only or sometimes read write and you'd potentially need to be auditing both of those code paths "fully". Honestly, I think you'd be better of being read write "all the time" in that case, as you'd at least be testing that path much more throughly. However, what I'd actually recommend is:
(3) Do a read/write open, then destroy those CoreData object and do your read only open again. I think that will let you open the file and it means the read/write sequence is trivial to debug/verify (since the file is barely open at all).
__
Kevin Elliott
DTS Engineering, CoreOS/Hardware