Copy SQLite Database from URL to Local Path - database

What can I use to copy a remote database to a local path?
success = [FileManager copyItemAtURL:dbPath toPath:databasePath error: &error];
Obviously the above won't work. Looking at the manual it seems you can copy path to path or url to url. But I've seen example of myapp://path/to/documents/database.sql. Now I'm sorta confused. Can someone possibly point me in the right direction?
This is what I'm doing right now... but it's not overwriting the database or I'm doing things in the wrong order. The file is only a couple of Kbs also.
- (void)createDB {
BOOL success;
NSError *error;
NSData *fetchedData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://www.dot.com/book/book.sqlite"]];
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [documentsPath stringByAppendingPathComponent:#"book.sqlite"];
[fetchedData writeToFile:filePath atomically:YES];
NSLog(#"%#", filePath);
NSFileManager *FileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *databasePath = [documentsDirectory stringByAppendingString:#"book.sqlite"];
success = [FileManager fileExistsAtPath:databasePath];
if(success)return;
NSString *dbPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"book.sqlite"];
success = [FileManager copyItemAtPath:dbPath toPath:databasePath error: &error];
if(!success)
NSAssert1(0, #"Failed to copy database. Error: %#", [error localizedDescription]);
}

I see by the line,
NSString *dbPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"book.sqlite"];
you are trying to get the db from Resources directory, but your code above actually downloads the sqlite directly to Documents directory NOT resources (which is not writable)
It fails because there is no book.sqlite at resources directory. You don't need to copy the file since it is already present in Documents directory

Related

Get File Size at URL Objective-C

I'm looking for a way to get the file size of a specific file at an NSURL address. This is what I have tried but it always returns '0' in the log output:
NSString *url = #"http://www.examplesite.com/file01.zip";
unsigned long long fileSize1 = [[[NSFileManager defaultManager] attributesOfItemAtPath:[url lastPathComponent] error:nil] fileSize];
NSLog(#"size of %# in bytes === %llu", [url lastPathComponent], fileSize1);
After searching some on I found this solution. It finds the file size of the file on the server and shows the result in the log.
NSString *url = #"http://www.examplesite.com/file01.zip";
NSURL *URL = [NSURL URLWithString:url];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
[request setHTTPMethod:#"HEAD"];
NSHTTPURLResponse *response;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error: nil];
long long size = [response expectedContentLength];
NSLog(#"File size before download: %lld",size);

Objective-C - How to write an array to a file?

I have a text file that I can scan (NSScanner) and tag. The results are stored in an array. The structure is two strings, one for english and one for greek.
I want to write an output file that maintains the array structure. I presume I can create a plist file for this purpose.
However, I'm stuck and need help to create this file.
I have a test whether the file was created, but I get this result:
outgoingWords.count: 442
2014-08-12 17:54:17.369 MyScanner[97350:2681695] *** Assertion failure in -[ViewController checkArray], /Users/david/Desktop/Word Scanning/MyScanner/MyScanner/ViewController.m:98
2014-08-12 17:54:17.373 MyScanner[97350:2681695] Failed to set (contentViewController) user defined inspected property on (NSWindow): writeToFile failed
The code I'm using so far is as follows:
-(void)checkArray {
//do stuff to verify the array
long i = outgoingWords.count;
NSString *tempString = [NSString stringWithFormat:#"%li", i];
NSLog(#"outgoingWords.count: %#", tempString); //442
NSArray *tempArray2 = [outgoingWords copy];
NSString *path = [[NSBundle mainBundle] pathForResource:#"/Users/David/Desktop/alfa2" ofType:#"plist"];
BOOL success = [tempArray2 writeToFile:path atomically:YES];
NSAssert(success, #"writeToFile failed");
}
Could someone either identify what I'm missing, or point me to an existing answer I can use (I've looked)..
Many thanks..
edit. I've also tried the approach in this SO question. But get the same result.
NSString *path = [[NSBundle mainBundle] pathForResource:#"/Users/David/Desktop/alfa2" ofType:#"plist"];
NSString *error;
NSData *data = [NSPropertyListSerialization dataFromPropertyList:tempArray2 format:NSPropertyListBinaryFormat_v1_0 errorDescription:&error];
BOOL success = [NSKeyedArchiver archiveRootObject:data toFile:path];
NSAssert(success, #"archiveRootObject failed");
Problem is that you are writing to the bundle, which is not allowed. You should write to a path in your document or other directory, for example:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
filePath = [documentsDirectory stringByAppendingPathComponent:#"FileName.xxx"];
[data writeToFile:filePath atomically:NO];

NSURL custom scheme trouble

I wrote below code to programmatically load a URL in UIWebview.
NSString *urlStr = [NSString stringWithFormat:#"app-api://camera_button(%#)", #"{\"date\":\"2014-05-26\",\"referer_url\":\"http://google.com",\"abort_url\":\"http://google.com"}"];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlStr]]];
And in the webView's delegate method webView:shouldStartLoadWithRequest:navigationType: , I found the url being loaded has been changed to 'file://app-api://......'. But what I needed is 'app-api:......'. Anyone can tell me what the problem is ? Thanks in advance.
Ok if problem in URL string, then use following code (stringByAddingPercentEscapesUsingEncoding)
NSString *urlString = [NSString stringWithFormat:#"URL_STRING"];
NSURL *finalURL = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
EDITED
You can remove file:// from your url string by using following code
NSString *selectedRequest = "MY URL STRING";
NSString *requestString = [selectedRequest stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *finalString = [requestString stringByReplacingOccurrencesOfString:#"file://" withString:#""];
NSLog(#"%#", finalString);

Adding data given by the user to an array - Objective-C

I'm trying to create a Mac OS X app where there are some default sound and the user can add others if he wants. I'm loading the sounds to an array in -awakeFromNib :
for (NSString *str in [PreferencesController beats]) {
resourcePath = [[NSBundle mainBundle] pathForSoundResource:str];
beat = [[NSSound alloc] initWithContentsOfFile:resourcePath byReference:YES];
[beat setLoops:YES];
[beat setName:str];
[beatsArray addObject:beat];
}
Everything works fine until the app tries to add to the array a sound added by the user. It says : *** -[NSURL initFileURLWithPath:]: nil string parameter. I'm guessing that it can't find the URL of the file but I'm copying the file to the app's directory when the user selects it by the following code :
if ( [openDlg runModalForTypes:[NSArray arrayWithObjects:#"aif",#"aiff",#"mp3",#"wav",#"m4a",nil]] == NSOKButton)
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSString *dataPath = [[NSBundle mainBundle] bundlePath];
NSLog(#"Datapath is %#", dataPath);
NSLog(#"Selected Files : %#",[[openDlg URLs] objectAtIndex:0]);
[fileManager copyItemAtURL: [[openDlg URLs] objectAtIndex:0] toURL: [NSURL fileURLWithPath: [[NSBundle mainBundle] bundlePath]] error:&error];
NSLog(#"File copied");
NSMutableArray *newArray = [[NSMutableArray alloc] initWithArray:[PreferencesController beats]];
NSString *fileName = [[[openDlg URL] path] lastPathComponent];
NSArray *fileNameArray = [fileName componentsSeparatedByString:#"."];
[newArray addObject:[fileNameArray objectAtIndex:0]];
NSLog(#"%#",newArray);
[PreferencesController setBeats:newArray];
[self awakeFromNib];
[_tableView reloadData];
}
What's wrong with this code?
Looks like you're trying to copy a file to a folder because you're just using the bundle path as the destination URL. The destination URL needs to specify the full path including the destination file name.
Try logging the error when the file is copied:
NSLog(#"File copied with error: %#", error);
This line contains the error:
[fileManager copyItemAtURL: [[openDlg URLs] objectAtIndex:0] toURL: [NSURL fileURLWithPath: [[NSBundle mainBundle] bundlePath]] error:&error];
Specifically, the problem is that the destination URL is a folder:
[[NSBundle mainBundle] bundlePath]
It should be something like:
[[[NSBundle mainBundle] bundlePath] stringByAppendingString:[[[[openDlg URLs] objectAtIndex:0] path] lastPathComponent];
Then, once you have it working, as #Abizern says in the comments, saving to the bundle is a bad idea (it's part of the app).
Once you have it working, you should choose a better location to save the sounds to (like a support document folder for the app, Programmatically get path to Application Support folder)

xcode sqlite3 "out of memory" error

When we run the checkAndCreateDatabase method it says that the database exists but the sqlite3_error message returns an "out of memory" error before exiting the method. How can this be fixed?
-(void) checkAndCreateDatabase{
NSLog(#"Run Method: checkAndCreateDatabase");
// Check if the SQL database has already been saved to the users phone, if not then copy it over
BOOL success;
// Create a FileManager object, we will use this to check the status
// of the database and to copy it over if required
// Check if the database has already been created in the users filesystem
success = [[NSFileManager defaultManager] fileExistsAtPath:databasePath];
// If the database already exists then return without doing anything
if(success){
NSLog(#"Database Exists");
} else {
// If not then proceed to copy the database from the application to the users filesystem
NSLog(#"Database Does Not Exist");
// Get the path to the database in the application package
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseName];
// Copy the database from the package to the users filesystem
[[NSFileManager defaultManager] copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
NSLog(#"Database Copied To filesystem And Exists");
}
NSLog(#"Method checkAndCreateDatabase Finished Message: %s",sqlite3_errmsg(database));
return;
}
- (void)viewDidLoad {
NSLog(#"Run Method: viewDidLoad");
// Setup some globals
databaseName = #"w2w.db";
NSLog(#"Database Name: %#",databaseName);
// Get the path to the documents directory and append the databaseName
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
NSLog(#"Database Path: %#",databasePath);
// Execute the "checkAndCreateDatabase" function
[self checkAndCreateDatabase];
[super viewDidLoad];
}
Where is the database variable being initialized? I've run into this same error message when I have accidentally passed in an undefined or incorrect parameter to sqlite3_errmsg(). I think this is the default error message.

Resources