iOSアプリを作ってみる(7) NSMutableArray 2行以上ないとだめなの?

今回の話題はちょっと細かいですが、結構ハマったのでメモしておきたいと思います。

1文字の単語だけエラーの怪

アプリの基本的な動きが出来て、実際にテストで動かしている時に変な状況に遭遇しました。漢字2文字以上の場合は問題ないにも関わらず、漢字1文字の単語になると必ず落ちるのです。

ログを見ると、このエラーを吐いています。

[__NSArrayI replaceObjectAtIndex:withObject:]: unrecognized selector sent to instance

実際のソースコードはこのあたり。

NSMutableArray *pinElements = [[NSMutableArray alloc] init];
pinElements = [origPinyin componentsSeparatedByString:@" "];
....(中略)....
 [pinElements replaceObjectAtIndex:i withObject:[[pinElements objectAtIndex:i] stringByReplacingOccurrencesOfString:foundStr withString:@""]];

origPinyinという文字列の中には、"ni3 hao3"というようにピンインが半角スペース区切りで入っています。それをcomponetsSeparatedByString:@" "で分割されてNSMutableArrayとして定義されているpinElementsに入れています。漢字1文字の単語の場合のピンインは、"shang1"というように半角スペースがないのでそのまま同じpinElementsの中に1エントリだけ追加されます。

ところが、1文字の場合だけエラーになってしまうんです。こんな感じでデバッガを見てもエントリの数が違うだけで全く違いが分かりません。

f:id:deutschina:20130910200233p:plain
f:id:deutschina:20130910200257p:plain

エントリがゼロならともかく、1件は入っているのだから片方だけエラーになるのは意味不明です。ただ想像ですが、エントリが1件だけの場合は、元のNSStringがそのまま渡されてしまい、それが唯一のエントリになるので、NSMutableArrayっぽく扱われないんだろうなというところでしょうか。

それなら無理矢理2個にするか

とは言え、前に進まなくてはなりません。そこで考えたのは1文字の単語の場合も無理矢理2エントリにしてしまう方法です。

    NSString *origPinBConv = [origPinyin stringByAppendingString:@" ."];
    NSMutableArray *pinElements = [[NSMutableArray alloc] init];
    pinElements = [origPinBConv componentsSeparatedByString:@" "];
	
    for (int i=0;i<= [pinElements count] - 2; i++) {
....

元々のピンイン情報に、" ."(スペース、ドット)というのを無理矢理付加します。すると1文字の単語の時も、pinElementsに分解するときは2エントリになります。しかし、エラー回避のためのダミーエントリに意味はないので、次のFor文で処理するときは最後の"."だけ入ったエントリを無視するように、iの閾値をpinElementsの件数-2(indexは0から始まるので)にして、最後のエントリは処理されません。

ということで、ようやくエラーの回避に成功しました。これによって、画面に表示されるピンインがアルファベット+数字という形式から、きちんと声調記号付きで表示されるようになりました。

f:id:deutschina:20130910202729p:plain

まだ、er化対応していないけど。。。それでも一歩前進です。