Persistence(12)〜SQLite3への保存(6)

2011. 03. 09
旧版の本書のサンプルコードとiPhone OS 3.x版のサンプルコードとの差異を比較します。


●applicationWillResignActive:への修正

Persistence(9)〜SQLite3への保存(3)』でも説明しましたが、iPhone OS 3.x版はマルチタスク未対応であったため、ファイル書き込みのタイミングがapplicationWillTerminate:(アプリケーションの終了直前)となっており、そのままでは現在のiOS 4.x以降でファイルへの書き込みができないので、applicationWillResignActive:に修正する必要があります。
(修正箇所は上記ページで確認してください)


●iPhone OS 3.x版との差異

旧版の本書とiPhone OS 3.x版では、データを読み込みviewDidLoadに違いはなく、データを書き込むapplicationWillResignActive:の内容が異なります。

相違点は以下の通りです。

1)SQLステートメントupdateを、NSStringオブジェクトではなくcharオブジェクトで生成
2)INSERTステートメントで、VALUESキーワードでの値の設定をワイルドカード『?』で指定
3)sqlite3_exec()ではなくsqlite3_prepare_v2()sqlite3_step()sqlite3_finalize()を使用
4)sqlite3_bind_*()によるワイルドカード『?』へのバインド
5)sqlite3_free()によるエラーメッセージオブジェクトの解放の省略

iPhone OS 3.x版の修正を加えたapplicationWillResignActive:は以下のようになります。
(太字が追加・修正した部分)

- (void)applicationWillResignActive:(UIApplication *)application {
    sqlite3 *database;
    for (int i = 1; i <= 4; i++) {
        NSString *fieldName = [[NSString alloc] initWithFormat:@"field%d", i];
        UITextField *field = [self valueForKey:fieldName];
        [fieldName release];

        char *update = "INSERT OR REPLACE INTO FIELDS (ROW, FIELD_DATA) VALUES (?, ?);";
        char *errorMsg;
        sqlite3_stmt *stmt;
        if (sqlite3_prepare_v2(database, update, -1, &stmt, nil) == SQLITE_OK) {
            sqlite3_bind_int(stmt, 1, i);
            sqlite3_bind_text(stmt, 2, [field.text UTF8String], -1, NULL);
        }
        if (sqlite3_step(stmt) != SQLITE_DONE)
            NSAssert1(0, @"Error updating tables: %s", errorMsg);
        sqlite3_finalize(stmt);

    }
    sqlite3_close(database);
}

2033.jpg

1)INSERTステートメントの設定

NSStringオブジェクトとして生成していたINSERTステートメントを、charオブジェクトとして生成しています。

これは変数の指定にテキストフィールドのインスタンスやNSStringのメソッドを使用せず、ワイルドカード『?』を使っているため、Objective-Cで書く必要が無いからです。

2)VALUESキーワードのワイルドカード指定

4つのテキストフィールドの値はforループで設定するため、格納する値は各テキストフィールドを指す変数を指定する必要があります。

旧版の本書ではテキストフィールドのインスタンスのテキストを変換し、直接INSERTステートメントに指定するという、Objective-C言語で記述を行っていました。

iPhone OS 3.x版では変数指定の部分をワイルドカード『?』(バインド変数)とし、sqlite3_bind_*()ルーチンを使用することによってC言語での記述に改められています。

3)SQLステートメント実行部分の変更

sqlite3_exec()ではsqlite3_bind_*()ルーチンを記述できないので、SQLステートメントの実行部分をsqlite3_prepare_v2()sqlite3_step()sqlite3_finalize()による記述に変更しています。

4)準備ステートメントでのバインド変数の指定

sqlite3_prepare_v2()で準備ステートメントを生成する際に、バインド変数の組み込みを行います。

sqlite3_prepare_v2()の記述自体はsqlite3_exec()で行っていたものと大差なく、sqlite3のオブジェクトdatabaseに対し、C言語文字列で記述したINSERTステートメントupdateを指定しています。

準備ステートメントのコンパイルに成功したら、バインド変数を組み込みます。

1つ目のバインド変数は列ROWの整数値ですので、sqlite3_bind_int()でコンパイル済みステートメントstmtの1つ目にiを指定しています。

2つ目のバインド変数は列FIELD_DATAのテキスト値ですので、sqlite3_bind_text()でコンパイル済みステートメントstmtの2つ目に、テキストフィールドのテキスト値をUTF8StringメソッドでC文字列に変換して指定しています。

sqlite3_bind_text()の第4引数は第3引数で渡すテキスト値のバイト数で、-1を渡すことで自動指定することになります。

第5引数はSQLiteの処理が完了した後で文字列の処理に使用するデストラクタで、ここではNULLとしています。

5)sqlite3_free()の省略

iPhone OS 3.x版では、sqlite3_free()によるエラーメッセージオブジェクトの解放は省略されています。

6)SQLステートメントの実行

sqlite3_step()でバインド変数を組み込んだINSERTステートメントを実行し、正常に完了するとSQLITE_DONEが返されますので、そうでない場合はアサーションを生成します。

1つの行の処理が終わったらsqlite3_finalize()でステートメントを破棄し、次の行にループします。

4つの行の処理が終わったら、sqlite3_close()でデータベースファイルを閉じます。


●実行

applicationWillTerminate:をapplicationWillResignActive:に修正したiPhone OS 3.x版のサンプルコードではアサーションが発生しませんが、上記のサンプルコードを実行してアプリケーションを非アクティブにすると、デバッガコンソールに『Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error updating tables: 8”ˇøD6'』というテーブル更新時のアサーションが出力されます。

