Evernote SDK for iOS 1.3.1 を組み込んだら警告いっぱい出てきた
Evernote SDK for iOS を組み込んだら、なんか警告がいっぱい出てきました。
大半がEDAMNoteStore で発生しているみたいです。
内容を見ると「変数の型が合わんよ」って言われてる
この記事のタイトルにもある様に、以下の警告が大半でした。
Implicit conversion loses integer precision: 'NSUInteger' (aka 'unsigned long') to 'int'
ざっくり言うと「NSUInteger の値をint に放り込むとデータの一部が失われるかもよ」ということです。
NSUInteger は符号なし32bit 整数型で、格納できる値は0〜4,294,967,295 です。
対して、int 型は符号あり32bit 整数型で、格納できる値は-2,147,483,648~2,147,483,647 です。
どちらも32bit の整数型ですが、符号あり(マイナス値扱える)と符号なし(マイナス値扱えない)で、格納できる値に違いがあります。
今回の場合、NSUInteger の値が2,147,483,647 を超えた場合、格納先であるint 型に格納できず不具合を生じさせてしまう可能性があるわけです。
格納しようとしているコードはどんなの?
問題のコードを見てみましょう。
Xcode画面右上ちょい左寄りあたりに、黄色い三角形の警告マークが出ています。
これをクリックすれば、あがっている警告がずーらずらと出てきますので、その中の一番上をクリックしてみましょう。
こんな感じのコードが書かれていました。
int len = [escapeChars count];
この場合、int 型の変数len にescapeChars 内のオブジェクト数count を格納させたいわけですが、escapeChars は何かと調べてみるとNSArray 型のオブジェクトでした。
NSArray のcount プロパティはNSUInteger 型です。
つまり、そのままint len に格納すると、値がオーバーフローしてしまう可能性があるわけです。
とりあえずint 型にキャストしてやれば警告は消える
int 型にNSUInteger 型を格納しようとするから警告を出されるわけで。
格納時に「これはint 型ですよー」と指定してしまえば、警告は出してきません。
(それが妥当か否かは別として)
具体的にはこうです。
// int len = [escapeChars count]; int len = (int)[escapeChars count];
格納する[escapeChars count] に(int)を付けて、int 型に型変換(キャスト)してやるわけです。
これで警告が1つ消えました。
キャストするのは、型変換しても大丈夫か確認してから
型変換といっても、何ら安全確認しているわけではありません。
単にint len に値を格納する前に、強制的にint 型に変換しているだけです。
ですから、その段階で[escapeChars count]の値がint 型に収まり切らない値であった場合、結局オーバーフローは発生してしまいます。
なので、その変数を本当に型変換して大丈夫か、よく確認してから型変換を行いましょう。
型変換して大丈夫か否かは、その変数にどれぐらいの値が入る可能性があるかによります。
なので、こればかりは自分で調べて確認するしかありません。
地味にコードを追いかけましょう。
例えば、前述の例の場合、int len に格納される[escapeChars count]が何者か?というのがポイントになります。
escapeChars という名のNSArray が何かについて調べてみると、URLエンコードに用いられるエスケープシーケンスに該当する文字を格納している箱でした。
コロンとかセミコロンとかスラッシュとかのあれです。
URLのエスケープシーケンス文字はせいぜい20種類ほどです。
となると、その数が4,294,967,295に到達することはあり得ません。
ですから、安心してint 型にキャストしてしまえるというわけです。
(他に、ノート数なんかも10万件の天井がありますから、NSUInteger からint にキャストしても、何の問題もありませんね。)
ほんまにこれでええんかな?
そんな感じで、警告が出ている値格納について、1つずつ潰して行った結果、警告はゼロになりました。
ただ「ほんまにこれでええんかな?」という心配が消えません。
もし「それちゃうで」とか「そんなんせんでも、こうしたらええんちゃうのん?」とかありましたら、ご教示いただけると、大変嬉しいです。
“とりあえずint 型にキャストしてやれば警告は消える”とのことですが、基本的に大きな数字を扱うのではなければ問題ないかとおもいます。
ただ、NSIntegerを使うと、32bit環境だと4b、64bit環境だと8bという感じで自動的に大きさをあわせてくれるようですので、こちらのほうがつかいやすいかもしれません。
なお、人からの受け売りですので、間違えていればすみませんm(__)m
ToraDady コメントありがとうございます。<(_ _)>
言われてみれば「intに収まらねー場合があるよ」って言われているだけですから、int でのキャストに拘る必要はないですね。