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.
Related
I am working on something using SQLite3 and I cant exactly figure out why I am getting an error. I have looked at other SO post and no one can actually quite put a finger on that error and I have tried a number of things. the code is failing on this line (sqlite3_open(dbPath, &itemDB)==SQLITE_OK).
I have tried:
commenting that line and saying sqlite3_open(dbPath, &itemDB), when i do that my code excecutes but nothing in the folder
Error from the NSLog was "unable to open database file" so i created the datbase and placed it in the path myself to see if that would help but no difference
Verified the path by using breakpoints, path is correct but the db is just never created.
-(void)openDatabase
{
NSArray *path=NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES);
NSString *docPath=[path objectAtIndex:0];
// dbPathString=[docPath stringByAppendingPathComponent:#"items.db"];
dbPathString = [docPath stringByAppendingPathComponent:#"items.sqlite"];
char *error;
NSFileManager *fileManager=[NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:dbPathString]) {
const char *dbPath=[dbPathString UTF8String];
//Create DB
if (sqlite3_open(dbPath, &items)==SQLITE_OK)
// sqlite3_open(dbPath, &items);
{
const char *sql_stmt= " CREATE TABLE IF NOT EXIST PERSON (ID INTEGER PRIMARY KEY AUTOINCREMENT,NAME TEXT,PRICE INTEGER)";
sqlite3_exec(items, sql_stmt, NULL, NULL, &error);
sqlite3_close(items);
NSLog(#"Db Created");
}
NSLog(#"%s", sqlite3_errmsg(items));
}
}
You are trying to write to the documentation directory, not the document directory.
Replace NSDocumentationDirectory with NSDocumentDirectory.
Try this tutorial
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: #"contacts.db"]];
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: databasePath ] == NO) {
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK) {
char *errMsg;
const char *sql_stmt = "CREATE TABLE IF NOT EXISTS CONTACTS (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT, ADDRESS TEXT, PHONE TEXT)";
if (sqlite3_exec(contactDB, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK) {
status.text = #"Failed to create table";
}
sqlite3_close(contactDB);
}
else {
status.text = #"Failed to open/create database";
}
}
This will help u
#import<sqlite3.h>
-(BOOL)createTable
{
NSArray *yourArray=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *filePath=[yourArray objectAtIndex:0];
filePath =[filePath stringByAppendingPathComponent:#"yourdatabase.sqlite"];
NSFileManager *manager=[NSFileManager defaultManager];
BOOL success = NO;
if ([manager fileExistsAtPath:filePath])
{
success =YES;
}
if (!success)
{
NSString *path2=[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"yourdatabase.sqlite"];
success =[manager copyItemAtPath:path2 toPath:filePath error:nil];
}
createStmt = nil;
NSString *tableName=#"SecondTable";
if (sqlite3_open([filePath UTF8String], &database) == SQLITE_OK) {
if (createStmt == nil) {
NSString *query=[NSString stringWithFormat:#"create table (ID INTEGER PRIMARY KEY AUTOINCREMENT,NAME TEXT,PRICE INTEGER)];
if (sqlite3_prepare_v2(database, [query UTF8String], -1, &createStmt, NULL) != SQLITE_OK) {
return NO;
}
sqlite3_exec(database, [query UTF8String], NULL, NULL, NULL);
return YES;
}
}
return YES;
}
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);
I'd like to get all tracks from an album on iTunes using iTunes.h.
Right now I get the data of the current track by:
NSInteger trackID = iTunes.currentTrack.databaseID;
NSString *name = iTunes.currentTrack.name;
And the name of the album by:
NSString *trackAlbum = iTunes.currentTrack.album;
But know I don't know how to get all the tracks that are in the same album as the current track.
Any ideas? Thanks
The iTunes API is poorly written.
You have to filter the array with a predicate.
NSArray *allSongs = [self allSongs];
NSArray *songsOfAlbum = [allSongs filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"album == %# && artist == %#", albumString, artistString]];
You can get all the songs like this:
// Get all Songs
- (NSArray *)allSongs {
if (_allSongs == nil) {
NSArray *tracksToPlay = [(SBElementArray *)[self.library tracks] get];
// Sort by artist
_allSongs = tracksToPlay;
}
return _allSongs;
}
- (iTunesLibraryPlaylist *)library {
if (_library == nil) {
// Whole Library
iTunesSource *source = [[[[self.iTunes sources] get] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"kind == %i", iTunesESrcLibrary]] objectAtIndex:0];
// Only the Music
_library = [[[[source playlists] get] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"specialKind == %i", iTunesESpKMusic]] objectAtIndex:0];
}
return _library;
}
You can use iTunes Library Framework (10.9 osx) for iTunes 11.
#import <iTunesLibrary/ITLibrary.h>
#import <iTunesLibrary/ITLibMediaItem.h>
#import <iTunesLibrary/ITLibAlbum.h>
NSError *error = nil;
ITLibrary *library = [ITLibrary libraryWithAPIVersion:#"1.0" error:&error];
if (library)
{
NSArray *tracks = library.allMediaItems; // <- NSArray of ITLibMediaItem
}
for (ITLibMediaItem *item in tracks) {
NSLog(#"tracks %#",item.album.title);
}
You can fetch album information from ITLibMediaItem
As an example to retrieve the artworks I have submitted a github repository:
It is an objective c code which uses the above code changed:
#import <Foundation/Foundation.h>
#import <iTunesLibrary/ITLibrary.h>
#import <iTunesLibrary/ITLibMediaItem.h>
#import <iTunesLibrary/ITLibArtwork.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSError *error = nil;
ITLibrary *library = [ITLibrary libraryWithAPIVersion:#"1.0" error:&error];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (library)
{
//NSArray *playlists = library.allPlaylists; // <- NSArray of ITLibPlaylist
NSArray *tracks = library.allMediaItems; // <- NSArray of ITLibMediaItem
[tracks enumerateObjectsUsingBlock:^(ITLibMediaItem* _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (obj.artworkAvailable) {
ITLibArtwork* artWork=obj.artwork;
//NSData* d=artWork.imageData;
switch (artWork.imageDataFormat) {
case ITLibArtworkFormatPNG:{
NSURL* fileURL=obj.location;
NSString* fs=fileURL.lastPathComponent;
NSString* path=[fileURL.path stringByReplacingOccurrencesOfString:fs withString:#"Folder.png"];
if (![fileManager fileExistsAtPath:path]){
[artWork.imageData writeToFile:path atomically:YES];
}
}
break;
case ITLibArtworkFormatJPEG:{
NSURL* fileURL=obj.location;
NSString* fs=fileURL.lastPathComponent;
NSString* path=[fileURL.path stringByReplacingOccurrencesOfString:fs withString:#"Folder.jpg"];
if (![fileManager fileExistsAtPath:path]){
[artWork.imageData writeToFile:path atomically:YES];
}
}
break;
default:
break;
}
}
}];
NSLog(#"End reached");
}
}
return 0;
}
https://github.com/ENees/iTunesGetImages
I have been using SQLite for awhile now, and have decided to go to FMDB. I need to make it a singleton. Here's my code below; what do I have to change to have FMDB access the singleton d/b?
#pragma mark Singleton Methods
+ (SQLiteDB *) sharedSQLiteDB {
if(!sharedSQLiteDB) {
sharedSQLiteDB = [[SQLiteDB alloc] init];
[sharedSQLiteDB openCreateDB]; // check to see if d/b exists
}
return sharedSQLiteDB;
}
and this is the code I use to initialize the d/b using FMDB:
//----------------------- checkIfDatabaseExists -----------------|
- (void) openCreateDB {
searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); // Get the path to the database file
documentPath = [searchPaths objectAtIndex:0];
databasePath = [documentPath stringByAppendingPathComponent:#"ppcipher.s3db"];
cDatabasePath = [databasePath cStringUsingEncoding:NSUTF8StringEncoding];
NSLog(#"d/b path: /%#", databasePath);
NSString *sqlCommand = #"CREATE TABLE CardData (card_id TEXT PRIMARY KEY NOT NULL, card_name TEXT NOT NULL, "
#"card_type TEXT, code_val TEXT, create_date TEXT DEFAULT CURRENT_DATE, user_notes TEXT, gps_loc TEXT)";
char * errmsg = nil;
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtPath:databasePath error:NULL]; // <------------ delete d/b TESTING ONLY!
BOOL fileExists = [fileManager fileExistsAtPath:databasePath];
if(!fileExists) {
FMDatabase* db = [FMDatabase databaseWithPath: databasePath];
if (![db open]) {
NSLog(#"Could not open/create database");
}
[db executeUpdate:#"CREATE TABLE CardData (card_id TEXT PRIMARY KEY NOT NULL, card_name TEXT NOT NULL, "
#"card_type TEXT, code_val TEXT, create_date TEXT DEFAULT CURRENT_DATE, user_notes TEXT, gps_loc TEXT)"];
if(errmsg != nil)
NSLog(#"error: %s", errmsg); // DEBUGGING ONLY! (REMOVE when done!)
}
return;
}
Your SQLiteDB class will need to maintain a reference to your FMDatabase so your additional methods will be able to share the same database.
#interface SQLiteDB : NSObject //Or whatever base class
{
FMDatabase *_database;
}
#end
//implementation
- (void) openCreateDB {
...
if(!fileExists) {
_database = [[FMDatabase databaseWithPath: databasePath] retain];
...
}
}
my NSMutableArray creation code is being bypassed altogether for some reason. in theory it is supposed to create an NSMutableArray based on an sqlite database. There is only one warning message and no errors. what am I missing?
the implementation file is:
#import "iProspectFresno LiteAppDelegate.h"
#import "MainViewController.h"
#import "Mine.h"
#import <Foundation/Foundation.h>
#implementation iProspectFresno_LiteAppDelegate
#synthesize window;
#synthesize mainViewController;
#synthesize mines;
-(void) checkAndCreateDatabase {
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
success = [fileManager fileExistsAtPath:databasePath];
if(success) return;
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseName];
[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
}
-(void) readMinesFromDatabase
{
sqlite3 *database;
mines = [[NSMutableArray alloc] init];
NSLog(#"readMinesFromDatabase initialized");
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
const char *sqlStatement = "select * from MinesoftheMotherLode";
sqlite3_stmt *compiledStatement;
NSLog(#"first if statement");
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK)
{
NSLog(#" second if statement initialized");
while(sqlite3_step(compiledStatement) == SQLITE_ROW)
{
NSNumber *aentryNumber = [NSNumber numberWithInt:(int)sqlite3_column_int(compiledStatement, 1)];
NSString *amineName = [NSString stringWithUTF8String:(char*)sqlite3_column_text(compiledStatement, 2)];
NSString *amineType = [NSString stringWithUTF8String:(char*)sqlite3_column_text(compiledStatement, 3)];
NSString *astatus = [NSString stringWithUTF8String:(char*)sqlite3_column_text(compiledStatement, 4)];
NSNumber *alatitude = [NSNumber numberWithDouble:(double)sqlite3_column_double(compiledStatement, 5)];
NSNumber *alongitude = [NSNumber numberWithDouble:(double)sqlite3_column_double(compiledStatement, 6)];
NSString *ametal =[NSString stringWithUTF8String:(char*)sqlite3_column_text(compiledStatement, 7)];
BOOL *adisplay = NO;
NSNumber *acoverRegion =[NSNumber numberWithInt:(int)sqlite3_column_int(compiledStatement, 9)];
NSLog(#"mine", aentryNumber, amineName, amineType, astatus, alatitude, alongitude, ametal, adisplay, acoverRegion);
Mine *mine = [[Mine alloc] initWithEntryNumber:aentryNumber mineName:amineName mineType:amineType status:astatus latitudeInitial:alatitude longitudeInitial:alongitude metal:ametal display:adisplay coverRegion:acoverRegion];
[mines addobject:mine];
[mine release];
}
}
NSLog(#"created database successfully");
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
- (void)applicationDidFinishLaunching:(UIApplication *)application {
databaseName = #"MinesoftheMotherLode.sql";
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
[self checkAndCreateDatabase];
[self readMinesFromDatabase];
MainViewController *aController = [[MainViewController alloc] initWithNibName:#"MainView" bundle:nil];
self.mainViewController = aController;
[aController release];
mainViewController.view.frame = [UIScreen mainScreen].applicationFrame;
[window addSubview:[mainViewController view]];
[window makeKeyAndVisible];
}
The implementation file for Mines is here:
#import "Mine.h"
#implementation Mine
#synthesize entryNumber, mineName, mineType, status, latitudeInitial, longitudeInitial, metal, display, coverRegion;
-(id)initWithEntryNumber:(NSNumber *)e mineName:(NSString *)n mineType:(NSString *)t status:(NSString *)s latitudeInitial:(NSNumber *)l longitudeInitial:(NSNumber *)o metal:(NSString *)m display:(BOOL *)d coverRegion:(NSNumber *)c
{
self.entryNumber = e;
self.mineName = n;
self.mineType = t;
self.status = s;
self.latitudeInitial = l;
self.longitudeInitial = o;
self.metal = m;
self.display = d;
self.coverRegion = c;
return self;
}
#end
The NSLog "Second if statement initialized" is not showing up on the console. any ideas as to what needs to be fixed here? and yes I know, I should be using core data.
It seems you've answered your initial question about it loading. For your secondary question regarding the crash about the null string, you should be loading strings like this:
if (sqlite3_column_text(init_statement, 0) != NULL) {
self.someString = [NSString stringWithUTF8String:(char *)sqlite3_column_text(init_statement, 0)];
} else {
self.someString = #"";
}