Advertise Mobile SDKs Books Events Forum News Social Networking Support Us
Follow @iphonedevsdk on Twitter

Interface 2, Advanced iOS
Mockup & Code Gen
($9.99)

Make your own iPhone apps
and run them live!
(free)

Pic Frame Dynamo: Photo Editing
($0.99)

Abiliator
($1.99)

Want your application or service advertised on iPhone Dev SDK?

Go Back   iPhone Dev SDK Forum > iPhone SDK Development Forums > iPhone SDK Development

Reply
 
LinkBack Thread Tools Display Modes
Old 05-20-2010, 06:04 PM   #1 (permalink)
Registered Member
 
Join Date: Dec 2008
Posts: 13
ghoover is on a distinguished road
Default Sqlite file caching in iPhone 3.2

As of 3.2 it appears that sqlite files are being cached. I discovered that when replacing a sqlite database file and loading its contents, stale data is returned from the overwritten database file. The contents of the new file are correct (as verified by NSFileManager contentsAtPath and on relaunch the new file is loaded correctly. A workaround is to use a new unique name rather than overwriting the existing name, suggesting that the files are being cached by name. This behavior occurs in both the simulator and on iPad (I assume iPhone as well). This is a real headache. Anyone know how to disable this "feature"?
ghoover is offline   Reply With Quote
Old 05-20-2010, 09:40 PM   #2 (permalink)
Coder for Life
 
Karl Kraft's Avatar
 
Join Date: Sep 2008
Location: Austin, TX
Posts: 76
Karl Kraft is on a distinguished road
Send a message via AIM to Karl Kraft
Default

Quote:
Originally Posted by ghoover View Post
As of 3.2 it appears that sqlite files are being cached. I discovered that when replacing a sqlite database file and loading its contents, stale data is returned from the overwritten database file.
Do you have an actual reproducible test case? I use sqlite3 for my 3.2 app and I'm not seeing this result at all. I assume be "overwritten" you mean that you are completely destroying the db and rewriting it, such as downloading it from a remote server. Do you close and reopen the database as well? If not your handle to the database will still point to the old file, even if it does not appear to exist on disk anymore.


Quote:
Originally Posted by ghoover View Post
....occurs in both the simulator and on iPad (I assume iPhone as well).
There is no 3.2 for the iPhone.
Karl Kraft is offline   Reply With Quote
Old 05-21-2010, 10:53 AM   #3 (permalink)
Registered Member
 
Join Date: Dec 2008
Posts: 13
ghoover is on a distinguished road
Default

Yes, I am downloading from a remote server and passing the data in like this:

close ensures that all sqlite handles are closed - I have verified that new handles are being created after the data is saved. The interesting part is if you uncomment the line that creates a new unique path, it works fine. And the code has worked on all prior SDK versions.

Code:
- (void)replaceStoreWithData:(NSData *)data {
	[self close];
	

	NSFileManager *fileManager = [NSFileManager defaultManager];
	if ([fileManager fileExistsAtPath: path]) {
		NSError *error;
		if (![fileManager removeItemAtPath: path
									 error: &error])
			NSLog(@"Error removing database file: %@", [error localizedDescription]);
	}


	//	path = [path stringByAppendingFormat: @"%f", [[NSDate date] timeIntervalSince1970]]; 

	if (![fileManager createFileAtPath: path
							  contents: data
							attributes: nil])
		NSLog(@"Error creating database file with data (%i)", [data length]);
	
	
	[self openWithPath: [[path copy] autorelease]];
}
ghoover is offline   Reply With Quote
Old 12-23-2010, 12:08 PM   #4 (permalink)
Registered Member
 
Join Date: Dec 2010
Posts: 1
icozip is on a distinguished road
Default Same problems here

Did you come up with a solution? I'm having the exact same problems.
icozip is offline   Reply With Quote
Old 12-23-2010, 08:16 PM   #5 (permalink)
Registered Member
 
Join Date: Dec 2008
Posts: 13
ghoover is on a distinguished road
Default

I ended up getting creative with file naming -- I append the date to the filename. You can then normalize on exit (or launch) (or just track the new name you're using, which is what I do).
ghoover is offline   Reply With Quote
Old 03-06-2011, 04:18 AM   #6 (permalink)
Registered Member
 
Join Date: Apr 2010
Location: Vegas
Posts: 11
SevenOTwo is on a distinguished road
Default Can You elaborate on your specific solution?

I have been having this exact problem, can you post the code that you are using to get past this problem? Also, you mention appending time and date to the SQLite file as it is uploaded, how would you go about that? And then how would you go about removing it when the file is downloaded again??

Any assistance would be greatly appreciated, I have been looking everywhere for the past 2 weeks for this solution.

Thank!!

SevenOTwo
SevenOTwo is offline   Reply With Quote
Old 03-06-2011, 01:06 PM   #7 (permalink)
Registered Member
 
Join Date: Dec 2008
Posts: 13
ghoover is on a distinguished road
Default

Just append the date to the path. You can determine how fine a resolution you need to avoid conflicts (ie. day/hour/minute/second) and then format the date accordingly. This is the code I use (Formatters is a class I use for formatting numbers and dates - you can use NSDateFormatter).

Code:
NSString *newDB = [NSString stringWithFormat: @"Data_Sync-%@.sqlite", [Formatters stringFromDate: [NSDate now]
																									  withFormat: DATEFORMAT_DB_TMP]];
Stripping the date portion is easy, just look for the '-' character between the name and file suffix.
ghoover is offline   Reply With Quote
Old 03-06-2011, 05:12 PM   #8 (permalink)
Registered Member
 
Join Date: Apr 2010
Location: Vegas
Posts: 11
SevenOTwo is on a distinguished road
Default Another Question..

Looking at your original code above, I am assuming that 'path' is actually the variable that holds the default location to the applicationDocumentDirectory, is this correct?

Basically what I am trying to accomplish is;

I have two IBAction's, one is upload and the other is download.

By looking at the code above, it doesn't seem comLete, no defaultDocDirectory/tempDirectory, and how are you accessing the actual .sqlite file? Sorry if this all seams a bit noob, but i am to some degree and I really need to figure this out. Would it be easier if I posted both IBActions here? I am sure many others have the same questions.

Thanks Again!!

SevenOTwo
SevenOTwo is offline   Reply With Quote
Old 03-06-2011, 06:08 PM   #9 (permalink)
Registered Member
 
Join Date: Apr 2010
Location: Vegas
Posts: 11
SevenOTwo is on a distinguished road
Default My IBAction Code... :8)

Code:
/****************************
* @Interface File (.h)                *
****************************/
@Interface

	UIBarButtonItem *link;
	UIBarButtonItem *download;
	UIBarButtonItem *upload;
	    
	UITextField *textField;
	
	DBRestClient *restClient;

	NSString *defaultDocumentDirectory;
	NSString *writableDocumentDirectory;
	NSString *documentsDirectory;
	NSString *documentsHomeDirectory;
	NSString *tempFolder;
	NSString *permFolder;
	
	NSArray *documentPaths;

}

