For some reason, my app doesn't seem to create a database in the Documents folder. I have been following this video tutorial (http://www.youtube.com/watch?v=bC3F8a4F_KE) (it also has the source code available (https://github.com/iffytheperfect1983/sqliteTutorial) which I downloaded and it ran on the Simulator perfectly).
I used a few NSLog statements to attempt to pinpoint the problem. I realized that while all of the code up to "Declared" statement ran with no problems, the rest of the NSLog statements didn't show up in the console. I have looked tirelessly back and forth between the code I wrote and the code in the tutorial but with no avail for a solution.
Here is the code.
#interface ViewController () {
NSMutableArray *letterArray;
sqlite3 *letterDB;
NSString *dbPathString;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Set up
letterArray = [[NSMutableArray alloc]init];
[[self letterList] setDelegate:self];
[[self letterList] setDataSource:self];
// create or open database
[self createOpenDB];
// Display database
[self displayDB];
}
// Create/open database
- (void) createOpenDB {
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES);
NSString *docPath = [path objectAtIndex:0];
dbPathString = [docPath stringByAppendingPathComponent:#"letters.db"];
char *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:dbPathString]) {
const char *dbPath = [dbPathString UTF8String];
NSLog(#"Declared");
// create database here
if (sqlite3_open(dbPath, &lettersDB)==SQLITE_OK) {
NSLog(#"'If' statement is ok");
const char *sql_stmt = "CREATE TABLE IF NOT EXISTS LETTERS (ID INTEGER PRIMARY KEY AUTOINCREMENT, A TEXT, B TEXT, C TEXT, D TEXT, E TEXT, F TEXT, G TEXT)";
NSLog(#"Declared");
sqlite3_exec(lettersDB, sql_stmt, NULL, NULL, &error);
NSLog(#"Execution complete.");
sqlite3_close(lettersDB);
NSLog(#"Close complete.");
NSLog(#"Database creation successful.");
}
}
}
How do I solve this? Thank you in advance.
You're using the NSDocumentationDirectory when you should be using the NSDocumentDirectory directory.
Change this:
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES);
To this:
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
Related
I have an iOS app that at times needs to store UIImage objects locally.
I am using [UIImagePNGRepresentation(image) writeToFile:full_path options:NSAtomicWrite error:nil]; to save the image and [file_manager removeItemAtPath:full_path error:NULL]; to delete the file.
This all works great, however, whenever I delete a file, should I decide to save a new file (which just so happens to have the same name as the old file), the save code doesn't work and returns the following error:
: ImageIO: CGImageReadCreateDataWithMappedFile 'open' failed
error = 2 (No such file or directory)
: ImageIO: CGImageReadCreateDataWithMappedFile 'open' failed
error = 2 (No such file or directory)
: ImageIO: PNG zlib error
So heres what I don't get, why can't I save a file with the same name as the old file, after I have deleted the old file?
The reason I ask this, is that, my app will save certain image files and then when they are no longer needed, my app will delete them. However, there are times when my app needs the image files again (could be a few hours after deletion or a few weeks). When this happens, my app will load the appropriate image data and then try to save it. And thats when the error occurs.
Whats going wrong here?
Thanks for your time, Dan.
UPDATE - Here are the methods I have setup to save/access and delete my image files
-(void)save_local_image:(UIImage *)image :(NSString *)file_name {
// Get the app documents directory link.
NSString *documents = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
// Add the new file name to the link.
NSString *database_link = [[NSString alloc] initWithString:[documents stringByAppendingPathComponent:file_name]];
// Save the image data locally.
[UIImagePNGRepresentation(image) writeToFile:database_link options:NSAtomicWrite error:nil];
}
-(UIImage *)get_local_image:(NSString *)file_name {
// Create the return data.
UIImage *image_data = nil;
// Get the app documents directory.
NSArray *directory = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] error:NULL];
// Only check for data if at least
// one file has been saved locally.
if ([directory count] > 0) {
// Loop through the different local files.
for (NSString *path in directory) {
// Get the full local file URL.
NSString *full_path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:path];
// Get the range of the file name.
NSRange range = [full_path rangeOfString:file_name];
// Get the image data if it exists.
if ((range.location != NSNotFound) || (range.length == [file_name length])) {
// Load the image file in.
image_data = [UIImage imageWithContentsOfFile:full_path];
break;
}
}
}
return image_data;
}
-(void)delete_local_image:(NSString *)file_name {
// Get the app documents directory.
NSArray *directory = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] error:NULL];
// Only check for data if at least
// one file has been saved locally.
if ([directory count] > 0) {
// Loop through the different local files.
for (NSString *path in directory) {
// Get the full local file URL.
NSString *full_path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:path];
// Get the range of the file name.
NSRange range = [full_path rangeOfString:file_name];
// Delete the local image data if it exists.
if ((range.location != NSNotFound) || (range.length == [file_name length])) {
NSError *testError = nil;
// Delete the image file.
NSFileManager *file_manager = [[NSFileManager alloc] init];
BOOL success = [file_manager removeItemAtPath:full_path error:&testError];
NSLog(#"%d", success);
if (testError != nil) {
NSLog(#"%#", testError.localizedDescription);
}
break;
}
}
}
}
I am using this to save and read:
- (void) saveImageToFile:(NSString *) urlImg withNameNumber:(int)numberName andQuestionId:(int) questionID
{
NSString* documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString* foofile = [documentsPath stringByAppendingPathComponent:[NSString stringWithFormat:#"gallery%d%d.jpg",numberName,questionID]];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:foofile];
if (!fileExists) {
NSData *tempImgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#%#",#"https://testurl/",urlImg]]];
NSString *filename = [NSString stringWithFormat:#"gallery%d%d.jpg",numberName,questionID];
NSString *imagePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:filename];
[tempImgData writeToFile:imagePath atomically:YES];
}
}
-(UIImage*) readImageFromFile:(int)numberName andQuestionId:(int) questionID
{
NSString * documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
return [UIImage imageWithContentsOfFile:[NSString stringWithFormat:#"%#/gallery%d%d.jpg",documentsDirectoryPath,numberName,questionID]];
}
I am using SQLite and previous answers state that I should use this code:
#import "ViewController.h"
#interface ViewController ()
{
NSMutableArray *arrayOfPerson;
sqlite3 *personDB;
NSString *dbPathString;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
arrayOfPerson = [[NSMutableArray alloc]init];
[[self myTableView]setDelegate:self];
[[self myTableView]setDataSource:self];
[self createOrOpenDB];
}
- (void)createOrOpenDB
{
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docPath = [path objectAtIndex:0];
dbPathString = [docPath stringByAppendingPathComponent:#"persons.db"];
char *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL success = [fileManager fileExistsAtPath:dbPathString];
NSLog(#"here 0");
if (!success) {// THIS IS MY CONCERN
const char *dbPath = [dbPathString UTF8String];
NSLog(#"here 1");
//creat db here
NSLog(#"sqlite3 = %d",sqlite3_open(dbPath, &personDB));
NSLog(#"OK= %d", SQLITE_OK);
if (sqlite3_open(dbPath, &personDB)==SQLITE_OK) {
NSLog(#"here 2");
const char *sql_stmt = "CREATE TABLE IF NOT EXISTS PERSONS (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT, AGE INTEGER)";
sqlite3_exec(personDB, sql_stmt, NULL, NULL, &error);
sqlite3_close(personDB);
}
}
}
However, when I run this code my app does not gets into this loop:
if(!success) {
....
}
I tried using
if(success) {
....
}
and it works. But I do not think that is correct. Please help me.
In my Application,I am taking screenshots of image View and then I am saving those screen shots in document folder of the application.Now I want to Email all those images with the same folder structure they are in.Zipping all the folders containing the images?
-(void)ZipFile2{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDirectory = [paths objectAtIndex:0];
BOOL isDir=NO;
NSArray *subpaths;
NSString *exportPath = docDirectory;
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:exportPath isDirectory:&isDir] && isDir){
subpaths = [fileManager subpathsAtPath:exportPath];
}
NSString *archivePath = [docDirectory stringByAppendingString:#"Uploads.zip"];
ZipArchive *archiver = [[ZipArchive alloc] init];
[archiver CreateZipFile2:archivePath];
for(NSString *path in subpaths)
{
NSString *longPath = [exportPath stringByAppendingPathComponent:path];
if([fileManager fileExistsAtPath:longPath isDirectory:&isDir] && !isDir)
{
[archiver addFileToZip:longPath newname:path];
}
}
BOOL successCompressing = [archiver CloseZipFile2];
if(successCompressing)
NSLog(#"Success");
else
NSLog(#"Fail");
}
I use this code but the zip file is not created in my Ipad ??? can you Help Me
ZipArchive has a delegate protocol which sends a message whenever a error occurs.
add below ZipArchive allocation.
archiver.delegate = self
Add protocol to header class and then implement the following method:
- (void)ErrorMessage:(NSString*) msg {
NSLog(#"Zip error: %#", msg);
}
I'm having some issue connecting to my sqlite database.. I'm using xcode version 4.4.1
here's my code..
NSString *docsDir;
NSArray *dirPaths;
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
// Build the path to the database file
databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: #"signature.db"]];
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: databasePath ] == NO)
{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
status.text = #"Connected..";
} else {
status.text = #"Failed to open/create database..";
}
}
[filemgr release];
Any suggestion..?
Thanks,
Boom
There is no need to check if the database exists; sqlite3_open_v2() (reference) will create the database, if it does not exist, if you pass the flag SQLITE_OPEN_CREATE:
NSString *dbPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPath:#"signature.db"];
if (sqlite3_open_v2([dbPath UTF8String], &database, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE) == SQLITE_OK)
{
status.text = #"Connected..";
// Check the schema and install if it doesn't exist
sqlite3_close(database);
} else {
status.text = #"Failed to open/create database..";
}
You may wish to check if the DB file is in place if you have one in your app's bundle that is pre-built so you can drop it into your documents folder. Of course, as you enhance your app, any schema changes will need to be done in code. Here is some code that I use (that works, but needs to updated a bit)
When opening/creating the DB I use this to specify where the DB file will be. I don't put it with the init because my location is different between iOS and Mac OS X and I want the DB code to work with both:
NSString *dbFilePath;
NSArray *searchPaths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentFolderPath = searchPaths[0];
dbFilePath = [documentFolderPath stringByAppendingPathComponent: #"MyDBFile.db"];
MyDB* appDB = [[EasySpendLogDB alloc] initWithFile:dbFilePath];
if(!appDB) {
// show error
return;
}
This is in my DB access class. It uses some wrapper classes I wrote:
- (id) initWithFile: (NSString*) filePathName {
if(!(self = [super init])) return nil;
BOOL myPathIsDir;
BOOL fileExists = [[NSFileManager defaultManager]
fileExistsAtPath: filePathName
isDirectory: &myPathIsDir];
NSString *backupDbPath = [[NSBundle mainBundle]
pathForResource:#"MyDBFile"
ofType:#"db"];
if (backupDbPath != nil && !fileExists) {
[[NSFileManager defaultManager]
copyItemAtPath:backupDbPath
toPath:filePathName
error:nil];
}
db = [[ABSQLiteDB alloc] init];
if(![db connect:filePathName]) {
return nil;
}
[self checkSchema]; // this is where schema updates are done (see project sample)
return self;
}
You may also want to check out this objective-c wrapper I wrote that has a sample project: https://github.com/AaronBratcher/ABSQLite
Suppose I have a custom function called savePlist as below.
CommonClass.m
- (NSString *)getDirectoryPath
{
NSArray *pathList = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [pathList objectAtIndex:0];
return path;
}
- (void)savePlist:(NSString *)fileName WithArray:(NSArray *)fileArr
{
NSString *path = [[self getDirectoryPath] stringByAppendingPathComponent:fileName];
[fileArr writeToFile:path atomically:YES];
}
While I run a code as below, no plist is generated.
ABCAppDelegate.m
...
[cc savePlist:#"example.plist" WithArray:[NSArray new]];
The file of example.plist has not been generated, is there any mistakes on my code?
Thanks
UPDATE:
If I use the code as below, the xxx.plist file has been generated successfully.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *plistFile = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"abc.plist"];
NSMutableDictionary *plist = [[NSMutableDictionary alloc] initWithContentsOfFile:plistFile];
if (!plist) {
plist = [NSMutableDictionary new];
[plist writeToFile:plistFile atomically:YES];
NSLog(#"write plist");
}
Reference: link
UPDATE 2:
I change the code as below:
NSLog(#"code");
[cc savePlist:#"example.plist" WithArray:[NSArray new]];
NSLog(#"code");
- (void)savePlist:(NSString *)fileName WithArray:(NSArray *)fileArr
{
NSLog(#"fileName = %#, fileArr = %#", fileName, fileArr);
NSString *path = [[self getDirectoryPath] stringByAppendingPathComponent:fileName];
NSLog(#"path = %#", path);
[fileArr writeToFile:path atomically:YES];
}
It just print out:
2011-10-10 14:24:00.560 ABC[3390:207] code
2011-10-10 14:24:00.561 ABC[3390:207] code
No message of fileName = and fileArr =, also path = print out on the log, so the code inside savePlist have not been executed?
It looks like your common class object is not instantiated, and you are sending all those messages to nil. Try logging cc in your app delegate code, where you call this method from.
You need to create an instance of your common class, something like
cc = [[CommonClass alloc] init];
(may vary depending on your set up).