web-dev-qa-db-fra.com

Utiliser et accéder à la base de données SQLite existante sur iOS

J'ai une base de données entièrement remplie dans SQLite que j'aimerais utiliser dans ma nouvelle application. C'est plutôt grand, alors j'aimerais éviter de changer si possible dans un autre format. Comment puis-je utiliser cette base de données de telle sorte qu'elle soit livrée avec mon application?

EDIT: Si je viens de déposer le fichier dans mon répertoire de fichiers pris en charge, par exemple, comment puis-je y accéder? Comment puis-je le référencer?

15
muttley91

L'interaction avec la base de données SQLite peut être rendue simple et nette à l'aide de FBDB Framework. FMDB est un wrapper d'Objective-C pour l'interface SQLite C.

Référence à lire:

Documentation de la FMDB

Exemple de projet avec storyboard

La configuration initiale

Ajoutez le SQLite DB comme n'importe quel autre fichier de l'ensemble de votre application, puis copiez la base de données dans le répertoire de documents à l'aide du code suivant, puis utilisez la base de données à partir du répertoire de documents

  1. Commencez par télécharger le FMDB Framework
  2. Extraire la structure maintenant, copiez tout le fichier du dossier src/fmdb (pas les dossiers src/sample ou src/extra).
  3. Cliquez sur votre projet dans la colonne de gauche de Xcode.
  4. Cliquez sur la cible principale dans la colonne du milieu.
  5. Cliquez sur l'onglet «Build Phases».
  6. Développez la flèche en regard de «Lier le binaire avec les bibliothèques».
  7. Cliquez sur le bouton "+".
  8. Recherchez libsqlite3.0.dylib et double-cliquez dessus.

Copiez votre existing database dans app's document dans didFinishLaunchingWithOptions: et conservez le chemin d'accès à la base de données tout au long de l'application.

Dans votre AppDelegate, ajoutez le code suivant.

AppDelegate.m

#import "AppDelegate.h"

@implementation AppDelegate

// Application Start
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // Function called to create a copy of the database if needed.
    [self createCopyOfDatabaseIfNeeded];

    return YES;
}

#pragma mark - Defined Functions

// Function to Create a writable copy of the bundled default database in the application Documents directory.
- (void)createCopyOfDatabaseIfNeeded {
    // First, test for existence.
    BOOL success;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSError *error;
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    // Database filename can have extension db/sqlite.
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *appDBPath = [documentsDirectory stringByAppendingPathComponent:@"database-name.sqlite"];

    success = [fileManager fileExistsAtPath:appDBPath];
    if (success) {
        return;
    }
    // The writable database does not exist, so copy the default to the appropriate location.
    NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"database-name.sqlite"];
    success = [fileManager copyItemAtPath:defaultDBPath toPath:appDBPath error:&error];
    NSAssert(success, @"Failed to create writable database file with message '%@'.", [error localizedDescription]);
}

YourViewController.m

Sélectionner une requête

#import "FMDatabase.h"

- (void)getAllData {
    // Getting the database path.
    NSArray  *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *docsPath = [paths objectAtIndex:0];
    NSString *dbPath = [docsPath stringByAppendingPathComponent:@"database-name.sqlite"];

    FMDatabase *database = [FMDatabase databaseWithPath:dbPath];
    [database open];
    NSString *sqlSelectQuery = @"SELECT * FROM tablename";

    // Query result 
    FMResultSet *resultsWithNameLocation = [database executeQuery:sqlSelectQuery];
    while([resultsWithNameLocation next]) {
        NSString *strID = [NSString stringWithFormat:@"%d",[resultsWithNameLocation intForColumn:@"ID"]];
        NSString *strName = [NSString stringWithFormat:@"%@",[resultsWithNameLocation stringForColumn:@"Name"]];
        NSString *strLoc = [NSString stringWithFormat:@"%@",[resultsWithNameLocation stringForColumn:@"Location"]];

        // loading your data into the array, dictionaries.
        NSLog(@"ID = %d, Name = %@, Location = %@",strID, strName, strLoc);
    }
    [database close];   
}

Insérer une requête

#import "FMDatabase.h"

- (void)insertData {

    // Getting the database path.
    NSArray  *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *docsPath = [paths objectAtIndex:0];
    NSString *dbPath = [docsPath stringByAppendingPathComponent:@"database-name.sqlite"];

    FMDatabase *database = [FMDatabase databaseWithPath:dbPath];
    [database open];    
    NSString *insertQuery = [NSString stringWithFormat:@"INSERT INTO user VALUES ('%@', %d)", @"Jobin Kurian", 25];
    [database executeUpdate:insertQuery];   
    [database close];
}

