问题
I'm using a singleton called CSAppData
to store data for my iPhone app. I'm storing an object called CSInbox
in the singleton. When I logout of my app, I want to clear the data for that object.
Here is my singleton code, including the method for clearing the data:
- (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];
}
However, in one of my view controllers, in the initWithCoder
method, I'm storing the inbox variable:
-(id) initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if(self) {
self.inbox = [[CSAppData appData] inbox];
}
return self;
}
So, when the app logs out and the clearData
method is called, the view controller is still pointing to the old CSInbox
object. And even though I am initializing a new view controller and setting it to the root view controller (in the AppDelegate), like this:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
MainTabControllerViewController *viewController = (MainTabControllerViewController *)[storyboard instantiateViewControllerWithIdentifier:@"mainView"];
[self.window setRootViewController:viewController];
The one child view controller that has the CSInbox
is never reinitialized, and is still pointing to that old CSInbox object. (I'm not sure why this is happening.)
So, what is the best way to solve this?
- Change the
clearData
method in the singleton to just reset the properties of theCSInbox
object, rather than alloc and init and new one? - Move the
self.inbox = [[CSAppData alloc] init];
to theviewDidLoad
in the view controller class so it gets set properly upon the second login? - Change the logout function in the
AppDelegate
so that the root view controller and all other view controllers are released, so they will reinitialize upon the second login?
I'm leaning toward #1 or #3...
As requested, here is 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
And here is CSInboxViewController.h:
@interface CSInboxViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate, CSThreadViewControllerDelegate>
@property (strong, nonatomic) IBOutlet UITableView *inboxTableView;
@property (strong,nonatomic) CSInbox *inbox;
@end
And CSAppData.h:
@interface CSAppData : NSObject {
CSInbox *inbox;
}
@property(nonatomic,strong) CSInbox *inbox;
+ (CSAppData *)appData;
+ (void)clearData;
@end
回答1:
I think the answer lies not in destroying the singleton object and recreating it, but to actually clear the instance variables within that singleton object.
You don't show the declaration of [CSAppData inbox]
, but if it's an NSMutableArray
, for example, then you can clear that, and any existing references to the singleton object can remain:
+(void) clearData {
CSAppData *appData = [CSAppData appData];
[appData.inbox removeAllObjects];
}
回答2:
One way to handle this, complying with the spirit of using a singleton, is having your view controllers access directly your singleton inbox
, i.e.: [CSAppData appData].inbox
instead of self.inbox
. This is a bit wordier, but it would "magically" fix your issue.
If that is not acceptable to you, I would go with option #1 of those you list. Even better, I would make the inbox
in the singleton a singleton itself, or make sure it is never replaced by another instance.
EDIT:
Another approach you have, is using KVO in your controller so that it gets notified when the inbox
object has changed. Don't know if it is quite worth it, but could be used.
来源:https://stackoverflow.com/questions/20150372/best-way-to-safely-clear-data-in-a-singleton