Objective-C中的单例共享数据源

3

大家好 - 我正在编写一个相当简单的iPhone应用程序。 数据来自于一个plist文件(基本上是NSDictionary),我试图将其加载到一个单例类中,并在我的各种视图控制器之间使用它来访问数据。

这是我的单例实现(严重模仿此线程):

@implementation SearchData

@synthesize searchDict;
@synthesize searchArray;

- (id)init {
    if (self = [super init]) {
        NSString *path = [[NSBundle mainBundle] bundlePath];
        NSString *finalPath = [path stringByAppendingPathComponent:@"searches.plist"];
        searchDict = [NSDictionary dictionaryWithContentsOfFile:finalPath];
        searchArray = [searchDict allKeys];
    }

    return self;
}

- (void)dealloc {
    [searchDict release];
    [searchArray release];
    [super dealloc];
}

static SearchData *sharedSingleton = NULL;

+ (SearchData *)sharedSearchData {
    @synchronized(self) {
        if (sharedSingleton == NULL)
            sharedSingleton = [[self alloc] init];
    }   
    return(sharedSingleton);
}

@end

因此,每当我尝试在我的应用程序其他地方(如TableView代理)访问searchDict或searchArray属性时,就会像这样:

[[[SearchData sharedSearchData] searchArray] objectAtIndex:indexPath.row]

我遇到了一个异常,异常信息是 *** -[NSCFSet objectAtIndex:]: unrecognized selector sent to instance 0x5551f0

我不确定为什么会向 NSCFSet 对象发送 objectAtIndex 消息,感觉我的单例模式实现可能有问题。我也尝试过像苹果在上述帖子中推荐的更复杂的单例模式实现,但是仍然遇到了同样的问题。感谢您提供的任何见解。

3个回答

11

在你的 -init 方法中,你直接访问了实例变量并没有对它们进行保留。它们会在应用程序的生命周期后期被其他对象删除并释放其内存。

要么保留你创建的对象,要么使用非便利方法来生成它们。

searchDict = [[NSDictionary alloc] initWithContentsOfFile:finalPath];
searchArray = [[searchDict allKeys] retain];

谢谢Ashley,保留变量解决了问题。作为后续 - 在我的@property声明中,(non-atomic, retain)的目的是什么?我认为retain意味着属性会自动被保留。 - Andy Bourassa
@property定义中的标签定义了访问器的工作方式。在非原子性、保留(retain)的情况下,它们不会在多个线程之间进行同步,并且会保留被赋值的对象(根据我的记忆,这本来就是原子性的)。然而,你直接绕过了这些变量,直接进行了赋值。 - Ashley Clark
关于为什么你不应该在-init和-dealloc方法中使用self.variable语法,可以看看我对其他答案的评论。简短回答:会产生意想不到的副作用。 - Ashley Clark

1

每当您分配合成变量时,请通过“self”进行,例如:

- (id)init {
  if (self = [super init]) {
      NSString *path = [[NSBundle mainBundle] bundlePath];
      NSString *finalPath = [path stringByAppendingPathComponent:@"searches.plist"];
      self.searchDict = [NSDictionary dictionaryWithContentsOfFile:finalPath];
      self.searchArray = [searchDict allKeys];
  }

  return self;

}

同时确保你已经在头文件中将这些变量设置为'retain'。


1
苹果公司特别建议在-init方法中不要这样做,因为您的setter可能会在对象初始化期间出现未满足条件的副作用。 - Ashley Clark
我还应该补充一点,他们在-dealloc中也出于同样的原因建议不要这样做。 - Ashley Clark

0
你好,你能告诉我通过“self”分配合成变量的优势是什么吗?谢谢Shiva。
这样设置值可以通过setter实现;它会释放先前的值并保留您分配的值。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接