Requête de mise à jour

- (void)updateDate {

    // Getting the database path.
    NSArray  *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *docsPath = [paths objectAtIndex:0];
    NSString *dbPath = [docsPath stringByAppendingPathComponent:@"fmdb-sample.sqlite"];

    FMDatabase *database = [FMDatabase databaseWithPath:dbPath];
    [database open];    
    NSString *insertQuery = [NSString stringWithFormat:@"UPDATE users SET age = '%@' WHERE username = '%@'", @"23", @"colin" ];
    [database executeUpdate:insertQuery];
    [database close];
}

Supprimer la requête

#import "FMDatabase.h"

- (void)deleteData {

    // Getting the database path.
    NSArray  *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *docsPath = [paths objectAtIndex:0];
    NSString *dbPath = [docsPath stringByAppendingPathComponent:@"database-name.sqlite"];

    FMDatabase *database = [FMDatabase databaseWithPath:dbPath];
    [database open];
    NSString *deleteQuery = @"DELETE FROM user WHERE age = 25";
    [database executeUpdate:deleteQuery];   
    [database close];
}

Ajout de fonctionnalité

Obtenir le nombre de lignes

Assurez-vous d'inclure le fichier FMDatabaseAdditions.h à utiliser intForQuery:.

#import "FMDatabase.h"
#import "FMDatabaseAdditions.h"

- (void)gettingRowCount {

    // Getting the database path.
    NSArray  *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *docsPath = [paths objectAtIndex:0];
    NSString *dbPath = [docsPath stringByAppendingPathComponent:@"database-name.sqlite"];

    FMDatabase *database = [FMDatabase databaseWithPath:dbPath];
    [database open];
    NSUInteger count = [database intForQuery:@"SELECT COUNT(field_name) FROM table_name"];
    [database close];
}
40
icodebuster

Ajoutez la base de données SQL comme n'importe quel autre fichier de votre lot d'applications.

Copiez-le dans le répertoire de documents via le code et utilisez-le. Le but de cette opération est que la mise à jour du contenu dans sqlite est possible uniquement dans le répertoire de documents

-(void) 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
    NSFileManager *fileManager = [NSFileManager defaultManager];

    // Check if the database has already been created in the users filesystem
    success = [fileManager fileExistsAtPath:_databasePath];

    // If the database already exists then return without doing anything
    if(success) return;

    // If not then proceed to copy the database from the application to the users filesystem

    // 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
    [fileManager copyItemAtPath:databasePathFromApp toPath:_databasePath error:nil];

}

- (id)init {
    if ((self = [super init]))
    {
        _databaseName = DB_NAME;

        NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDir = [documentPaths objectAtIndex:0];
        _databasePath = [documentsDir stringByAppendingPathComponent:_databaseName];

        if (sqlite3_open([[self dbPath] UTF8String], &_database) != SQLITE_OK)
        {
            [[[UIAlertView alloc]initWithTitle:@"Missing"
                                       message:@"Database file not found"
                                      delegate:nil
                             cancelButtonTitle:@"OK"
                             otherButtonTitles:nil, nil]show];
        }
    }
    return self;
}
8
Lithu T.V

Utilisation de Swift, singleton class et FMDB. vous pouvez utiliser le code ci-dessous pour le réaliser très facilement.

Exemple de téléchargement

import Foundation
class LocalDatabase: NSObject {


//sharedInstance
static let sharedInstance = LocalDatabase()



    func methodToCreateDatabase() -> NSURL? {

    let fileManager = NSFileManager.defaultManager()

    let urls = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)

    if let documentDirectory:NSURL = urls.first { // No use of as? NSURL because let urls returns array of NSURL

        // exclude cloud backup
        do {
            try documentDirectory.setResourceValue(true, forKey: NSURLIsExcludedFromBackupKey)
        } catch _{
            print("Failed to exclude backup")
        }

        // This is where the database should be in the documents directory
        let finalDatabaseURL = documentDirectory.URLByAppendingPathComponent("contact.db")

        if finalDatabaseURL.checkResourceIsReachableAndReturnError(nil) {
            // The file already exists, so just return the URL
            return finalDatabaseURL
        } else {
            // Copy the initial file from the application bundle to the documents directory
            if let bundleURL = NSBundle.mainBundle().URLForResource("contact", withExtension: "db") {

                do {
                    try fileManager.copyItemAtURL(bundleURL, toURL: finalDatabaseURL)
                } catch _ {
                    print("Couldn't copy file to final location!")
                }

            } else {
                print("Couldn't find initial database in the bundle!")
            }
        }
    } else {
        print("Couldn't get documents directory!")
    }

