Discussion:
Programmatically Clear Dirty NSDocument
Richard Charles
2016-11-07 18:46:00 UTC
Permalink
I have a dirty document that needs to be cleared programmatically. So I try the following but it does not work. I have verified that updateChangeCount: is being called but the document change count state is not being changed. This code is executed on the main thread.

// Called from a controller.
// This does not work.
NSDocument *doc = self.myDocument;
[doc updateChangeCount:NSChangeUndone];

So next I try the following. When a function key is pressed the following code is executed. This is exactly the same as before but it now works! The document is no longer dirty. This code is also executed on the main thread.

// Called with a function key press.
// This works fine.
NSDocument *doc = self.myDocument;
[doc updateChangeCount:NSChangeUndone];

So next I try the following using performSelector. But this does not work at all when called from a controller or when called with a function key press.

// This does not work at all.
NSDocument *doc = self.myDocument;
[doc performSelector:@selector(updateChangeCount:)
withObject:@(NSChangeUndone)
afterDelay:0];

So why does successfully calling -[NSDocument updateChangeCount:] have a hidden dependency on the run loop?

--Richard Charles


_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

This email sent to ***@ml-i
Jens Alfke
2016-11-07 19:24:04 UTC
Permalink
Post by Richard Charles
afterDelay:0];
That one definitely won’t work. The parameter to updateChangeCount: is an integer (enum) value, not an object reference, but you’re calling it with an NSNumber object. The value actually passed to the method will be a garbage value based on the raw address* of the NSNumber object.

If you want to use a delayed-perform to call a method that takes a non-object parameter, you have to create a new method that makes the call you want, then invoke _that_ method using a delayed perform. (Or you could just do things the modern way, with dispatch_async and a block.)

—Jens

* I’m aware that small integers don’t turn into real NSNumber objects on the heap, rather a tagged pointer, but the result is the same: a pointer that will result in a garbage value when interpreted as an integer.
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

This em
Richard Charles
2016-11-07 21:41:52 UTC
Permalink
Post by Jens Alfke
Post by Richard Charles
afterDelay:0];
That one definitely won’t work. The parameter to updateChangeCount: is an integer (enum) value, not an object reference, but you’re calling it with an NSNumber object. The value actually passed to the method will be a garbage value based on the raw address* of the NSNumber object.
You are right, the method is passed a garbage value! I was under the mistaken assumption that the frameworks would take care of this conversion for me. (Cocoa magic has cast a spell on me.)
Post by Jens Alfke
If you want to use a delayed-perform to call a method that takes a non-object parameter, you have to create a new method that makes the call you want, then invoke _that_ method using a delayed perform.
That works.
Post by Jens Alfke
(Or you could just do things the modern way, with dispatch_async and a block.)
That also works.
Post by Jens Alfke
* I’m aware that small integers don’t turn into real NSNumber objects on the heap, rather a tagged pointer, but the result is the same: a pointer that will result in a garbage value when interpreted as an integer.
Very accurate answer Jens. Thanks so much for the help.

Life is good again. :)

--Richard Charles


_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

Th
Jonathan Mitchell
2016-11-07 19:28:48 UTC
Permalink
Post by Richard Charles
NSChangeUndone
try NSChangeCleared



_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-i
Jens Alfke
2016-11-07 19:59:03 UTC
Permalink
Why not just call [doc revertToContentsOfURL:[doc url] ofType:[doc fileType] error:&error], which is what the docs for -revertDocumentToSaved: say it does after the user confirmation?

—Jens
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

This email sent to ***@m
Quincey Morris
2016-11-07 21:33:46 UTC
Permalink
Post by Richard Charles
This is exactly the same as before but it now works!
Regarding that particular mystery, NSChangeUndone decrements the change count. If it happened to be 1 when you tried this, the document would stop being dirty. Presumably, in your first test, the change count was greater than 1. As Jens said, the third test was invalid.

_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-
Richard Charles
2016-11-07 22:02:03 UTC
Permalink
Post by Quincey Morris
Post by Richard Charles
This is exactly the same as before but it now works!
Regarding that particular mystery, NSChangeUndone decrements the change count. If it happened to be 1 when you tried this, the document would stop being dirty. Presumably, in your first test, the change count was greater than 1. As Jens said, the third test was invalid.
Yes this has been a mystery. Thanks for the insight. Up until a day ago I did not even know that NSDocument had something called a change count.

It appears that the following is what was happening.
Post by Quincey Morris
// Called from a controller.
// This does not work.
NSDocument *doc = self.myDocument;
[doc updateChangeCount:NSChangeUndone];
The above did not work because it needs to be called later in the run loop.
Post by Quincey Morris
// Called with a function key press.
// This works fine.
NSDocument *doc = self.myDocument;
[doc updateChangeCount:NSChangeUndone];
The above worked fine because it was done manually in a dedicated run of the run loop with a key press.
Post by Quincey Morris
// This does not work at all.
NSDocument *doc = self.myDocument;
afterDelay:0];
As Jens pointed out the above could never work.

But I am off and running now. Thanks so much.

--Richard Charles


_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkiv
Loading...