From the Core Data Programming Guide:

"If you do not intend to use Core Data's undo functionality, you can reduce your application's resource requirements by setting the context’s undo manager to nil. This may be especially beneficial for background worker threads..."

Well, I've got a background worker process which opens an NSPersistenDocument. Since it has no "undo" capability, I want to set it to nil as recommended. (I have other reasons for not wanting an undo manager scurrying around.) But the document doesn't like having nil undo manager. When I ask for it later, it creates one for itself, and sets its managed object context to have the same one.

This is easily demonstrated by adding the following method to DepartmentAndEmployees project, in the implementation of MyDocument:

- (id)init {
    self = [super init] ;
    if (self) {
        // Set both doc's and moc's undo manager to nil
        [[self managedObjectContext] setUndoManager:nil] ;
        [self setUndoManager:nil] ;

        // Get and log them
NSLog(@"1: moc's undoManager = %@", [[self managedObjectContext] undoManager]) ;
        NSLog(@"2: doc's undoManager = %@", [self undoManager]) ;
NSLog(@"3: moc's undoManager = %@", [[self managedObjectContext] undoManager]) ;
    }

    return self ;
}

Here is the debugger Log Output, with breakpoint set at - [NSManagedObjectContext setUndoManager:]

Running…
(gdb) continue
(gdb) continue
(gdb) continue
(gdb) continue
Test[61463:813] 1: moc's undoManager = (null)   ## This is good.
(gdb) p/a *(int *)($esp+8)
$1 = 0x161a80
(gdb) continue
Test[61463:813] 2: doc's undoManager = <NSUndoManager: 0x161a80> ## Arghh!! Test[61463:813] 3: moc's undoManager = <NSUndoManager: 0x161a80> ## Arghh!!

Here is the call stack at the last break. I typed the p/a command when viewing #1.

#0      0x92af7cf6 in -[NSManagedObjectContext setUndoManager:]
#1      0x91cc3f4d in -[NSPersistentDocument setUndoManager:]
#2      0x91969ea9 in -[NSDocument undoManager]
#3      0x00002f0f in -[MyDocument init] at MyDocument.m:358

Apparently when -[NSDocument undoManager] sees that its undo manager is nil (because I set it to nil), it says to itself, "Golly, we need an undo manager here. So it creates one, sets it in the subclass - [NSPersistentDocument setUndoManager:], which in turn says, "Gee, our moc needs this too", and then invokes -[NSManagedObjectContext setUndoManager:].

The obvious solution would be to add to the init method:

   [self setHasUndoManager:nil] ;

which would probably work for NSDocument but for NSPersistentDocument, the documentation says:

   "Overridden to be a no-op  ... You should not override this method.
The persistent document uses the managed object context’s undo manager."

Overriding -hasUndoManager didn't work either.  It's never invoked.

However, my third guess seems to be working. In the MyDocument implementation I overrode...

- (NSUndoManager*)undoManager {
    return nil ;
}

This seems to work. I can add employees, delete employees, open and save documents, and there are no crashes or whineys printed to the console. In the menu, Edit > Undo is always disabled, as expected.

In my actual application, my document subclass is in a framework, of which my non-gui background worker and the gui app are thin wrappers. So, I condition the code in the above methods with if(!NSApp).

Am I violating the "spirit of the docs" here, or is this solution OK?

Sincerely,

Jerry Krinock

_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to