Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

MrFusion

macrumors 6502a
Original poster
Jun 8, 2005
613
0
West-Europe
Is it possible to have maximum one instance of a custom class for each NSDocument? If so, how would you guarantee such a thing?
 
Subclass NSDocument. Give it a read-only property that returns the custom "only-one-per-NSDocument" class. In the getter for the property, only make an instance of the custom class when the ivar supporting it is null. Manage ownership to match the NSDocument instance lifetime.

http://developer.apple.com/library/...ptual/Documents/Tasks/SubclassNSDocument.html

If you can't subclass NSDocument, then it's harder. You have to correlate each NSDocument instance with a single instance of your custom class. An NSMutableDictionary can do the correlation, but you won't be able to use an NSDocument instance as the key, because a copy will be stored as the key. You can use the object-address of the NSDocument to make an NSNumber, and use that as the key. Then you're basically using the object's pointer as a key.

There's probably an NSSomethingOrOther collection class that does this mapping between any-pointer-as-key and any-other-pointer-as-value, but I'm not recalling what the class name is. It would behoove you to read the Collections Programming Guide. It would behoove me to do the same, but I have less vested interest in doing so right now.
 
If you can't subclass NSDocument, then it's harder.

"can't subclass NSDocument" makes no sense. NSDocument is an abstract class that merely provides the basic conveniences you need to handle a document-based application. On it's own, it has no useful functionality, you have to subclass it to be able to do anything with it.
 
Subclass NSDocument. Give it a read-only property that returns the custom "only-one-per-NSDocument" class. In the getter for the property, only make an instance of the custom class when the ivar supporting it is null. Manage ownership to match the NSDocument instance lifetime.

http://developer.apple.com/library/...ptual/Documents/Tasks/SubclassNSDocument.html

If you can't subclass NSDocument, then it's harder. You have to correlate each NSDocument instance with a single instance of your custom class. An NSMutableDictionary can do the correlation, but you won't be able to use an NSDocument instance as the key, because a copy will be stored as the key. You can use the object-address of the NSDocument to make an NSNumber, and use that as the key. Then you're basically using the object's pointer as a key.

There's probably an NSSomethingOrOther collection class that does this mapping between any-pointer-as-key and any-other-pointer-as-value, but I'm not recalling what the class name is. It would behoove you to read the Collections Programming Guide. It would behoove me to do the same, but I have less vested interest in doing so right now.

Yes, that works provided that I only use "MyDocument" to retrieve an "only-one-per-NSDocument" instance. It doesn't prevent me (or someone else) from using the init method of the "only-one-per-NSDocument" and getting a second instance.
I will have a look at the Collections Programming Guide.
 
Yes, that works provided that I only use "MyDocument" to retrieve an "only-one-per-NSDocument" instance. It doesn't prevent me (or someone else) from using the init method of the "only-one-per-NSDocument" and getting a second instance.
I will have a look at the Collections Programming Guide.

I think it would be as simple as this:

Code:
// in the implementation for your custom singleton class

- (id)init {
     [COLOR="Blue"]MyDocument[/COLOR]   *thisDocument = [[NSDocumentController sharedDocumentController] currentDocument];
     if ( ![thisDocument isKindOfClass:[COLOR="blue"]MyDocument[/COLOR]] ) {
          // safety check, just in case another kind of document might exist within your application
          // probably not needed
          [self release];
          self = nil;
     } else {
          if ( [thisDocument [COLOR="blue"]mySingletonClass[/COLOR]] != nil ) {
               // the object already exists, return the existing one
               [self release];
               self = [thisDocument [COLOR="blue"]mySingletonClass[/COLOR]];
          } else {
               // initialize the new instance
               self = [super init];

                /* the init code for you class goes here */

          }
     }
     return self;
}

(substituting your class names, of course)

Alternately (perhaps more effectively) you could write a class method that uses a similar technique, but creates and inits the singleton if it does not yet exist. In that case, the method should include an (id)sender parameter: if the sender is a view type object, the class method would use [[[sender window] windowController] document] instead of currentDocument to handle the possibility that the currentDocument is not what you want (e.g., a drag dropped on a window that is not the top one).
 
Last edited:
I think it would be as simple as this:

Code:
// in the implementation for your custom singleton class

- (id)init {
     [COLOR="Blue"]MyDocument[/COLOR]   *thisDocument = [[NSDocumentController sharedDocumentController] currentDocument];
     if ( ![thisDocument isKindOfClass:[COLOR="blue"]MyDocument[/COLOR]] ) {
          // safety check, just in case another kind of document might exist within your application
          // probably not needed
          [self release];
          self = nil;
     } else {
          if ( [thisDocument [COLOR="blue"]mySingletonClass[/COLOR]] != nil ) {
               // the object already exists, return the existing one
               [self release];
               self = [thisDocument [COLOR="blue"]mySingletonClass[/COLOR]];
          } else {
               // initialize the new instance
               self = [super init];

                /* the init code for you class goes here */

          }
     }
     return self;
}

(substituting your class names, of course)

Alternately (perhaps more effectively) you could write a class method that uses a similar technique, but creates and inits the singleton if it does not yet exist. In that case, the method should include an (id)sender parameter: if the sender is a view type object, the class method would use [[[sender window] windowController] document] instead of currentDocument to handle the possibility that the currentDocument is not what you want (e.g., a drag dropped on a window that is not the top one).

Brilliant! I will play around with these suggestions and see what fits best.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.