tags:

views:

501

answers:

2

Well, I'm trying to decide if the way I chose to persist web-based data is the right way in my iPhone app.

I haven't yet dove into the intricacies of Core Data, so am still using Sqlite with the FMDB wrapper.

Here is how I'm doing it now:

I have a class that uses a singleton similar to theElements sample. A static shared instance is created, and is shared among two or more views. The data is downloaded and loaded into an array in this class. I store the downloads in Sqlite. I load the Sqlite stored data on initialization, and get any updates from the web per a timestamp.

Am I doing this the "correct" way? Does this look proper?

Here is some pseudocode heavily cut for brevity.

@implementation theClass
static theClass *sharedInstance = nil;
...
- (void)requestDone:(Request *)request
{
    NSDictionary *results=[[request responseString] JSONValue];
    [self._array removeAllObjects];
    [self._array addObjectsFromArray:results];
    [self updateDatabase]; //stores any new results
    [[NSUserDefaults standardUserDefaults] setObject:self.lastUpdated forKey:@"LastAccessed"];
    [[NSUserDefaults standardUserDefaults] synchronize];
    [self didFinish];
}
-(void)setupArray {
    self._array=[NSMutableArray array];
    ...
}
...
-(void)getUpdates {
    NSURL *jsonURL = [NSURL URLWithString:@"URL TO THE WEBDATA"];
    request = NSURLRequst....
}
- init {
    if (self = [super init]) {
     [self setupArray];
    }
    return self;
}

+ (theClass *)shared {
    @synchronized(self) {
        if (sharedInstance == nil) {
      [[self alloc] init]; // assignment not done here
        }
    }
    return sharedInstance;
}

+ (id)allocWithZone:(NSZone *)zone {
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [super allocWithZone:zone];
            return sharedInstance;  // assignment and return on first allocation
        }
    }
    return nil; //on subsequent allocation attempts return nil
}

- (id)copyWithZone:(NSZone *)zone {
    return self;
}

- (id)retain {
    return self;
}

- (unsigned)retainCount {
    return UINT_MAX;}

- (void)release {
    //do nothing
}

- (id)autorelease {
    return self;
}
A: 

I am looking at the same problem and I concluded that NSUserDefaults is for small data sets, i.e., like settings and possibly state, but not state data. The large data values or data I am looking at saving in a file with [NSArray writeToFile] and read-back with [NSArray initFromFile].

You have to query the path assigned to your application and append your filename. What I have not yet learned is how to check for the file existence, how to delete (or some other means of clear/reset).

I will be experimenting tonight. The other thing I want to do is persist an XML file, but I think all I can hope for is an XML string in a file. That way, I can share the same logic for retrieving data on the network and loading local copy of similar data.

BTW - what is the purpose of the singleton? You already own all the threads and no other process (application) can access your sandbox, so you should be able to use semaphores (mutex). My question isn't a challenge, it is to help me understand what patterns are useful in the iPhone.

mobibob
A: 

I actually just use the NSUserDefaults plist for snapping the last updated time only (in case I need it). I store everything in a sqlite DB ([self updateDatabase]).

To check for file existence:

NSString *fullPath = [[[NSBundle mainBundle]bundlePath] stringByAppendingPathComponent:@"filenamehere"];
//--or--
NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:filenamehere];

if ([[NSFileManager defaultManager] fileExistsAtPath:fullPath]) ...

To delete:

[fileManager removeItemAtPath:pathtofile error:NULL];

I guess your question is the one I had (somewhat). I was wondering if the singleton class should handle access to persistent data storage when the data is accessed across multiple viewcontrollers in the app. I just stuck with the design, since it works well for my app (although in very large apps I could see memory issues I guess). So I suppose I have answered my own question.