連載
» 2007年05月14日 09時03分 公開

第3回 plist(プロパティリスト)とFoundation【前編】Undocumented Mac OS X(4/4 ページ)

[白山貴之,ITmedia]
前のページへ 1|2|3|4       

plistとFoundation

 plistの各要素は、Foundationと呼ばれるCocoaのフレームワークに存在するクラスと強く結びついている。plistの要素に対応するクラスが存在する上、plistの内容を格納したNSStringという文字列クラスに対しpropertyListというたった1つのメソッドを送るだけでplistの内容がパースされ、それぞれのクラスを用いたオブジェクトが生成、メモリに展開される。

ファイルからの入力

 リスト4はその簡単なサンプルだ。NSStringクラスのインスタンスであるfilecontentには、filenameで指定されるファイルの内容がテキストとして丸ごと格納される(リスト4-1)。このfilecontentに対してpropertyListメッセージを送る(リスト4-2)と、その内容がパースされ、メモリ上に同等の構造をしたオブジェクト群がロードされる。

リスト4 リスト4 plistを読み込むサンプル(Cocoa版)。ポイントはpropertyListメソッド1つだ
注  Apple版GCCオリジナルのオプション。「-l」がリンクするライブラリを指定するように、「-framework」はリンクするフレームワークを指定する。なお、「-L」に対応するオプションは「-F」だ

 実行例2リスト4の実行結果で、ここではリスト2のplistを読み込ませている。NSLog()関数*の出力からplistで表現されたのと同等のオブジェクトが生成されているのが分かる(図1)


% ./plistread list2.plist
2005-10-10 18:39:49.454 plistread[1282] {
    "\U30ad\U30fc1" = "\U50241";
    "\U30ad\U30fc2" = (
        "\U914d\U5217\U30e1\U30f3\U30d0\U30fc1",
        "\U914d\U5217\U30e1\U30f3\U30d0\U30fc2",
        "\U914d\U5217\U30e1\U30f3\U30d0\U30fc3"
    );
}

実行例2 リスト4の実行結果(正しい場合)
図1 図1 plistの各属性や構造はそのままメモリ上のオブジェクトに展開される

実行に失敗した場合の対処

 propertyListメソッドの実行に失敗した場合、例外が発生する(実行例3)。Objective-Cにおいて例外をとらえるには、NS_DURINGからNS_HANDLERで囲っておくと良い(リスト4-3)。例外発生時はNS_HANDLERからNS_ENDHANDLERまでの内容が実行される。また、例外の内容を示すオブジェクトはNS_HANDLERからNS_ENDHANLDERまでの間で有効な変数localExceptionに格納されている。このlocalExceptionの内容を確認することで、どこでパースエラーが起こっているのかが分かる*


% ./plistread list2_wrong.plist
2005-10-10 19:33:30.682 plistread[1745] in thread <NSThread: 0x502e60>\
{num = 1, threadDictionary = (null)},exception caused.
  name: <NSParseErrorException>
  reason: <XML parser error:
        Close tag on line 18 does not match open tag dict
Old-style plist parser error:
        Malformed data byte group at line 1; invalid hex
>
  userInfo: <(null)>

実行例3 リスト4の実行結果(間違っている場合)。propertyListメソッドはplistのパースに失敗すると例外を発生させる。この例外を捉えることでplistのどこが文法ミスなのかを知ることができる

ファイルへの出力

 ファイルへの出力を行うには、NSArrayもしくはNSDictionaryに対して「writeToFile:atomically:」メッセージを送ると良い。リスト5はそのサンプルだ。

リスト5 リスト5  plistを書き出すサンプル(Cocoa版)。これもポイントは「writeToFile:atomically:」ただ1つだ

 リスト5の「@""」はソースコード中に埋めることのできるNSStringのリテラル*である。NSDictionaryは、生成時の構造からその内容を変更できないのに対し、そのサブクラスであるNSMutableDictionaryはその内容を変更可能という違いがある。ここでは、空のNSMutableDictionaryクラスのインスタンスを生成し、そこに順番にオブジェクトを格納していった後ファイル名を第1引数、真偽値のYES*を第2引数に「writeToFile:atomically:」メッセージを送付している。リスト6がその結果だ。

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"

"http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<plist version="1.0">

<dict>

    <key>Key1</key>

    <string>Value1</string>

    <key>Key2</key>

    <dict>

        <key>SubKey1</key>

        <string>Value2</string>

    </dict>

    <key>Key3</key>

    <array>

        <string>Member1</string>

        <string>Member2</string>

        <string>Member3</string>

    </array>

</dict>

</plist>


リスト6 リスト5を実行すると、このようなplistが生成される

 このように、読み出しおよび書き込みに関しては簡単に処理される。Cocoaでは、データの格納、操作のために利用するNSStringやNSDictionaryといったオブジェクトは日常的に使われているため、わずか1つのメッセージを送るだけでファイルに保存し、オブジェクトを手軽に永続化できるのだ。

次回は

 Foundationと同様に基本的なデータ構造を扱うフレームワークである「CoreFoundation」の紹介を交えつつ、「Mac OS Xの『魂』」であるFoundationとplistの理解を深めていきたい。

このページで出てきた専門用語

NSLog()関数

NSLog()関数は、標準エラー出力に対して、第1引数で指定された書式で文字列を出力する手軽なデバッグ用の関数であり、「%@」という書式でObjective-Cのあらゆるオブジェクトを文字列に変換、出力を行う。なお、このとき出力先での文字化けを防ぐため、ASCII外の文字に関しては「\Uユニコード値」にエンコードされる。

パースエラーが起こっているのかが分かる

読み込むだけなら、NSDictionaryの「dictionaryWithContentsOfFile:」、ないしはNSArrayクラスの「arrayWithContentsOfFile:」メソッドを使えば1行で可能だが、これらはplistの文法が間違っていたとき単純にnilを返すだけで、エラーチェックが難しいという弱点がある。

NSStringのリテラル

GCCに含まれるObjective-Cコンパイラは「@""」からなる文字列をNSStringクラスのサブクラスである静的文字列クラスに展開する。この静的文字列クラスは、NeXTおよびGNUstepの古いバージョンではNXConstantStringクラスで、Mac OS XではNSConstantStringクラスになる。なお、「@""」の中にはASCII内の文字しか含めることができない。

YES

歴史的な事情から、YESは単に1の、NOは0に対するマクロであり、C++のtrue、falseのような真偽値ではない。


本記事は、オープンソースマガジン2006年1月号「Undocumented Mac OS X」を再構成したものです。


前のページへ 1|2|3|4       

Copyright © ITmedia, Inc. All Rights Reserved.

注目のテーマ