4

この投稿が長くなって申し訳ありません。この問題で私の旅を文書化することを意図しています。

時々変更する必要がある 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 を自由に切り替えることができます。

「スイッチ」が発生するとどうなるか

ユーザーが から に切り替えると、次の 2 つのことDocumentADocumentB必要になります。

  1. 私のプライマリNSViewController( MainViewController) は、新しいオブジェクトを使用できる必要があります。
  2. メイン ウィンドウのコンテンツ ボーダーにあるAppDelegateを更新する必要があります。NSTextField(FWIW、私はのコンセントを割り当てることしかできないようNSTextFieldですAppDelegate

質問)

私は、シングルトンが散らかることなくグローバル参照を持つ方法としてかなり言及されているのを見てきましたAppDelegate(主にherehere )。そうは言っても、そのようなシングルトンの上書きに関する情報はあまり見たことがありません (私たちの場合、ユーザーが から [またはその逆] に切り替えるとDocumentADocumentBこのグローバル参照は新しいオブジェクトを保持する必要があります)。私はデザインパターンの専門家ではありませんが、シングルトンは破棄して再作成することを意図していないと聞いたことを覚えています...

したがって、これらすべてを考慮して、ここに私の質問があります:

  1. クラス クラスタをどのように保存しますか (適切にアクセスできるようMainViewControllerAppDelegate)?
  2. (頻繁MainViewControllerに使用する人)と(プライマリウィンドウを管理する人[したがって、私の])の両方に知識を持たせることで、懸念を混合していますか?DocumentAppDelegateNSTextFieldDocument

この問題について間違って考えている場合は、遠慮なくお知らせください。この実装は、できるだけ直交的で正しいものにしたいと考えています。

ありがとう!


ステータスアップデート #1

@JackyBoy からのアドバイスのおかげで、私がたどったルートは次のとおりです。

  • Document「切り替え」時に「通知」AppDelegateMainViewController、それらに新しく作成されたインスタンスを渡すものです。
  • AppDelegateとの両方が、必要に応じて Singleton インスタンスを介してオブジェクトをMainViewController更新できます。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の存在を知っているという事実に悩まされるべきですか? さらに、オブジェクトが更新されると、両方に再通知されるという事実に悩まされる必要がありますか?AppDelegateMainViewControllerDocument AppDelegateMainViewController

いつものように、理想的な実装への探求が続く中、これに関する皆さんの注目に感謝しています。:)


ステータスアップデート #2

@Caleb からのコメントはNSNotification、この特定の問題に対して、ベースのセットアップの方がはるかに扱いにくいことを理解するのに役立ちました。

皆さんありがとう!

4

2 に答える 2

1

彼がここで共有オブジェクトを必要としているとは思えません。シングルトンはなおさらです。多くの異なるオブジェクトから任意の時点で現在のドキュメントを見つける必要がありますか? どちらも現在のドキュメントについて知る必要がある 2 つのオブジェクト (アプリ デリゲートとビュー コントローラー) しかないようです。通知はそれを管理する簡単な方法を提供します。切り替えが発生するたびに、新しいドキュメントを含む NSNotification を投稿できます。現在のドキュメントについて知る必要があるすべてのオブジェクトは、「ドキュメント スイッチ」通知用に登録されており、通知が到着すると、インスタンス変数またはプロパティにドキュメントへのポインターを格納できます。

于 2013-04-21T07:40:29.413 に答える