Class Cluster like Singleton?

CHANGE THE LENGTH OF THIS MAIL; THIS MEETS MY TRAVEL DOCUMENT WITH THIS PROBLEM.

I have a question about a generic object in a Cocoa application that needs to change from time to time and how best to store it so that it can be accessed from several different places. The bear is with me.

Class implementation

The generic object is implemented as a cluster of classes (i.e., https://stackoverflow.com/a/3/2127/ ), which looks like this (note that Document is just the name of the class; this does not necessarily indicate what my actual class):

In Document.h :

 typedef enum { DocumentTypeA, DocumentTypeB } DocumentType; @interface Document : NSObject {} - (Document *) initWithDocumentType:(NSUInteger)documentType; - (void) methodA; - (void) methodB; @end 

In Document.m :

 @interface DocumentA : Document - (void) methodA; - (void) methodB; @end @interface DocumentB : Document - (void) methodA; - (void) methodB; @end @implementation Document - (Document *)initWithDocumentType:(NSUInteger)documentType; { id instance = nil; switch (documentType) { case DocumentTypeA: instance = [[DocumentA alloc] init]; break; case DocumentTypeB: instance = [[DocumentB alloc] init]; break; default: break; } return instance; } - (void) methodA { return nil; } - (void) methodB { return nil; } @end @implementation DocumentA - (void) methodA { // ... } - (void) methodB { // ... } @end @implementation DocumentB - (void) methodA { // ... } - (void) methodB { // ... } @end 

How the user interacts with Document

Through the menu item, the user can switch between DocumentA and DocumentB as desired.

What happens when the “Switch” is encountered

When a user switches from, say, DocumentA to DocumentB , I need two things:

  • My main NSViewController ( MainViewController ) should be able to use the new object.
  • My AppDelegate needs to update NSTextField , which is located on the border of the contents of the main window. (FWIW, I can only imagine that for NSTextField for AppDelegate ) there is a way out2>)

Question (s)

I have seen that singletones are mentioned quite as a way to have a global link without cluttering up one AppDelegate (primarily here and here ). However, I did not see much information about rewriting such a singlet (in our case, when the user switches from DocumentA to DocumentB [or vice versa], this global link should contain a new object). I am not an expert on design patterns, but I remember that singletones are not designed to destroy and recreate ...

So, considering all this, here are my questions:

  • How would you store a class cluster (so that MainViewController and AppDelegate can access it accordingly)?
  • I am confusing problems, having both the MainViewController (which uses Document lot) and the AppDelegate (which controls the main window [and thus my NSTextField ]) has Document knowledge?

Feel free to let me know if I think about this issue incorrectly; I want this implementation to be as orthogonal and correct as possible.

Thanks!


Status Update # 1

Thanks to @JackyBoy's advice, here's the route I took:

  • Document is one that, after "switching", "notifies" the AppDelegate and MainViewController passing them a newly created instance.
  • Both AppDelegate and MainViewController can update the Document object with a Singleton instance if necessary.

Here are my new files (dumbfounded so you can see the gist):

In Document.h :

 #import <Foundation/Foundation.h> @class AppDelegate; @class MainViewController; typedef enum { DocumentTypeA, DocumentTypeB } DocumentType; @interface Document : NSObject @property (weak, nonatomic) MainViewController *mainViewControllerRef; @property (weak, nonatomic) AppDelegate *appDelegateRef; + (Document *)sharedInstance; - (id)initWithParser:(NSUInteger)parserType; @end 

In Document.m :

 #import "AppDelegate.h" #import "Document.h" #import "MainViewController.h" @interface DocumentA : Document // ... @end @interface DocumentB : Document // ... @end @implementation Document @synthesize appDelegateRef; @synthesize mainViewControllerRef; + (Document *)sharedInstance { static XParser *globalInstance; static dispatch_once_t predicate; dispatch_once(&predicate, ^{ // By default, I return a DocumentA object (for no particular reason). globalInstance = [[self alloc] initWithDocumentType:DocumentA]; }); return globalInstance; } - (id)initWithDocumentType:(NSUInteger)documentType { Document *instance = nil; switch (parserType) { case DocumentTypeA: instance = [[DocumentA alloc] init]; break; case DocumentTypeB: instance = [[DocumentB alloc] init]; break; default: break; } // QUESTION: Is this right? Do I have to store these references // every time a new document type is initialized? self.appDelegateRef = (AppDelegate *)[NSApp delegate]; self.mainViewControllerRef = self.appDelegateRef.mainViewController; [self.appDelegateRef parserSwitchedWithParser:instance]; [self.mainViewControllerRef parserSwitchedWithParser:instance]; return instance; } @end @implementation Xparser_NSXML // ... @end @implementation DocumentA // ... @end 

Should I be bothered by the fact that Document knows about the existence of AppDelegate and MainViewController ? Also, should I worry that when the Document object is updated, it re-notifies both the AppDelegate and MainViewController (even if one of them initiated the update)?

As always, I appreciate all the eyeballs on this, as my search for the perfect realization continues. :)


Update Status # 2

A comment from @Caleb helped me understand that an installation based on NSNotification would be much less cumbersome for this particular problem.

Thank you all!

+4
source share
2 answers

I do not see that it is needed for a common object here, and even more so for a single. Do you really need to find the current Document at any time from different objects? Most likely, you only have two objects (application delegate and view controller) that should know about the current document. Notifications provide an easy way to manage this: when a transition occurs, you can publish an NSNotification that includes a new document. Any objects that need to know about the current Document will be registered for the “document switch” notification, and when the notification arrives, they can overlay the Document with a variable or instance property.

+1
source

I remember that singletones should not be destroyed and recreated ...

Well, you may have links inside it, so you are not really “destroying” the singleton, but the objects that it points to. I tend to leave the application delegate without application logic, so I usually put it in another place. In your case, since you need to access something from different places, it makes sense to have it. As for the cluster, you can still get it, just ask the singleton to access it and return the corresponding object as follows:

 Document *myDocument = [[MySingleton defaultManager] createObjectWithType:aType]; 

You get some things from this:

  • You can access your cluster from anywhere in your application.

  • you separate things, only one object knows about your cluster.

  • Inside Singleton, you can have an AppDelegate link to you and interact with it.

  • Inside Singleton, you can have a link to the objects that are used (document A, document B)

One more thing, I would advise putting the cluster access method as a class method (instead of an instance).

+1
source

All Articles