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