类群作为单身人士?

时间:2013-04-20 07:05:29

标签: objective-c cocoa singleton

对这篇文章的长度感到抱歉;用这个问题记录我的旅程是有意义的。

我对Cocoa应用程序中的共享对象有一个问题,需要不时更改以及如何最好地存储它以便可以从几个不同的地方访问它。忍受我。

班级实施

共享对象实现为类集群(即https://stackoverflow.com/a/2459385/327179),如下所示(注意Document只是一个类名;它不一定表示我的实际类是什么一样):

Document.h

typedef enum {
    DocumentTypeA,
    DocumentTypeB
} DocumentType;

@interface Document : NSObject {}
- (Document *) initWithDocumentType:(NSUInteger)documentType;
- (void) methodA;
- (void) methodB;
@end

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

用户如何与Document

进行互动

通过菜单项,用户可以随意在DocumentA和DocumentB之间切换。

发生“切换”时会发生什么

当用户从DocumentA切换到DocumentB时,我需要做两件事:

  1. 我的主要NSViewControllerMainViewController)需要能够使用新对象。
  2. 我的AppDelegate需要更新恰好位于主窗口内容边框中的NSTextField。 (FWIW,我似乎只能为NSTextField中的AppDelegate分配一个插座
  3. 问题

    我看到单身人士提到了相当多的一种方式来获得全局参考,而不会使一个AppDelegate(主要是herehere)混乱。也就是说,我没有看到很多关于覆盖这样一个单例的信息(在我们的例子中,当用户从DocumentA切换到DocumentB [反之亦然]时,这个全局引用需要保持新对象)。我不是设计模式方面的专家,但我确实记得听说单身人士不应该被摧毁和重建......

    所以,鉴于这一切,这是我的问题:

    1. 您如何存储我的类群(MainViewControllerAppDelegate可以正确访问它?)
    2. 我是否通过让MainViewController(谁大量使用Document)和AppDelegate(谁管理主窗口[因此,我的NSTextField])混合了我的问题了解Document
    3. 如果我错误地考虑这个问题,请随时告诉我。我希望这个实现尽可能正交和正确。

      谢谢!


      状态更新#1

      感谢@JackyBoy的建议,这是我采取的路线:

      • Document是指在“切换”后,通过传递新创建的实例来“通知”AppDelegateMainViewController
      • AppDelegateMainViewController都可以根据需要通过Singleton实例更新Document对象。

      以下是我的新文件(愚蠢到所以你们都可以看到问题的关键):

      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
      

      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
      

      Document是否知道AppDelegateMainViewController的存在这一事实是否应该让我感到困扰?此外,当Document对象更新时,它会重新通知 AppDelegateMainViewController(即使其中一个已启动),我也会感到困扰更新)?

      与往常一样,我欣赏每个人的眼球,因为我对理想实施的追求仍在继续。 :)


      状态更新#2

      来自@Caleb的评论帮助我理解基于NSNotification的设置对于这个特定问题来说不会那么笨重。

      谢谢,全部!

2 个答案:

答案 0 :(得分:1)

  

我确实记得听说单身人士不应该被摧毁   并重新创造......

嗯,你可以在里面有引用,所以你实际上并没有“摧毁”单身人士,而是他指向的对象。我倾向于在没有应用程序逻辑的情况下离开App Delegate,因此我通常把它放在其他地方。在你的情况下,因为你需要访问来自不同地方的东西,所以有一个是有意义的。关于集群,您仍然可以拥有它,您只需要让单例访问它并返回相应的对象,如下所示:

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

你从中获得了一些东西:

  1. 您可以从应用中的任何位置访问群集

  2. 你解耦了东西,只有一个实体知道你的群集。

  3. 在Singleton中你可以引用AppDelegate并与之交互。

  4. 在Singleton中你可以引用正在使用的对象(文档A,文档B)

  5. 还有一件事,我建议将集群访问方法作为类方法(而不是实例1)。

答案 1 :(得分:1)

我不认为他需要一个共享对象,更不用说单身人士了。您是否真的需要在许多不同对象的任意时间找到当前文档?看起来更像是你只需要了解当前Document的两个对象(app delegate和view controller)。 通知提供了一种简单的方法来管理:每当切换发生时,您都可以发布包含新文档的NSNotification。任何需要了解当前文档的对象都将注册&#34;文档开关&#34;通知,当通知到达时,他们可以在实例变量或属性中存储指向Document的指针。