サーバーデータベースを使用せずにユーザー情報をデバイスにローカルに保存するアプリを構築していますが、すべてデバイス側にあります。特定のユーザーの場所を保存してテーブルビューで表示することを考えているので、ユーザーが後でアプリを起動したときでも、履歴を取得して、履歴テーブルに過去の場所をフィードできます。基本的に、ローカルデータベースからの読み取り/書き込み機能。
さて、以前はそのような多くの質問があったことを知っていますが、外部データベースなしでローカルにデータを保存することに取り組む質問を見つけることができませんでした。たとえば、Core Dataを使用することがここで行うには最も簡単で正しいことかどうかはわかりません。
それについてのアドバイスをいただければ幸いです。
単純なデータの場合は、NSUserDefaultsを使用する必要があります。 CoreDataは非常に優れていますが、主にDB構造を格納するために使用され、複雑さをもたらします(しかし、私はそれが好きです:))。 StringやArrayなど(基本的に設定)を格納するだけの場合は、NSUserDefaultsを使用できます。
例えば:
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; //load NSUserDefaults
NSArray *fakeFavs = [[ NSArray alloc] initWithObjects:@"2",@"4", @"100", nil]; //declare array to be stored in NSUserDefaults
[prefs setObject:fakeFavs forKey:@"favourites"]; //set the prev Array for key value "favourites"
データを保存するには、基本的に2つのオプションがあります。
CoreDataはSQLiteを使用し、そのAPIは少し使いやすくなっています(データを読み書きするためにSQLを理解したり、多くの関数を作成したりする必要はありません)。
SQLite用のC APIを使用しているため、SQLite APIは依然として優れた選択肢です。これにより、古いiOSプラットフォームをターゲットにできるという利点があります。
どちらのオプションでも、データはクライアント側に保存され、ユーザーが電話をiTunesと同期するたびにバックアップされます。
いくつかの値を格納するだけで、検索ロジックが必要ない場合は、 NSUserDefaults を調べてください。
[NSUserDefaults standardUserDefaults]
配列、文字列、int、オブジェクト、およびNSStringキーによるアクセスを格納できる単なる辞書
内部的には単なるplistなので、xcodeで開いて現在の状態をすばやく確認できます
IPhoneにアプリケーションデータを保存する方法はいくつかあります。
より一般化されたソリューションには Realm の使用をお勧めします。
// Create Database file
- (void)createEditableCopyOfDatabaseIfNeeded
{
// First, test for existence.
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSLog(@"%@",documentsDirectory);
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:@"TestDB.sqlite"];
success = [fileManager fileExistsAtPath:writableDBPath];
if (success) return;
// The writable database does not exist, so copy the default to the appropriate location.
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"TestDB.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
NSAssert1(0, @"Failed to create writable database file with message '%@'.", [error localizedDescription]);
}
}
Select Query::::::
NSArray *array_hiback =[app.sk lookupAllForSQL:@"SELECT * FROM cycle_datagathering_begoodyourselef ORDER BY RANDOM() LIMIT 1"];
NSLog(@"%@",array_hiback);
insert Query:::::
NSMutableDictionary *dict=[[NSMutableDictionary alloc]init];
[dict setObject:@"0" forKey:@"isuploaded"];
[app.sk insertDictionary:dict forTable:@"mindeditor"];
[dict release];
update Query::::
NSMutableDictionary *updatedata=[[NSMutableDictionary alloc]init];
[updatedata setObject: [[NSUserDefaults standardUserDefaults] objectForKey:@"savecycleid"] forKey:@"cycleid"];
delete Query:::::
[app.sk deleteWhere:[NSString stringWithFormat:@"rowid=%@",str] forTable:@"mindeditor"];
[app.sk updateDictionary:updatedata forTable:@"mindeditor" where:[NSString stringWithFormat:@"rowid=%@", [[checkarray objectAtIndex:checkarray.count-1] objectForKey:@"cycleid"]]];
[updatedata release];
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
sk = [[SKDatabase alloc] init];
NSString *db = @"MindEditor.db";
[sk initWithDynamicFile:db];
userid=@"0";
}
SKDatabase.h
//
// SKDatabase.h
// Version 1.1
//
// Created by Shannon Appelcline on 9/11/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <sqlite3.h>
@protocol SKDatabaseDelegate <NSObject>
@optional
- (void)databaseTableWasUpdated:(NSString *)table;
@end
@interface SKDatabase : NSObject {
id<SKDatabaseDelegate> delegate;
sqlite3 *dbh;
BOOL dynamic;
}
@property (assign) id<SKDatabaseDelegate> delegate;
@property sqlite3 *dbh;
@property BOOL dynamic;
- (id)initWithFile:(NSString *)dbFile;
- (id)initWithDynamicFile:(NSString *)dbFile;
- (void)close;
- (sqlite3_stmt *)prepare:(NSString *)sql;
- (id)lookupColForSQL:(NSString *)sql;
- (NSDictionary *)lookupRowForSQL:(NSString *)sql;
- (NSArray *)lookupAllForSQL:(NSString *)sql;
- (int)lookupCountWhere:(NSString *)where forTable:(NSString *)table;
- (int)lookupMax:(NSString *)key Where:(NSString *)where forTable:(NSString *)table;
- (int)lookupSum:(NSString *)key Where:(NSString *)where forTable:(NSString *)table;
- (void)insertArray:(NSArray *)dbData forTable:(NSString *)table;
- (void)insertDictionary:(NSDictionary *)dbData forTable:(NSString *)table;
- (void)updateArray:(NSArray *)dbData forTable:(NSString *)table;
- (void)updateArray:(NSArray *)dbData forTable:(NSString *)table where:(NSString *)where;
- (void)updateDictionary:(NSDictionary *)dbData forTable:(NSString *)table;
- (void)updateDictionary:(NSDictionary *)dbData forTable:(NSString *)table where:(NSString *)where;
- (void)updateSQL:(NSString *)sql forTable:(NSString *)table;
- (void)deleteWhere:(NSString *)where forTable:(NSString *)table;
- (BOOL)runDynamicSQL:(NSString *)sql forTable:(NSString *)table;
@end
SKDatabase.m
//
// SKDatabase.m
// Version 1.1
//
// Created by Shannon Appelcline on 9/11/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "SKDatabase.h"
@implementation SKDatabase
@synthesize delegate;
@synthesize dbh;
@synthesize dynamic;
// Two ways to init: one if you're just SELECTing from a database, one if you're UPDATing
// and or INSERTing
- (id)initWithFile:(NSString *)dbFile {
if (self = [super init]) {
NSString *paths = [[NSBundle mainBundle] resourcePath];
NSString *path = [paths stringByAppendingPathComponent:dbFile];
int result = sqlite3_open([path UTF8String], &dbh);
NSAssert1(SQLITE_OK == result, NSLocalizedStringFromTable(@"Unable to open the sqlite database (%@).", @"Database", @""), [NSString stringWithUTF8String:sqlite3_errmsg(dbh)]);
self.dynamic = NO;
}
return self;
}
- (id)initWithDynamicFile:(NSString *)dbFile {
if (self = [super init]) {
NSArray *docPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [docPaths objectAtIndex:0];
NSString *docPath = [docDir stringByAppendingPathComponent:dbFile];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:docPath]) {
NSString *origPaths = [[NSBundle mainBundle] resourcePath];
NSString *origPath = [origPaths stringByAppendingPathComponent:dbFile];
NSError *error;
int success = [fileManager copyItemAtPath:origPath toPath:docPath error:&error];
NSAssert1(success,[NSString stringWithString:@"Failed to copy database into dynamic location"],error);
}
int result = sqlite3_open([docPath UTF8String], &dbh);
NSAssert1(SQLITE_OK == result, NSLocalizedStringFromTable(@"Unable to open the sqlite database (%@).", @"Database", @""), [NSString stringWithUTF8String:sqlite3_errmsg(dbh)]);
self.dynamic = YES;
}
return self;
}
// Users should never need to call prepare
- (sqlite3_stmt *)prepare:(NSString *)sql {
const char *utfsql = [sql UTF8String];
sqlite3_stmt *statement;
if (sqlite3_prepare([self dbh],utfsql,-1,&statement,NULL) == SQLITE_OK) {
return statement;
} else {
return 0;
}
}
// Three ways to lookup results: for a variable number of responses, for a full row
// of responses, or for a singular bit of data
- (NSArray *)lookupAllForSQL:(NSString *)sql {
sqlite3_stmt *statement;
id result;
NSMutableArray *thisArray = [NSMutableArray arrayWithCapacity:4];
if (statement = [self prepare:sql]) {
while (sqlite3_step(statement) == SQLITE_ROW) {
NSMutableDictionary *thisDict = [NSMutableDictionary dictionaryWithCapacity:4];
for (int i = 0 ; i < sqlite3_column_count(statement) ; i++)
{
if (sqlite3_column_decltype(statement,i) != NULL &&
strcasecmp(sqlite3_column_decltype(statement,i),"Boolean") == 0)
{
result = [NSNumber numberWithBool:(BOOL)sqlite3_column_int(statement,i)];
}
else if (sqlite3_column_type(statement, i) == SQLITE_TEXT)
{
result = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement,i)];
}
else if
(sqlite3_column_type(statement,i) == SQLITE_INTEGER)
{
result = [NSNumber numberWithInt:(int)sqlite3_column_int(statement,i)];
}
else if (sqlite3_column_type(statement,i) == SQLITE_FLOAT)
{
result = [NSNumber numberWithFloat:(float)sqlite3_column_double(statement,i)];
}
else
{
result = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement,i)];
}
if (result)
{
[thisDict setObject:result
forKey:[NSString stringWithUTF8String:sqlite3_column_name(statement,i)]];
}
}
[thisArray addObject:[NSDictionary dictionaryWithDictionary:thisDict]];
[thisArray retain];
}
}
sqlite3_finalize(statement);
return thisArray;
}
- (NSDictionary *)lookupRowForSQL:(NSString *)sql {
sqlite3_stmt *statement;
id result;
NSMutableDictionary *thisDict = [NSMutableDictionary dictionaryWithCapacity:4];
if (statement = [self prepare:sql])
{
if (sqlite3_step(statement) == SQLITE_ROW)
{
for (int i = 0 ; i < sqlite3_column_count(statement) ; i++)
{
if (strcasecmp(sqlite3_column_decltype(statement,i),"Boolean") == 0)
{
result = [NSNumber numberWithBool:(BOOL)sqlite3_column_int(statement,i)];
}
else if (sqlite3_column_type(statement, i) == SQLITE_TEXT)
{
result = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement,i)];
}
else if (sqlite3_column_type(statement,i) == SQLITE_INTEGER)
{
result = [NSNumber numberWithInt:(int)sqlite3_column_int(statement,i)];
}
else if (sqlite3_column_type(statement,i) == SQLITE_FLOAT)
{
result = [NSNumber numberWithFloat:(float)sqlite3_column_double(statement,i)];
}
else
{
result = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement,i)];
}
if (result)
{
[thisDict setObject:result
forKey:[NSString stringWithUTF8String:sqlite3_column_name(statement,i)]];
}
}
}
}
sqlite3_finalize(statement);
return thisDict;
}
- (id)lookupColForSQL:(NSString *)sql {
sqlite3_stmt *statement;
id result;
if (statement = [self prepare:sql]) {
if (sqlite3_step(statement) == SQLITE_ROW) {
if (strcasecmp(sqlite3_column_decltype(statement,0),"Boolean") == 0) {
result = [NSNumber numberWithBool:(BOOL)sqlite3_column_int(statement,0)];
} else if (sqlite3_column_type(statement, 0) == SQLITE_TEXT) {
result = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement,0)];
} else if (sqlite3_column_type(statement,0) == SQLITE_INTEGER) {
result = [NSNumber numberWithInt:(int)sqlite3_column_int(statement,0)];
} else if (sqlite3_column_type(statement,0) == SQLITE_FLOAT) {
result = [NSNumber numberWithDouble:(double)sqlite3_column_double(statement,0)];
} else {
result = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement,0)];
}
}
}
sqlite3_finalize(statement);
return result;
}
// Simple use of COUNTS, MAX, etc.
- (int)lookupCountWhere:(NSString *)where forTable:(NSString *)table {
int tableCount = 0;
NSString *sql = [NSString stringWithFormat:@"SELECT COUNT(*) FROM %@ WHERE %@",
table,where];
sqlite3_stmt *statement;
if (statement = [self prepare:sql]) {
if (sqlite3_step(statement) == SQLITE_ROW) {
tableCount = sqlite3_column_int(statement,0);
}
}
sqlite3_finalize(statement);
return tableCount;
}
- (int)lookupMax:(NSString *)key Where:(NSString *)where forTable:(NSString *)table {
int tableMax = 0;
NSString *sql = [NSString stringWithFormat:@"SELECT MAX(%@) FROM %@ WHERE %@",
key,table,where];
sqlite3_stmt *statement;
if (statement = [self prepare:sql]) {
if (sqlite3_step(statement) == SQLITE_ROW) {
tableMax = sqlite3_column_int(statement,0);
}
}
sqlite3_finalize(statement);
return tableMax;
}
- (int)lookupSum:(NSString *)key Where:(NSString *)where forTable:(NSString *)table {
int tableSum = 0;
NSString *sql = [NSString stringWithFormat:@"SELECT SUM(%@) FROM %@ WHERE %@",
key,table,where];
sqlite3_stmt *statement;
if (statement = [self prepare:sql]) {
if (sqlite3_step(statement) == SQLITE_ROW) {
tableSum = sqlite3_column_int(statement,0);
}
}
sqlite3_finalize(statement);
return tableSum;
}
// INSERTing and UPDATing
- (void)insertArray:(NSArray *)dbData forTable:(NSString *)table {
// NSMutableString *sql = [NSMutableString stringWithCapacity:16];
// [sql appendFormat:@"INSERT INTO %@ (",table];
//
//
// for (int i = 0 ; i < [dbData count] ; i++) {
// NSLog(@"%@",[[dbData objectAtIndex:i] objectForKey:@"mid"]);
// [sql appendFormat:@"%@",[[dbData objectAtIndex:i] objectForKey:@"key"]];
// if (i + 1 < [dbData count]) {
// [sql appendFormat:@", "];
// }
// }
// [sql appendFormat:@") VALUES("];
// for (int i = 0 ; i < [dbData count] ; i++) {
// if ([[[dbData objectAtIndex:i] objectForKey:@"value"] intValue]) {
// [sql appendFormat:@"%@",[[[dbData objectAtIndex:i] objectForKey:@"value"] intValue]];
// } else {
// [sql appendFormat:@"'%@'",[[dbData objectAtIndex:i] objectForKey:@"value"]];
// }
// if (i + 1 < [dbData count]) {
// [sql appendFormat:@", "];
// }
// }
// [sql appendFormat:@")"];
// [self runDynamicSQL:sql forTable:table];
for(int i=0;i<[dbData count];i++)
{
NSDictionary *dict=[dbData objectAtIndex:i];
NSMutableString *sql = [NSMutableString stringWithCapacity:16];
[sql appendFormat:@"INSERT INTO %@ (",table];
NSArray *dataKeys = [dict allKeys];
for (int i = 0 ; i < [dataKeys count] ; i++) {
[sql appendFormat:@"%@",[dataKeys objectAtIndex:i]];
if (i + 1 < [dataKeys count]) {
[sql appendFormat:@", "];
}
}
[sql appendFormat:@") VALUES("];
for (int i = 0 ; i < [dataKeys count] ; i++) {
if ([[dict objectForKey:[dataKeys objectAtIndex:i]] intValue]) {
[sql appendFormat:@"%@",[dict objectForKey:[dataKeys objectAtIndex:i]]];
} else {
[sql appendFormat:@"'%@'",[dict objectForKey:[dataKeys objectAtIndex:i]]];
}
if (i + 1 < [dict count]) {
[sql appendFormat:@", "];
}
}
[sql appendFormat:@")"];
[self runDynamicSQL:sql forTable:table];
}
}
- (void)insertDictionary:(NSDictionary *)dbData forTable:(NSString *)table {
NSMutableString *sql = [NSMutableString stringWithCapacity:16];
[sql appendFormat:@"INSERT INTO %@ (",table];
NSArray *dataKeys = [dbData allKeys];
for (int i = 0 ; i < [dataKeys count] ; i++) {
[sql appendFormat:@"%@",[dataKeys objectAtIndex:i]];
if (i + 1 < [dbData count]) {
[sql appendFormat:@", "];
}
}
[sql appendFormat:@") VALUES("];
for (int i = 0 ; i < [dataKeys count] ; i++) {
//if ([[dbData objectForKey:[dataKeys objectAtIndex:i]] intValue]) {
// [sql appendFormat:@"%@",[dbData objectForKey:[dataKeys objectAtIndex:i]]];
// } else {
[sql appendFormat:@"'%@'",[dbData objectForKey:[dataKeys objectAtIndex:i]]];
//}
if (i + 1 < [dbData count]) {
[sql appendFormat:@", "];
}
}
[sql appendFormat:@")"];
[self runDynamicSQL:sql forTable:table];
}
- (void)updateArray:(NSArray *)dbData forTable:(NSString *)table {
[self updateArray:dbData forTable:table where:NULL];
}
- (void)updateArray:(NSArray *)dbData forTable:(NSString *)table where:(NSString *)where {
NSMutableString *sql = [NSMutableString stringWithCapacity:16];
[sql appendFormat:@"UPDATE %@ SET ",table];
for (int i = 0 ; i < [dbData count] ; i++) {
if ([[[dbData objectAtIndex:i] objectForKey:@"value"] intValue]) {
[sql appendFormat:@"%@=%@",
[[dbData objectAtIndex:i] objectForKey:@"key"],
[[dbData objectAtIndex:i] objectForKey:@"value"]];
} else {
[sql appendFormat:@"%@='%@'",
[[dbData objectAtIndex:i] objectForKey:@"key"],
[[dbData objectAtIndex:i] objectForKey:@"value"]];
}
if (i + 1 < [dbData count]) {
[sql appendFormat:@", "];
}
}
if (where != NULL) {
[sql appendFormat:@" WHERE %@",where];
} else {
[sql appendFormat:@" WHERE 1",where];
}
[self runDynamicSQL:sql forTable:table];
}
- (void)updateDictionary:(NSDictionary *)dbData forTable:(NSString *)table {
[self updateDictionary:dbData forTable:table where:NULL];
}
- (void)updateDictionary:(NSDictionary *)dbData forTable:(NSString *)table where:(NSString *)where {
NSMutableString *sql = [NSMutableString stringWithCapacity:16];
[sql appendFormat:@"UPDATE %@ SET ",table];
NSArray *dataKeys = [dbData allKeys];
for (int i = 0 ; i < [dataKeys count] ; i++) {
if ([[dbData objectForKey:[dataKeys objectAtIndex:i]] intValue]) {
[sql appendFormat:@"%@=%@",
[dataKeys objectAtIndex:i],
[dbData objectForKey:[dataKeys objectAtIndex:i]]];
} else {
[sql appendFormat:@"%@='%@'",
[dataKeys objectAtIndex:i],
[dbData objectForKey:[dataKeys objectAtIndex:i]]];
}
if (i + 1 < [dbData count]) {
[sql appendFormat:@", "];
}
}
if (where != NULL) {
[sql appendFormat:@" WHERE %@",where];
}
[self runDynamicSQL:sql forTable:table];
}
- (void)updateSQL:(NSString *)sql forTable:(NSString *)table {
[self runDynamicSQL:sql forTable:table];
}
- (void)deleteWhere:(NSString *)where forTable:(NSString *)table {
NSString *sql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@",
table,where];
[self runDynamicSQL:sql forTable:table];
}
// INSERT/UPDATE/DELETE Subroutines
- (BOOL)runDynamicSQL:(NSString *)sql forTable:(NSString *)table {
int result;
//NSAssert1(self.dynamic == 1,[NSString stringWithString:@"Tried to use a dynamic function on a static database"],NULL);
sqlite3_stmt *statement;
if (statement = [self prepare:sql]) {
result = sqlite3_step(statement);
}
sqlite3_finalize(statement);
if (result) {
if (self.delegate != NULL && [self.delegate respondsToSelector:@selector(databaseTableWasUpdated:)]) {
[delegate databaseTableWasUpdated:table];
}
return YES;
} else {
return NO;
}
}
// requirements for closing things down
- (void)dealloc {
[self close];
[delegate release];
[super dealloc];
}
- (void)close {
if (dbh) {
sqlite3_close(dbh);
}
}
@end