在单例中安全清除数据的最佳方法?

时间:2013-11-22 17:00:00

标签: ios objective-c singleton

我正在使用一个名为CSAppData的单例来存储我的iPhone应用程序的数据。我在单例中存储了一个名为CSInbox的对象。当我退出我的应用程序时,我想清除该对象的数据。

这是我的单例代码,包括清除数据的方法:

- (id)init {
    self = [super init];
    if (self)
    {
        self.inbox = [[CSInbox alloc] init];
    }
    return self;
}

+ (CSAppData *)appData {
    static CSAppData * appDataInstance;
    @synchronized(self) {
        if(!appDataInstance) {
            appDataInstance = [[CSAppData alloc] init];
        }
    }
    return appDataInstance;
}

+(void) clearData {
    CSAppData *appData = [CSAppData appData];
    appData.inbox = [[CSInbox alloc] init];
}

但是,在我的一个视图控制器中,在initWithCoder方法中,我存储了收件箱变量:

-(id) initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if(self) {
        self.inbox = [[CSAppData appData] inbox];
    }
    return self;
}

因此,当应用程序注销并调用clearData方法时,视图控制器仍指向旧的CSInbox对象。即使我正在初始化一个新的视图控制器并将其设置为根视图控制器(在AppDelegate中),如下所示:

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
MainTabControllerViewController *viewController = (MainTabControllerViewController *)[storyboard instantiateViewControllerWithIdentifier:@"mainView"];
[self.window setRootViewController:viewController];

具有CSInbox的一个子视图控制器永远不会重新初始化,并且仍然指向旧的CSInbox对象。 (我不确定为什么会这样。)

那么,解决这个问题的最佳方法是什么?

  1. 更改单例中的clearData方法,只重置CSInbox对象的属性,而不是alloc和init以及新对象?
  2. self.inbox = [[CSAppData alloc] init];移动到视图控制器类中的viewDidLoad,以便在第二次登录时正确设置?
  3. 更改AppDelegate中的注销功能,以便释放根视图控制器和所有其他视图控制器,以便在第二次登录时重新初始化?
  4. 我倾向于#1或#3 ...

    根据要求,这是 CSInbox.h:

    @interface CSInbox : NSObject
    
    @property (nonatomic,strong) NSMutableArray *threads;
    @property (nonatomic, assign) NSInteger newCount;
    @property (nonatomic,strong) NSDate *lastUpdate;
    
    -(void) setThreadsFromJSON:(NSDictionary *)json;
    
    @end
    

    这是 CSInboxViewController.h

    @interface CSInboxViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate, CSThreadViewControllerDelegate>
    
    @property (strong, nonatomic) IBOutlet UITableView *inboxTableView;
    @property (strong,nonatomic) CSInbox *inbox;
    
    @end
    

    CSAppData.h

    @interface CSAppData : NSObject {
        CSInbox *inbox;
    }
    
    @property(nonatomic,strong) CSInbox *inbox;
    
    + (CSAppData *)appData;
    + (void)clearData;
    
    @end
    

2 个答案:

答案 0 :(得分:5)

我认为答案不在于破坏单例对象并重新创建它,而是实际清除该单例对象中的实例变量。

您没有显示[CSAppData inbox]的声明,但是如果它是NSMutableArray,那么您可以清除它,并且可以保留对单例对象的任何现有引用:

+(void) clearData {
    CSAppData *appData = [CSAppData appData];
    [appData.inbox removeAllObjects];
}

答案 1 :(得分:1)

处理此问题的一种方法是遵守使用单身人士的精神,让您的视图控制器直接访问您的单身inbox,即:[CSAppData appData].inbox而不是self.inbox。这有点啰嗦,但它会“神奇地”修复你的问题。

如果您不接受,我会选择您列出的选项#1。更好的是,我会将单例中的inbox变为单身,或者确保它永远不会被另一个实例替换。

编辑:

您拥有的另一种方法是在控制器中使用KVO,以便在inbox对象发生更改时收到通知。不知道它是否值得,但可以使用。