    return nil
}

    func methodToInsertUpdateDeleteData(strQuery : String) -> Bool
    {

       // print("%@",String(methodToCreateDatabase()!.absoluteString))

        let contactDB = FMDatabase(path: String(methodToCreateDatabase()!.absoluteString) )

        if contactDB.open() {

            let insertSQL = strQuery

            let result = contactDB.executeUpdate(insertSQL,
                withArgumentsInArray: nil)

            if !result {
                print("Failed to add contact")
                print("Error: \(contactDB.lastErrorMessage())")
                return false
            } else {
                print("Contact Added")
                return true
            }
        } else {
            print("Error: \(contactDB.lastErrorMessage())")
            return false
        }

    }

    func methodToSelectData(strQuery : String) -> NSMutableArray
    {

        let arryToReturn : NSMutableArray = []

        print("%@",String(methodToCreateDatabase()!.absoluteString))

        let contactDB = FMDatabase(path: String(methodToCreateDatabase()!.absoluteString) )

        if contactDB.open() {
            let querySQL = strQuery

            let results:FMResultSet? = contactDB.executeQuery(querySQL,
                withArgumentsInArray: nil)

            while results?.next() == true
            {
                arryToReturn.addObject(results!.resultDictionary())
            }

            // NSLog("%@", arryToReturn)

            if arryToReturn.count == 0
            {
                print("Record Not Found")

            }
            else
            {
                print("Record Found")

            }


            contactDB.close()
        } else {
            print("Error: \(contactDB.lastErrorMessage())")
        }

        return arryToReturn

    }
}

Avoir un codage heureux.

1
Hasya

Pour copier un fichier .sqlite dans le répertoire ...

BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
// Database filename can have extension db/sqlite.
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *databasePath = [documentsDirectory stringByAppendingPathComponent:@"MapView.sqlite"];

success = [fileManager fileExistsAtPath:databasePath];
//    if (success){
//        return;
//    }
// The writable database does not exist, so copy the default to the appropriate location.
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"MapView.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:databasePath error:&error];
if (!success) {
    //NSAssert1(0, @"Failed to create writable database file with message '%@'.", [error localizedDescription]);
}
else
{
    NSLog(@"Database created successfully");
}

Pour sélectionner les données de la base de données ...

const char *dbpath = [databasePath UTF8String];
sqlite3_stmt    *statement;

if (sqlite3_open(dbpath, &mapDB) == SQLITE_OK)
{
    NSString *querySQL = [NSString stringWithFormat: @"SELECT * FROM maplatlong"];

    const char *query_stmt = [querySQL UTF8String];

    if (sqlite3_prepare_v2(mapDB, query_stmt, -1, &statement, NULL) == SQLITE_OK)
    {
        while(sqlite3_step(statement) == SQLITE_ROW)
        {
            NSString *cityN = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 0)];
            NSString *lat = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 1)];
            NSString *longi = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 2)];

            [cityName addObject:cityN];
            [latitude addObject:lat];
            [longitude addObject:longi];

        }
        sqlite3_finalize(statement);

                }
    sqlite3_close(mapDB);

}
0

Les méthodes suivantes vous aideront à gérer la base de données

Méthode de copie de la base de données dans le répertoire du document s'il n'existe pas

-(void)copyDatabase
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *insPath = [NSString stringWithFormat:@"Instamontage.sqlite"];
    destPath = [documentsDirectory stringByAppendingPathComponent:insPath];
    NSString *srcPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:insPath];
// NSLog(@"\n src %@ \n dest %@", srcPath, destPath);
   if (![[NSFileManager defaultManager] fileExistsAtPath:destPath])
   {
    NSError *error;
    NSLog(@"not exist");
    [[NSFileManager defaultManager] copyItemAtPath:srcPath toPath:destPath error:&error];
   }
   else
   {
      NSLog(@"exist");
   }
}

Méthode pour insérer/supprimer/mettre à jour un tableau

