2

In my app I have Singleton object, which should save its state through app launches. So I need to save it somehow.

I see only two options: 1) save it on app termination (plus, maybe, going background); 2) save it each time any property changed.

First option looks bad, because app can be killed, for example, because of some bug, memory limits or device power-off (low battery). So I expect state won't be saved.

Second option needs either manual notifications about each change, or KVO + observing of each property.

Seems that I do something wrong here. Maybe, you can give me some advice or there is some well-known pattern (I've tried to google, but found nothing particular).

UPDATE:

Yes, there is NSUserDefaults, but to improve its usability (smth. more than just key-values) I would write wrapper-methords, so I will end with the same problem (lines of manual coding).

UPDATE2:

CoreData is also bad choice for me: just one object to store + inserting there also needs some more lines of code.

UPDATE3:

It's not a question about "how to save". It's about "how to call this saving automatically (or with less of coding)". So in NSUserDefault way we need to manually implement each property as wrapper. In NSCoding - call save or post notification (to catch & save from one place) from each property also.

kpower
  • 3,871
  • 4
  • 42
  • 62
  • You can use [NSUserDefaults](http://www.icodeblog.com/2008/10/03/iphone-programming-tutorial-savingretrieving-data-using-nsuserdefaults/), it synchronizes automatically (or manually if you prefer) – Daniel Aug 13 '13 at 11:39
  • You can also implement the NSCoding protocol to save the whole class: see [this question](http://stackoverflow.com/questions/3000220/best-way-to-save-to-nsuserdefaults-for-custom-class) – Daniel Aug 13 '13 at 11:42
  • simpleBob, question is not how to save, but how to make those changes enough frequent (ideally - automatic) to store object up-to-date. – kpower Aug 13 '13 at 11:48
  • That's exactly what NSUserDefaults does, see my answer below – Daniel Aug 13 '13 at 11:55
  • Actually, you SHOULD NOT use synchronize. From Apple:`Because this method is automatically invoked at periodic intervals, use this method only if you cannot wait for the automatic synchronization (for example, if your application is about to exit) or if you want to update the user defaults to what is on disk even though you have not made any changes.` – Daniel Aug 13 '13 at 12:07
  • Yes, my mistake... updated. – kpower Aug 13 '13 at 12:40

2 Answers2

1

I think the first option is the better way to do it. The OS always informs the app when it will be killed for example for memory warnings the didReceiveMemoryWarning method will be called where you can save the states to the singleton object. (Device power off is same as go to background so the applicationWillEnterForeground method will be called).

Istvan
  • 1,627
  • 1
  • 11
  • 17
  • 1
    "Even if you develop your app using iOS SDK 4 and later, you must still be prepared for your app to be killed without any notification." (`App Termination` here: http://developer.apple.com/library/ios/DOCUMENTATION/iPhone/Conceptual/iPhoneOSProgrammingGuide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html#//apple_ref/doc/uid/TP40007072-CH4-SW49) – kpower Aug 13 '13 at 11:53
1

The simplest way to save user states in iOS is through NSUserDefaults.

Here is an example which keeps track of all changed made to your singleton:

@interface MySingleton : NSObject
{
}

+ (MySingleton *)sharedSingleton;

@property (copy) NSString *userName;//the variable to track
@end

@implementation MySingleton
@synthesize userName;
+ (MySingleton *)sharedSingleton
{
  static MySingleton *sharedSingleton;

  @synchronized(self)
  {
    if (!sharedSingleton)
      sharedSingleton = [[MySingleton alloc] init];

    return sharedSingleton;
  }     
}

- (void)setUserName:(NSString*)userName
{
   //update the variable
   self.userName = userName;
   //saves the new value to NSUserDefaults
   [[NSUserDefaults standardUserDefaults] setObject:userName forKey:@"userName"]; 
   //forces instantaneous synchronization, not needed, would be updated after a periodic interval anyways
   [[NSUserDefaults standardUserDefaults] synchronize];
}
@end

Optionally you can implement the NSCoding protocol and save the whole class to NSUserDefaults, take a look at this question.

Community
  • 1
  • 1
Daniel
  • 20,420
  • 10
  • 92
  • 149
  • Thanks, but here you still implement all properties manually - hope for a better solution :) – kpower Aug 13 '13 at 11:57
  • @kpower you also can save everything in one go if you implement NSCoding first – Daniel Aug 13 '13 at 12:01
  • I know! I want this `save` to be called somehow automatically! – kpower Aug 13 '13 at 12:42
  • 1
    I think you only have 3 options, where only the 1st one is a good idea: (1) You somehow keep track of when a variable has changed f.e. through properties. (2) You implement a periodic saving f.e. with NSTimer. (3) You try save the data before it closes. – Daniel Aug 13 '13 at 13:09
  • (3) should rather be complementary to (1) or (2) – Daniel Aug 13 '13 at 13:09