.31 2011

iPhoneとiPad向けのUniversalアプリにて「設定画面」の分岐方法

あっというまの8月
夏休みを満喫した学生さんは宿題や課題に追われていると邪念を送信していますUTOです。

前々回のエントリで設定画面に設定項目を追加する方法を書きましたが、
今回はそれに+アルファしてiPhoneとiPadで画面レイアウトを分けたい・設定項目に差をつけたいっという
ことを実現してみました。

スポンサーサイト



.19 2011

iPhoneアプリを「設定画面」にて設定するための手順

どうも、あつです。なついですね。
いいえ、UTOです。夏です。暑いです。


アプリ起動時にアプリに関する設定を読み込んで反映させるっという手段はよく使われると思います。

たとえばSkypeアプリの場合「自動ログイン」や「自動ロックしない」といったアプリの動作に関する項目があります。

歯車マークの「設定」を表示し、下の方にスクロールさせるとインストールしているアプリがいくつか列挙されていると思います。
ここに開発するアプリで項目を追加して、起動時に読み込んでみるっということを行いたいと思います。

結構Google先生でもこの部分をまとめた記事ってヒットしにくかったので事細かく書いてみることにします。
キーワードは「Settings.bundle」とか「Root.plist」とか「NSUserDefaults」になりますかね…

.19 2009

SQLite を使ってみる(6)

Tasaki です。

いよいよ SQLite 編も最終回となりました。
最後はデータの削除とアプリケーション終了時の後処理についてです。

ただ、4回目のエントリで既に個別のデータの消去については紹介済みですので、今回は全てのデータを消去する場合を考えます。
これはすごく単純でして、全てのデータの読み込みとデータの消去の方法が分かっていれば、簡単に思いつくでしょう。
実装例を以下に示します。このメソッドは、データベースへのポインタ database とデータベース内のデータから作成した Person オブジェクトの配列 dataArray を管理するクラスで定義することを想定しています。
// 全ての位置情報をテーブルから削除
- ( void ) deleteAllData {
static char *sqlString = "DELETE FROM person";
sqlite3_stmt *statement = NULL;
if( database != NULL ) {
  if( sqlite3_prepare_v2( database, sqlString, -1, &statement, NULL ) == SQLITE_OK ) {
   while( sqlite3_step( statement ) == SQLITE_ROW );
  }
  sqlite3_finalize( statement );
 }
}

上の例ではエラー処理を怠けてしまっていますが、削除できたデータと同じものだけをメモリに展開中の配列から抹消することが、望ましいのではないでしょうか。

次に後処理に関してですが、最低でも以下の処理は必要になります。
これも前述のクラスで定義しておくべきメソッドです。
- ( void ) closeDatabase {
if( database == NULL ) {
  return;
 }
if( sqlite3_close( database ) != SQLITE_OK ) {
  NSLog( @"Failed to close database with '%s'.", sqlite3_errmsg( database ));
 }
}

これで、開始から終了までに最低限必要となる機能をご紹介できました。
慣れるまではいろいろ面倒に感じますが、ある程度仕組みが分かってしまえば、応用はそう難しくないのではないでしょうか。

まあ、3.0 で追加された Core Data を使えば、もっと楽なのは間違いないでしょうけど。
Core Data についてのエントリもありますので、こちらからどうぞ。


.17 2009

SQLite を使ってみる(5)

Tasaki です。

このテーマもついに5回までやってきました。
前回まででデータベースの読み込み部分の実装はできあがっていますので、今回はデータの追加部分を考えます。

ここでは、メモリに展開中のデータ配列に新たなデータが追加されたとき、同時にデータベースへのコミットを行うことで対処することにします。

そこで、前回ご紹介した Person クラスに次のメソッドを追加します。
// Person オブジェクトの新規追加用メソッド
- ( id ) initWithID:( NSUInteger ) id name:( NSString *) name database:( sqlite3 *) db {
if( name == nil || db == NULL ) {
  return nil;
 }
if(( self = [ super init ]) != nil ) {
  database = db;

  static char *sqlString = "INSERT INTO person VALUES(?,?)";
  sqlite3_stmt *statement = NULL;
  if( sqlite3_prepare_v2( database, sqlString, -1, &statement, NULL ) == SQLITE_OK ) {
   int i = 1;
   sqlite3_bind_int( statement, i++, id );
   sqlite3_bind_text( statement, i++, [ name UTF8String ], -1, SQLITE_TRANSIENT );
   if( sqlite3_step( statement ) != SQLITE_ERROR ) {
    self.id = id;
    self.name = name;
    [ name retain ];
   } else {
    // データベースへの登録に失敗
    NSLog( @"Insertion Error : failed to step with '%s'.", sqlite3_errmsg( database ));
   }
   sqlite3_finalize( statement );
  } else {
   NSLog( @"Insertion Error : failed to prepare with '%s'.", sqlite3_errmsg( database ));
  }
 }
return self;
}

