我遇到单例模式的问题。
我已阅读以下有关单例类的教程,并创建了自己的类。 http://www.galloway.me.uk/utorials/singleton-classes/ http://www.johnwordsworth.com/2010/04/iphone-code-snippet-the-singleton-pattern/
我第一次建立&运行它应用的应用程序。没问题! 但是,当我重建应用程序时,单例类不再正常工作。第一个init就像应该的那样工作,但是当我点击按钮后再次调用它时会崩溃我的应用程序。
我的单身人士课程:
BPManager.h
@interface BPManager : NSObject {
NSString *dbPath;
}
@property (nonatomic, retain) NSString *dbPath;
+ (id)bpManager;
- (void)initDatabase:(NSString *)dbName;
- (int)getQuestions;
@end
BPManager.m
static BPManager *sharedMyManager = nil;
@implementation BPManager
@synthesize dbPath;
- (void)initDatabase:(NSString *)dbName
{
dbPath = dbName;
}
-(int)getQuestions
{
NSLog(@"getQuestions");
}
- (id)init {
if ((self = [super init])) {
}
return self;
}
+ (BPManager *) bpManager {
@synchronized(self) {
if(sharedMyManager != nil) return sharedMyManager;
static dispatch_once_t pred; // Lock
dispatch_once(&pred, ^{ // This code is called at most once per app
sharedMyManager = [[BPManager alloc] init];
});
}
return sharedMyManager;
}
- (void)dealloc {
[dbPath release];
[super dealloc];
}
当我在构建界面时调用以下代码时,应用程序会创建单例:
BPManager *manager = [BPManager bpManager];
[manager initDatabase:@"database.db"];
注意:此时我也可以从其他文件创建对该类的引用。但是,当我点击一个按钮时,似乎松开了他的参考。
但是当点击一个按钮时,会输出以下代码:
BPManager *manager = [BPManager bpManager];
int count = [manager getQuestions];
应用程序应该获取sharedInstance。这样做,只有参数(如dbPath)不可访问。那是为什么?
+ (BPManager *) bpManager {
@synchronized(self) {
if(sharedMyManager != nil) return sharedMyManager;
static dispatch_once_t pred; // Lock
dispatch_once(&pred, ^{ // This code is called at most once per app
sharedMyManager = [[BPManager alloc] init];
});
}
return sharedMyManager;
}
但问题没有解决
答案 0 :(得分:3)
怎么样
@interface BPManager : NSObject
@property (nonatomic, copy) NSString *dbName;
@property (nonatomic, assign) int questions;
-(id) initWithDBName:(NSString*) dbName {
@end
#import "BPManager.h"
@implementation BPManager
@synthesize dbName=_dbName, questions;
+(BPManager *)singleton {
static dispatch_once_t pred;
static BPManager *shared = nil;
dispatch_once(&pred, ^{
shared = [[BPManager alloc] initWithDBName:@"database.db"];
});
return shared;
}
-(id) initWithDBName:(NSString*) dbName {
self = [super init]
if (self) self.dbName = dbName;
return self;
}
-(void)dealloc {
[_dbName release];
[super dealloc];
}
@end
BPManager *manager = [BPManager singleton];
int count = [manager questions];
静态对于实现文件是私有的,但没有理由在单例方法之外甚至可以访问它。 init使用默认实现覆盖默认实现,因此它没用。在Objective-C中,您使用var name(count)命名getter,而不是getCount。初始化类两次会导致未定义的行为。当您已经使用dispatch_once时,无需同步或检查if == nil,请参阅Care and Feeding of Singletons。 NSString应始终使用copy而不是@property中保留。你不需要dealloc,因为这将在你的应用程序运行时永远保持活跃状态,但它就是你想要将这个类用作非单例的情况。你可能也很好,这个班级在你的代表中是一个ivar而不是单身,但你可以两种方式。
答案 1 :(得分:0)
我不确定它是否是(完整)答案,但一个主要缺陷是您在类方法{{1}中使用实例变量(self
,super
) };我真的很惊讶它让你编译它。将+(id)bpManager
更改为@synchronized(self)
,将@synchronized(sharedMyManager)
更改为[[super alloc...] init]
。写这篇文章只是让我意识到问题看起来像是在实例化为超类的对象上访问子类方法,但是应该在调度中被覆盖。你不应该真的只需要其中一个,为什么这样双启动? (当我们在那里时,这是一个内存泄漏 - 在[[BPManager alloc...] init]
中初始化,然后在封闭中被覆盖而不释放它。)
答案 2 :(得分:0)
Jano的解决方案必须运作良好。我也用这种方式创建单例对象。我没有任何问题。
对于你的代码,我认为如果你使用@synchronized(这不是必要的,因为Jano说你有dispatch_once_t),你不应该在@synchronized中调用return。
+ (BPManager *) bpManager {
@synchronized(self) {
if(sharedMyManager == nil) {
static dispatch_once_t pred; // Lock
dispatch_once(&pred, ^{ // This code is called at most once per app
sharedMyManager = [[BPManager alloc] init];
});
}
}
return sharedMyManager;
}