@property (nonatomic, retain) IBOutlet UIBarButtonItem *link;
@property (nonatomic, retain) IBOutlet UIBarButtonItem *download;
@property (nonatomic, retain) IBOutlet UIBarButtonItem *upload;

@property (nonatomic, retain) IBOutlet UITextField *textField;

@property (nonatomic, retain) NSString *defaultDocumentDirectory;
@property (nonatomic, retain) NSString *writableDocumentDirectory;
@property (nonatomic, retain) NSString *documentsDirectory;
@property (nonatomic, retain) NSString *documentsHomeDirectory;
@property (nonatomic, retain) NSString *tempFolder;
@property (nonatomic, retain) NSString *permFolder;

@property (nonatomic, retain) NSArray *documentPaths;

- (NSString *)applicationDocumentsDirectory;

-(IBAction) link;
-(IBAction) download;
-(IBAction) upload;

@end

/****************************
* @implementation File (.m)      *
****************************/

@synthesize defaultDocumentDirectory;
@synthesize writableDocumentDirectory;
@synthesize documentsDirectory;
@synthesize documentPaths;
@synthesize documentsHomeDirectory;
@synthesize tempFolder; 
@synthesize permFolder;

NSString *uploadFolder = @"/Backup Folder [DB Backup][Do Not Delete]";