-(BOOL)dataManipulation: (NSString *)query
{
    BOOL result=NO;
   if (sqlite3_open([destPath UTF8String], &connectDatabase)==SQLITE_OK)
   {
      sqlite3_stmt *stmt;

      if (sqlite3_prepare_v2(connectDatabase, [query UTF8String], -1, &stmt, NULL)==SQLITE_OK)
    {
        sqlite3_step(stmt);
        result=YES;
    }
    sqlite3_finalize(stmt);
  }

  sqlite3_close(connectDatabase);
  return result;
}

Méthode d'obtention des lignes de la table

-(NSMutableArray *)getData: (NSString *)query
{
    NSMutableArray *arrData=[[NSMutableArray alloc]init];
    if (sqlite3_open([destPath UTF8String],&connectDatabase)==SQLITE_OK)
    {
        sqlite3_stmt *stmt;
        const char *query_stmt = [query UTF8String];

        if (sqlite3_prepare_v2(connectDatabase,query_stmt, -1, &stmt, NULL)==SQLITE_OK)
        {
            while (sqlite3_step(stmt)==SQLITE_ROW)
            {
                NSMutableDictionary *dictResult=[[NSMutableDictionary alloc] init];

                for (int i=0;i<sqlite3_column_count(stmt);i++)
                {
                    NSString *str;

                    if (sqlite3_column_text(stmt,i)!=NULL)
                    {
                        str = [NSString stringWithUTF8String:(char *)sqlite3_column_text(stmt,i)];
                    }
                    else
                    {
                        str=@"";
                    }
                    [dictResult setValue:str forKey:[NSString stringWithUTF8String:(char *)sqlite3_column_name(stmt,i)]];
                }
                [arrData addObject:dictResult];
            }
            sqlite3_finalize(stmt);
        }
        sqlite3_close(connectDatabase);
    }
    return arrData;
}

Les méthodes ci-dessus dans Swift seront écrites comme ci-dessous

Méthode de copie de la base de données dans le répertoire du document s'il n'existe pas

func copyDatabaseToDocumentDirectory() {
    let directoryList = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
    var documentDirectory = directoryList.first
    documentDirectory?.append("/DatabasePract1.sqlite")
    print(documentDirectory!)

    if !FileManager.default.fileExists(atPath: documentDirectory!) {
        let databaseBundlePath = Bundle.main.path(forResource: "DatabasePract1", ofType: "sqlite")
        do {
           try FileManager.default.copyItem(atPath: databaseBundlePath!, toPath: documentDirectory!)
            self.databasePath = documentDirectory
        } catch {
            print("Unable to copy database.")
        }
    } else {
        print("database exist")
        self.databasePath = documentDirectory
    }
}

Méthode pour insérer/supprimer/mettre à jour un tableau

func dataManipulation(query: String) -> Bool {
    var database: OpaquePointer?
    var result = false

    if (sqlite3_open(databasePath, &database) == SQLITE_OK) {
        var queryStatement: OpaquePointer?
        if (sqlite3_prepare_v2(database, query, -1, &queryStatement, nil) == SQLITE_OK) {
            sqlite3_step(queryStatement)
            result = true
        } else {
            let errmsg = String(cString: sqlite3_errmsg(database)!)
            print("error preparing insert: \(errmsg)")
        }
        sqlite3_finalize(queryStatement)
    }
    sqlite3_close(database)
    return result
}

Méthode d'obtention des lignes de la table

func fetchData(_ query: String) -> [[String:Any]] {
    var database: OpaquePointer?
    var arrData: [[String:Any]] = []

    if (sqlite3_open(databasePath, &database) == SQLITE_OK) {
        var stmt:OpaquePointer?
        if sqlite3_prepare(database, query, -1, &stmt, nil) != SQLITE_OK{
            let errmsg = String(cString: sqlite3_errmsg(database)!)
            print("error preparing insert: \(errmsg)")
            return arrData
        } 

        while(sqlite3_step(stmt) == SQLITE_ROW) {
            var dictData: [String: Any] = [:]
            for i in 0..<sqlite3_column_count(stmt) {
                var strValue = ""
                if (sqlite3_column_text(stmt, i) != nil) {
                    strValue = String(cString: sqlite3_column_text(stmt, i))
                }
                let keyName = String(cString: sqlite3_column_name(stmt, i), encoding: .utf8)
                dictData[keyName!] = strValue
            }
            arrData.append(dictData)
        }

        sqlite3_close(database)
    }
    return arrData
}
0
Indrajeet