このメソッドの返り値が空でなければ、それをデータ配列へ追加することでメモリ上とディスク上のデータの整合性が保たれることになります。(注:上記のコードでは、データベースへの登録に失敗したケースなどでは不整合が生じますが、name が nil になっているので外部から判別可能です)
ただ、id は主キーなので、呼び出し側で一意な値を渡しておかなければなりません。

今回、SQL ステートメント内部で ? パラメータと bind 関数を使用して値を渡していますが、このときのインデックスは 1 から始まりますので注意しましょう。


さて、これで読み出しと書き込みについての解説は終わりました。次回は削除を採りあげる予定ですが、前回のエントリでほとんど解決しちゃってる気がします。



.16 2009

SQLite を使ってみる(4)

Tasaki です。

今回は、前回掲載したコード内に登場した Person クラスの実装を見ていくことにします。

まず、ヘッダファイルの記述ですが、エンティティの各属性に対応する変数とプロパティを宣言します。加えて、前回登場したイニシャライザとデータベースから削除するためのメソッドを定義します。

#import <UIKit/UIKit.h>
#import <sqlite3.h>

@interface Person : NSObject {
// エンティティの属性
NSUInteger id;
NSString *name;
// DB のポインタ
sqlite3 *database;
}
@property ( nonatomic, retain ) NSString *name;
@property ( nonatomic ) NSUInteger id;

- ( id ) initWithStatement:( sqlite3_stmt *) statement database:( sqlite3 *) db;
- ( void ) deleteFromDatabase;

@end


上記メソッドの実装部を以下に示します。

// ステートメントから初期化
- ( id ) initWithStatement:( sqlite3_stmt *) statement database:( sqlite3 *) db {
if(( self = [ super init ]) != nil ) {
  database = db;

  int i = 0;
  id = sqlite3_column_int( statement, i++ );
  name = [[[ NSString stringWithUTF8String: sqlite3_column_text( statement, i++ )] retain ];
 }
return self;
}

// データベースから該当項目を抹消
- ( void ) deleteFromDatabase {
if( database == NULL ) {
  return;
 }
// 該当項目の削除用 SQL 文を作成
NSString *deleteSQL = [ NSString stringWithFormat: @"DELETE FROM location WHERE id=%d", id ];
// SQL文のコンパイルと実行
sqlite3_stmt *statement = NULL;
if( sqlite3_prepare_v2( database, [ deleteSQL UTF8String ], -1, &statement, NULL ) != SQLITE_OK ) {
  NSLog( @"Failed to prepare statement with '%s'.", sqlite3_errmsg( database ));
 }
int wasSucceeded = sqlite3_step( statement );
sqlite3_finalize( statement );
if( wasSucceeded != SQLITE_DONE ) {
  NSLog( @"Failed to delete from database with '%s'.", sqlite3_errmsg( database ));
 }
}


とりあえず、どんなエンティティでもこの2つのメソッドは最低限必要になると思います。
アプリにデータ修正機能を付加する場合には、更新用のメソッドが別途必要になります。

前回のエントリと合わせてご覧になればお分かりだと思いますが、SQLite API を用いた処理の流れは、どのような場合でもほとんど変わりません。prepare→step→finalize とエラー対処が基本です。このため大した処理でなくとも、コード量がそれなりに大きくなってしまいます。
SQLite を使えば使うほど、Core Data の偉大さを思い知らされそうです。


 HOME 

ブログ内検索

関連リンク

製品情報

最新記事

カテゴリ

プロフィール

neoxneo



NEXT-SYSTEM iOS Developers Blog


  • UTO:
    カナダ版iPhone4Sは、マナーモードでシャッター音がならない…


  • Ehara:
    ...


  • Hayate:
    ...


  • Tasaki:
    Developer登録完了...したのはいいけど


  • Ueda:
    ...



リンク