NSString = *dbFileName = @"yourDBFileName.sqlite";

	/////////////////////////////////////////////////////////
	//							          //							
	// UPLOAD:                                                  //						
	//                                                               //							
	////////////////////////////////////////////////////////

-(IBAction) upload {
	
        [self.restClient uploadFile:dbFileName toPath:uploadFolder fromPath:[[self applicationDocumentsDirectory] stringByAppendingPathComponent:dbFileName]];
	
	UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Notice" message:@"Database has Uploaded" delegate:self cancelButtonTitle:@"OK"
otherButtonTitles: nil];	
	
	[alert show];
	[alert autorelease];

        textField.text = @"Database is being uploaded...";
    
}

	/********************************************************
	* CATCH THE DOWNLOAD ERROR IF ONE EXISTS:                       *
	********************************************************/

- (void) restClient:(DBRestClient*)client uploadFileFailedWithError:(NSError*)error {
    
	textField.text = [error localizedDescription];    
}


	//////////////////////////////////////////////////////////////////
	//									     //							
	// DOWNLOAD:                 					     //						
	//									     //							
	//////////////////////////////////////////////////////////////////

-(IBAction) download {
	
	/*************************************************
	* DEFINE FILEMANAGER:                                             *
        *************************************************/
	
	NSFileManager *fileManager = [NSFileManager defaultManager];
	
	NSError *error;

	documentPaths = NSSearchPathForDirectoriesInDomains     (NSDocumentDirectory, NSUserDomainMask, YES);
	
	documentsDirectory = [documentPaths objectAtIndex:0];
	
	writableDocumentDirectory = [documentsDirectory stringByAppendingPathComponent:dbFileName];
		
	defaultDocumentDirectory = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:dbFileName];
	
	[fileManager copyItemAtPath:defaultDocumentDirectory toPath:writableDocumentDirectory error:&error];
	
	documentsHomeDirectory = NSHomeDirectory();
	
	tempFolder = [documentsHomeDirectory stringByAppendingString:[NSString stringWithFormat:@"/%@", dbFileName]];
	
	permFolder = [documentsDirectory stringByAppendingString:[NSString stringWithFormat:@"/%@", dbFileName]];
	
	[self.restClient loadFile:[NSString stringWithFormat: @"%@/%@", uploadFolder, dbFileName]

	intoPath:writableDocumentDirectory];	 
	 
	// intoPath:[[self applicationDocumentsDirectory] stringByAppendingPathComponent:dbFileName]];

	

	/*************************************************
        ** GET ALL FILES IN DIRECTORY:                                  *
        *************************************************/

	// [fileManager copyItemAtPath:tempFolder toPath:permFolder error:NULL];
	
	/************************************************
        ** SEND A MESSAGE TO THE WINDOW:                       *
        ************************************************/
	
	UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Notice" message:@"Database File has Downloaded" delegate:self cancelButtonTitle:@"OK?" otherButtonTitles: nil];

	[alert show];
	[alert release];
	
}

	/*************************************************
        * CATCH THE DOWNLOAD ERROR IF ONE EXISTS:            *
	*************************************************/

- (void) restClient:(DBRestClient*)client loadFileFailedWithError:(NSError*)error {
    
	textField.text = [error localizedDescription];

}

Last edited by SevenOTwo; 03-06-2011 at 06:11 PM.
SevenOTwo is offline   Reply With Quote
Old 03-06-2011, 07:07 PM   #10 (permalink)
Registered Member
 
Join Date: Dec 2008
Posts: 13
ghoover is on a distinguished road
Default

Ok, here's a routine for getting the app support directory. I stick it in a category of NSFileManager.

Code:
enum
{
	DirectoryLocationErrorNoPathFound,
	DirectoryLocationErrorFileExistsAtLocation
};
	
NSString * const DirectoryLocationDomain = @"DirectoryLocationDomain";

- (NSString *)applicationSupportDirectory {
	NSString *executableName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleExecutable"];
	NSError *error;
	NSString *result = [self findOrCreateDirectory: NSApplicationSupportDirectory
										  inDomain: NSUserDomainMask
							   appendPathComponent: executableName
											 error: &error];
	if (error) {
		NSLog(@"Unable to find or create application support directory:\n%@", error);
	}
	return result;
}

