1

I have a custom subclass of UIDocument that I use to store the user's content for my app. I call -[UIDocument updateChangeCount:UIDocumentChangeDone] directly to track changes to the document. Saving and loading work fine, but the document never autosaves. Why would this be happening?

CodeBender
  • 35,668
  • 12
  • 125
  • 132
Jayson
  • 1,689
  • 14
  • 26

2 Answers2

6

It turns out that the problem was that I wasn't calling -[UIDocument updateChangeCount:] from the main thread. Despite the fact that UIDocument isn't a UI element, it is still part of UIKit and so the usual caveats about always interacting with UIKit classes from the main thread still applies.

Wrapping the code in a dispatch to the main queue fixed the issue:

dispatch_async(dispatch_get_main_queue(), ^{
    [doc updateChangeCount:UIDocumentChangeDone];
});
Jayson
  • 1,689
  • 14
  • 26
2

First, an update on Jayson's answer for Swift:

DispatchQueue.main.async {
    doc.updateChangeCount(.done)
}

This works fine if you are just calling it in one or two places. However, if you have multiple calls, and a possibility of them being on background threads, then it may be beneficial to sub class UIDocument and override the updateChangeCount(:) function so that you enforce a main call. Otherwise, you become responsible for making the main call every time, which opens you up to a potential miss, leading to the document getting into the saveError state.

You would then have an override in your subclass like this:

override func updateChangeCount(_ change: UIDocumentChangeKind) {
    DispatchQueue.main.async {
        super.updateChangeCount(change)
    }
}
CodeBender
  • 35,668
  • 12
  • 125
  • 132
  • I actually did something similar, although I added my own method `addChange(_:)` that updates my own change flags and calls `updateChangeCount(_:)` on the main thread. In my case I do want to be able to call `updateChangeCount` synchronously when I know I’m already on the main thread, so the override wouldn’t work. – Jayson Dec 06 '18 at 03:24