これはsqlite3オブジェクトdatabaseをヘッダファイルで宣言するかソースファイルで宣言するかの違いに起因します。

旧版およびiPhone OS 3.x版では、viewDidLoadでsqlite3_open()を使用して開いたsqlite3オブジェクトをメソッド内で閉じず、applicationWillResignActive:においてsqlite3_close()で閉じています。

ここでは両メソッドの冒頭でsqlite3オブジェクトをそれぞれ宣言しているので、applicationWillResignActive:は開いていないデータベースに対して処理を行う形となり、アサーションが出る結果になっています。

実際ソースファイルでの宣言を止めて、iPhone OS 3.x版のサンプルコードと同様にヘッダファイルで宣言する形に変更するとアサーションが発生せず、正常に書き込みができるようになります。



参考文献

IT用語辞典/バインド

はじめてのiPhone3プログラミングはじめてのiPhone3プログラミング
(2009/12/17)
Dave Mark、Jeff LaMarche 他

商品詳細を見る

Beginning Ios 6 Development: Exploring the Ios SdkBeginning Ios 6 Development: Exploring the Ios Sdk
(2012/12/26)
David Mark、Jack Nutting 他

商品詳細を見る






Bose QuietComfort 20
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
08 | 2017/09 | 10
Sun Mon Tue Wed Thu Fri Sat
- - - - - 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Recent Articles
iTunes


Swift
Categories
Tips
Profile

水月杏香

Author:水月杏香
永遠の初心者プログラマ。

Wish List
WACOM


ARC
Technical Q&A
情報プロパティリストキー
Start Developing iOS Apps Today
BOSE

Bose QuietComfort 20
Reference
NSApplicationDelegateプロトコル
NSArrayクラス
NSAutoreleasePoolクラス
NSBundleクラス
NSBundle UIKit追加分
NSCalendarクラス
NSCoderクラス
NSCodingプロトコル
NSCopyingプロトコル
NSDataクラス
NSDateクラス
NSDateFormatterクラス
NSDictionaryクラス
NSEntityDescriptionクラス
NSEnumeratorクラス
NSErrorクラス
NSExceptionクラス
NSFetchRequestクラス
NSFileHandleクラス
NSFileManagerクラス
NSIndexPathクラス
NSIndexPath UIKit追加分
NSKeyedArchiverクラス
NSKeyedUnarchiverクラス
NSKeyValueCodingプロトコル
NSLocaleクラス
NSManagedObjectクラス
NSManagedObjectContextクラス
NSManagedObjectModelクラス
NSMutableArrayクラス
NSMutableCopyingプロトコル
NSMutableDictionaryクラス
NSMutableSetクラス
NSNotificationクラス
NSNotificationCenterクラス
NSNullクラス
NSNumberクラス
NSObjectクラス
NSObject UIKit追加分
NSObjectプロトコル
NSPersistentStoreクラス
NSPersistentStoreCoordinatorクラス
NSPredicateクラス
NSPropertyListSerializationクラス
NSRunLoopクラス
NSSetクラス
NSStringクラス
NSString UIKit追加分
NSTimerクラス
NSTimeZoneクラス
NSURLクラス
NSURLProtectionSpaceクラス
NSURLRequestクラス
NSUserDefaultsクラス
NSValueクラス

UIActionSheetクラス
UIActionSheetDelegateプロトコル
UIActivityIndicatorViewクラス
UIAlertViewクラス
UIAlertViewDelegateプロトコル
UIApplicationクラス
UIApplicationDelegateプロトコル
UIBarButtonItemクラス
UIBarItemクラス
UIButtonクラス
UIColorクラス
UIControlクラス
UIDatePickerクラス
UIDeviceクラス
UIEventクラス
UIFontクラス
UIGestureRecognizerクラス
UIImageクラス
UIImageViewクラス
UIKit Function
UILabelクラス
UINavigationControllerクラス
UINavigationItemクラス
UIPickerViewクラス
UIPickerViewDataSourceプロトコル
UIPickerViewDelegateプロトコル
UIPinchGestureRecognizerクラス
UIResponderクラス
UIScreenクラス
UIScrollViewクラス
UISearchBarクラス
UISearchBarDelegateプロトコル
UISegmentedControlクラス
UISliderクラス
UISwipeGestureRecognizerクラス
UISwitchクラス
UITableViewクラス
UITableViewCellクラス
UITableViewControllerクラス
UITableViewDataSourceプロトコル
UITableViewDelegateプロトコル
UITapGestureRecognizerクラス
UITextFieldクラス
UITextFieldDelegateプロトコル
UITextInputTraitsプロトコル
UITextViewクラス
UITextViewDelegateプロトコル
UIToolbarクラス
UITouchクラス
UIViewクラス
UIViewControllerクラス
UIWebViewクラス
UIWebViewDelegateプロトコル
UIWindowクラス

AVAudioPlayerクラス
AVAudioPlayerDelegateプロトコル

CADisplayLinkクラス
CAEAGLLayerクラス
CALayerクラス

CGAffineTransform
CGBitmapContext
CGColor
CGColorSpace
CGContext
CGGeometry
CGImage
CGPath

EAGLContextクラス
EAGLDrawableプロトコル

Foundation Constants
Foundation Data Types
Foundation Functions

MPMediaItemクラス
MPMediaItemArtworkクラス
MPMediaPlaylistクラス
MPMediaPropertyPredicateクラス
MPMediaQueryクラス
MPMusicPlayerControllerクラス

Randomization Services

System Sound Services
Amazon


OpenGL ES
SQLite
Monthly Archives
Recent Comments
Recent TrackBacks
RSS Link
Visitors
QR Code
QR