- (NSString *)findOrCreateDirectory:(NSSearchPathDirectory)searchPathDirectory
	inDomain:(NSSearchPathDomainMask)domainMask
	appendPathComponent:(NSString *)appendComponent
	error:(NSError **)errorOut
{
	//
	// Search for the path
	//
	NSArray* paths = NSSearchPathForDirectoriesInDomains(
		searchPathDirectory,
		domainMask,
		YES);
	if ([paths count] == 0)
	{
		if (errorOut)
		{
			NSDictionary *userInfo =
				[NSDictionary dictionaryWithObjectsAndKeys:
					NSLocalizedStringFromTable(
						@"No path found for directory in domain.",
						@"Errors",
					nil),
					NSLocalizedDescriptionKey,
					[NSNumber numberWithInteger:searchPathDirectory],
					@"NSSearchPathDirectory",
					[NSNumber numberWithInteger:domainMask],
					@"NSSearchPathDomainMask",
				nil];
			*errorOut =
				[NSError 
					errorWithDomain:DirectoryLocationDomain
					code:DirectoryLocationErrorNoPathFound
					userInfo:userInfo];
		}
		return nil;
	}
	
	//
	// Normally only need the first path returned
	//
	NSString *resolvedPath = [paths objectAtIndex:0];

	//
	// Append the extra path component
	//
	if (appendComponent)
	{
		resolvedPath = [resolvedPath
			stringByAppendingPathComponent:appendComponent];
	}
	
	//
	// Check if the path exists
	//
	BOOL exists;
	BOOL isDirectory;
	exists = [self
		fileExistsAtPath:resolvedPath
		isDirectory:&isDirectory];
	if (!exists || !isDirectory)
	{
		if (exists)
		{
			if (errorOut)
			{
				NSDictionary *userInfo =
					[NSDictionary dictionaryWithObjectsAndKeys:
						NSLocalizedStringFromTable(
							@"File exists at requested directory location.",
							@"Errors",
						nil),
						NSLocalizedDescriptionKey,
						[NSNumber numberWithInteger:searchPathDirectory],
						@"NSSearchPathDirectory",
						[NSNumber numberWithInteger:domainMask],
						@"NSSearchPathDomainMask",
					nil];
				*errorOut =
					[NSError 
						errorWithDomain:DirectoryLocationDomain
						code:DirectoryLocationErrorFileExistsAtLocation
						userInfo:userInfo];
			}
			return nil;
		}
		
		//
		// Create the path if it doesn't exist
		//
		NSError *error;
		if (![self createDirectoryAtPath: resolvedPath
			 withIntermediateDirectories: YES
							  attributes: nil
								   error: &error]) {
			if (errorOut) {
				*errorOut = error;
			}
			return nil;
		}
	}
	
	if (errorOut)
		*errorOut = nil;
	return resolvedPath;
}

You have a variety of options for performing the actual download. I use curl in my apps, but NSURLConnection, NSURLDownload, etc are viable options. Check google for tutorials on using these.

The result of your download will be an NSData object. You can write that to your target file where the file path is the application support directory with the dated filename appended to the end.

For example:
Code:
NSString *path = [[self applicationSupportDirectory] stringByAppendingPathComponent: filename];
BOOL ok = [fileManager createFileAtPath: path
						   contents: data
						 attributes: nil];
Reading and writing the sqlite file requires using the sqlite C api. There may be cocoa wrappers available but I haven't investigated that. There are plenty of good online sources for using the sqlite api. You'll need to understand SQL commands as well.
ghoover is offline   Reply With Quote
Reply

Bookmarks

Tags
cache, iphone, sqlite

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On



» Advertisements
» Online Users: 304
9 members and 295 guests
ajay123123, ChrisYates, Fstuff, guusleijsten, HemiMG, newDev, pkIDSF, Sami Gh, Steven.C
Most users ever online was 1,387, 04-10-2012 at 04:21 AM.
» Stats
Members: 175,648
Threads: 94,113
Posts: 402,877
Top Poster: BrianSlick (7,990)
Welcome to our newest member, brandon6031
Powered by vBadvanced CMPS v3.1.0

All times are GMT -5. The time now is 07:49 PM.
Powered by vBulletin® Version 3.8.0
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.3.0