Swift 2でiOS 9の特定の条件の通信でエラーになる。nilが帰ってくる時どうすればいいのか?

投稿者: Anonymous

下記のコードでエラーになります。

fatal error: unexpectedly found nil while unwrapping an Optional value

改善策を教えて頂けないでしょうか?

条件は

let API_KEY:String = "き"

の時だけです。
隠れてnilが帰ってきているようです。

多分、ここで落ちてます。

let myData:String = NSString(data:res, encoding: NSJapaneseEUCStringEncoding)! as string

よろしくお願いいたします。

ソースがかけていたので、少し修正いたしました。

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let API_KEY:String = "き"

        //URLエンコーディング(文字列エスケープ処理)
        let searchWord:String! = API_KEY.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)

        // 通信先のURLを生成.
        let myUrl:NSURL = NSURL(string:"http://www.social-ime.com/api/?string=(searchWord)")!

        // リクエストを生成.
        let myRequest:NSURLRequest  = NSURLRequest(URL: myUrl)

        // 送信処理を始める.
        let res:NSData = try! NSURLConnection.sendSynchronousRequest(myRequest, returningResponse: nil) as? NSData

        // 返ってきたデータを文字列に変換. 
        let myData:String = NSString(data:res, encoding: NSJapaneseEUCStringEncoding)! as String

        // 戻ってきた文字列の確認.
        print(myData)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

http://www.social-ime.com/api/?string=%E3%81%8D
このアドレスはエラーにならず。

関連項目。
https://ja.stackoverflow.com/questions/16426/nsurlrequestで日本語を使って-帰って来たデータを受け取るところでエラーになってしまうのはなぜか

解決

試しに文字コードをEUC-JPからSJISに変更し、NSDataからStringにする際のコードも同じようにEUC-JPからSJISにするとエラーにはなりませんでした。なるべく元のコードを変えずにやってみたのでお試し下さい。

    //URLエンコーディング(文字列エスケープ処理)
    let searchWord:String! = API_KEY.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)

    // 通信先のURLを生成.
    // let myUrl:NSURL = NSURL(string:"http://www.social-ime.com/api/?string=(searchWord)")!
    let myUrl:NSURL = NSURL(string:"http://www.social-ime.com/api/?string=(searchWord)&charset=SJIS")!

    // リクエストを生成.
    let myRequest:NSURLRequest = NSURLRequest(URL: myUrl)

    // 送信処理を始める.
    let res:NSData = try! NSURLConnection.sendSynchronousRequest(myRequest, returningResponse: nil) as NSData

    // 返ってきたデータを文字列に変換.
    // let myData:String = NSString(data:res, encoding: NSJapaneseEUCStringEncoding)! as String
    let myData:String = NSString(data:res, encoding: NSShiftJISStringEncoding)! as String

    // 戻ってきた文字列の確認.
    print(myData)

ちなみにSJIS指定で、レスポンスは次の通りです

期 帰 き 記 気 木 樹 器 機 黄 基 季 軌 生 危 喜 寄 希 揮 机 旗 汽 紀 規 貴 起 己 企 奇 岐 幾 忌 既 棋 棄 祈 輝 飢 騎 鬼 碁 姫 肌 葵 磯 窺 伎 嬉 毅 畿 稀 徽 亀 妓 祁 碕 其 鰭 箕 亟 倚 僖 冀 几 剞 匱 卉 咥 唏 喟 噐 圻 毀 竒 屓 嵜 弃 悸 愧 憙 掎 揆 旡 晞 暉 曁 朞 杞 枳 棊 榿 橲 櫃 欷 歸 麾 气 氣 沂 淇 煕 熈 熹 燬 畸 癸 皈 瞶 祺 禧 稘 簣 綺 羈 羇 羲 耆 虧 覊 覬 詭 諱 譏 豈 跂 跪 逵 餽 饋 饑 馗 騏 驥 麒 龜 熙 着 来 ? キ 今日 教徒 キ

この結果から推測ですが

  • このAPIはEUC-JPを指定してもEUC-JPの範囲外のコードの文字を返してきているのかも
    • もしくはiOSがEUC-JPの前半位をカバーできていないないのかも
  • ブラウザでアクセスした際に表示されるのはブラウザがレスポンスを無理にでも変換しているのかも

ただ、指定する文字コードをSJISに変えることは根本的対策ではなく、レスポンスされたデータがStringに変換できない場合は無視をする、というのがまずやるべき対応だとは思います。

以降は”nilが返ってきた場合にどうするのか”と言う話です。

見たところNSDataからStringに変換する部分について、提示されているコードでは「!でunwrapしasでキャスト」していますが、ここを「as?によるStringへのキャストとOptional Bindingを使う」のが良いのではないでしょうか?

具体的には次のようにif letとas?を使います。

    let API_KEY:String = "き"

    //URLエンコーディング(文字列エスケープ処理)
    let searchWord:String! = API_KEY.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)

    // 通信先のURLを生成.
    // let myUrl:NSURL = NSURL(string:"http://www.social-ime.com/api/?string=(searchWord)")!
    let myUrl:NSURL = NSURL(string:"http://www.social-ime.com/api/?string=(searchWord)&charset=SJIS")!

    // リクエストを生成.
    let myRequest:NSURLRequest = NSURLRequest(URL: myUrl)

    // 送信処理を始める.
    let res:NSData = try! NSURLConnection.sendSynchronousRequest(myRequest, returningResponse: nil) as NSData

    // 返ってきたデータを文字列に変換.
    // let myData:String = NSString(data:res, encoding: NSJapaneseEUCStringEncoding)! as String
    // let myData:String = NSString(data:res, encoding: NSShiftJISStringEncoding)! as String
    if let myData:String = NSString(data:res, encoding: NSShiftJISStringEncoding) as? String {
        // 文字コード指定で正しくStringへ変換できた時の処理
        print(myData)
    }
回答者: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *