Continuously updates value binding option triggers continuous autosaveInPlace attempts (for every single char you type).
Hello everyone, this is my first question here!
I hope I will ask it correctly… 🙂
I’m trying to add Lion’s autosave mechanism to my core data document-based application.
In my NSPersistentDocument subclass I’m overriding the +(BOOL)autosaveInPlace method returning YES and all the features work correctly (saving, new menus, the version browser…).
My problem is that when I’m typing in text fields bound to my model with the continuously updates value option, the autosave system triggers a save operation upon every single keystroke! The spinning beach-ball does not appear (maybe because my documents are fairly small) but the typing is really really slow.
AutosaveInPlace is called for every key press, and subsequently the saveToURL… and writeToURL… methods.
I found nearly nothing on the subject on the net, and even lesser in the official documentation from Apple.
In the Autosave and Versions WWDC ’11 video the engineer provides an incomplete example of how to cancel an autosave, when [self autosavingIsImplicitlyCancellable] returns YES, but in my case, this method returns always NO. This must be the expected behavior: the value must be continuously updated and as the on-disk file must at all times be identical to the contents the user sees on screen, this save must not be cancelled.
I found a more useful example on the net of how to prevent the save from being initiated in the first place (ovverriding the save… method instead of the write… one).
-(void)saveToURL:(NSURL *)url
ofType:(NSString *)typeName
forSaveOperation:(NSSaveOperationType)saveOperation
completionHandler:(void (^)(NSError *errorOrNil))completionHandler {
if (saveOperation == NSAutosaveInPlaceOperation) {
if ([self isWritingInMyTextField]) {
completionHandler([NSError errorWithDomain:NSCocoaErrorDomain
code:NSUserCancelledError
userInfo:nil]);
return;
}
}
[super saveToURL:url ofType:typeName forSaveOperation:saveOperation completionHandler:completionHandler];
}
This is working. In case of an autosave, if my textfield has the focus, I pass the documented silent cocoa error to the completion handler and the save doesn’t occur, the UI is responsive as before. The original poster claims that in this way the autosave is actually delayed until the current activity ends, but I’m not sure about that.
My problem is that I don’t want to have to observe every single text field for begin/end editing and have to manually trigger an autosave myself every now and then because I’m preventing the system to do it while I’m writing in text fields. The system should just understand it’s not reasonable to trigger a save on a single keystroke basis.
In the WWDC ’11 video, the engineer points to a way of checking for the user activity through NSRunLoop and events but it’s far beyond my understanding. I searched the documentation for NSRunLoop, NSEvent but I can’t figure out how to get the info «the user’s actively typing something!».
If anybody could point me in the right direction on this topic, I’d be grateful.
It would be better if someone knew the recommended way of dealing with this issue!
As a final consideration, I can read in the documentation for NSPersistentDocument that «NSPersistentDocument does not support NSDocument’s asynchronous saving API as that API requires accessing the document’s state on multiple threads and that violates NSManagedObjectContext’s requirements.». Does this mean that unless your app’s documents are very small you shouldn’t use autosave at all?
Well, Apple seems to want autosave to become the new way of doing things for all new apps, so I can’t figure out how it could happen if developers must renounce to core data.
Here’s my working answer.
I don’t know if my
isUserTypingmethod is the greatest way of doing it. The WWDC ’11 video engineer’s use of the run loop to check for user activity remains a mystery for me!