【Swift】iPhone5でStringをIntにキャストする時の罠

投稿日:

グリーンランドってデンマークの領土って知ってました?意外ですよね〜。

最近なんやかんやでSwiftの勉強を始めています。
Xcodeのレールに乗っかると、簡単なアプリであればサクッと作れてしまうというお手軽感に感動を覚えて、もっと早くやっとけば良かったなぁぁ〜なんて少しだけ思ってる次第です。
※もちろん簡単なアプリの話で、その先に行くには色々とお勉強が必要です

Xcode7から、作成中のアプリを実機にもインストール出来る様になったのでチャレンジのしがいもあがったと思います。たとえ簡単なアプリでもやっぱり実機で動かせるとテンションが違いますしね。

で、自分はiPhone5を未だに使っているのですが勉強中に見事にハマった所があったのでメモに残しておきます。

iPhone5は32bit

何にハマったかというと以下の例の様に、StringをIntへキャストする際、Int型の範囲を超える値をキャストするとnilになってしまうというものです。

iPhone5だとnilになる (この書き方はSwift2)

override func viewDidLoad() {
  super.viewDidLoad()

  let hoge = Int(overflow())
  print(hoge) // iPhone5だとnilになる
}

func overflow() -> String {
  return "2147483648"
}

※Xcodeで適当にプロジェクト作ってiPhone5でビルドすると試せると思います

何故こうなるかというと、どうやらiPhone5までは32bitだからなんですって。
知っている人には当たり前の事だと思いますが、32bitと64bitでは以下の通り、扱える数値の範囲が違います。

Int型の範囲(符号あり)

  • 32bit
    • -2,147,483,648 ~ 2,147,483,647
  • 64bit
    • –9,223,372,036,854,775,808 ~ 9,223,372,036,854,775, 807

つまり、32bitのiPhone5でInt(厳密にはOptional型)にキャスト出来る値の範囲は以下の通りという事になります。

let hoge = Int("2147483647")
print(hoge) // Optional(2147483647)

let hoge = Int("-2147483648")
print(hoge) // Optional(-2147483648)

nilになってしまった理由が分かりましたね。

これで何に困ったのか

これで自分が何に困ったかというと、Twitterのタイムラインを取得するAPIを試していて、タイムラインの追加読み込みをしたいとなった時です。
タイムラインの追加読み込みをしたい時、max_idを計算※1してAPIに渡さなければいけないのですが、上に挙げた現象によりmax_idが計算できなくて詰んだわけです。
※1 Twitterで取得したタイムライン情報の最後の id_strから-1 する

UInt64を使う

じゃあどうするのかというと、答えは簡単でIntでキャストするのではなくてUInt64を使えばおkです(と簡単に書きましたが、今までほぼPHPしか書いた事しか無い自分にとってここまで辿り着くには人に聞いたり教えてもらったり紆余曲折があったのです)。

こんな感じです。

UInt64を使ってmax_idを取得する例

// Twitterからの"id_str"はこんな感じで取っている想定 by SwiftyJSON
// tweetId = json["id_str"].stringValue
let maxId = UInt64(tweetId)! - 1

下記の参考サイトにもありますが、Intは実行環境のワード長に依存しますのですよ。
なので、きちんと範囲を指定する必要があったというわけです。
参考:数値型 | Swift言語を学ぶ

idなので符号無し整数を扱うUIntで書きましたが、符号ありの場合、Int64を使えばいいと思います。

まとめ

  • StringをIntにキャストする際は実行環境(32bit or 64bit)に気をつける
  • Int32,Int64,UInt32,UInt64 を意識する
  • 特に大きいサービス(今回はTwitter)のAPIを使う時とか
  • むしろiPhone5を早く乗り換える

最後に

TwitterのAPIを使う時、引き渡すパラメータでidが必須となっているAPIがあります。
例えば、POST favorites/create | Twitter Developers (ふぁぼる奴) などです。
Twitterの各APIから返却されるJsonには、ほぼ必ず”id”と”id_str”が返ってきますのでこの値を使うわけです。(まず、タイムラインを取得して各ツイートにその情報を持たせるイメージです)
で、実を言うとまず一番最初に自分がハマったのが、このドキュメントで必須パラメータはidとある通り返却されたJsonの”id”を使ったら見事にnilで一向にふぁぼれない現象でした。ですが上記にある通り、周りの方や先人の知恵を借りて解決したわけです。

そもそも、なんで”id”と”id_str”って返ってくるの?紛らわしいし何なの?なんでグリーンランドって国じゃないの?って感じですが”id”は数値、”id_str”が文字列で返ってくるのを見ると理由が何となく分かる気がしますし、ググってみると、
Twitter IDs | Twitter Developersにある通り、idの整数を使うと精度を落とすからid_strを使ってね!よろ!とありますね。

投稿日:
カテゴリー: Swift

作成者: shimabox

Web系のプログラマをやっています。 なるべく楽しく生きていきたい。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください