对不起这篇文章的长度;这是为了记录我遇到这个问题的旅程。
我有一个关于 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
,我需要发生两件事:
- 我的主要
NSViewController
(MainViewController
) 需要能够使用新对象。 - 我
AppDelegate
需要更新一个NSTextField
恰好位于主窗口内容边框中的内容。(FWIW,我似乎只能为NSTextField
in分配一个出口AppDelegate
)
问题
我已经看到很多提到单例作为一种获得全局参考的方法,而不会弄乱一个AppDelegate
(主要是这里和这里)。也就是说,我没有看到太多关于覆盖这样一个单例的信息(在我们的例子中,当用户切换DocumentA
到DocumentB
[或反之亦然] 时,这个全局引用将需要保存新对象)。我不是设计模式方面的专家,但我确实记得听说过单例并不意味着被销毁和重新创建......
所以,鉴于这一切,这是我的问题:
- 你将如何存储我的类集群(这样
MainViewController
并且AppDelegate
可以适当地访问它)? - 我是否通过让
MainViewController
(谁Document
大量使用)和AppDelegate
(谁管理主窗口[因此,我的NSTextField
])都知道Document
?
如果我对这个问题的思考有误,请随时告诉我;我希望这个实现尽可能正交和正确。
谢谢!
状态更新 #1
感谢@JackyBoy 的建议,这是我采取的路线:
Document
是在“切换”时“通知”AppDelegate
并MainViewController
通过将新创建的实例传递给它们的那个。- 两者都
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
知道 and 的存在而AppDelegate
烦恼MainViewController
吗?Document
此外,当对象更新时,它会重新通知和 (即使其中一个启动了更新)AppDelegate
,我是否应该对此感到困扰?MainViewController
与往常一样,我感谢大家对此的关注,因为我对理想实施的追求仍在继续。:)
状态更新 #2
@Caleb 的评论帮助我理解,NSNotification
对于这个特定问题,基于 - 的设置将不那么笨拙。
谢谢大家!