16699


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

[code]

    fatal error: unexpectedly found nil while unwrapping an Optional value
    
[/code]

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

条件は

[code]

    let API_KEY:String = "き"
    
[/code]

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

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

[code]

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

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

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

[code]

    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.
        }
    }
    
[/code]

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

関連項目。  
[https://ja.stackoverflow.com/questions/16426/nsurlrequestで日本語を使って-
帰って来たデータを受け取るところでエラーになってしまうのはなぜか](https://ja.stackoverflow.com/questions/16426/nsurlrequest%E3%81%A7%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6-%E5%B8%B0%E3%81%A3%E3%81%A6%E6%9D%A5%E3%81%9F%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E5%8F%97%E3%81%91%E5%8F%96%E3%82%8B%E3%81%A8%E3%81%93%E3%82%8D%E3%81%A7%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%A6%E3%81%97%E3%81%BE%E3%81%86%E3%81%AE%E3%81%AF%E3%81%AA%E3%81%9C%E3%81%8B)


CC BY-SA 3.0
2015-09-16T00:20:33.777
16662
2015-10-16T16:16:34.323
2017-04-13T12:52:38.920
-1
10845
question
ios swift xcode
Swift 2でiOS 9の特定の条件の通信でエラーになる。nilが帰ってくる時どうすればいいのか？


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

[code]

        //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)
    
[/code]

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

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

この結果から推測ですが

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

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

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

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

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

[code]

        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)
        }
    
[/code]


CC BY-SA 3.0
2015-09-16T15:15:40.583
16699
2015-09-16T15:23:03.840
2015-09-16T15:23:03.840
7374
7374
16662
answer


`NSString`のAPIでは、EUC-JPおよびSJISについて、JIS第2水準までの漢字しか対応していないのが原因です。

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

この結果の中には、夔という第4水準漢字が含まれています。

これはブラウザでは正常に見ることができるのですが、`NSShiftJISStringEncoding`および`NSJapaneseEUCStringEncoding`のいずれにおいても、`NSString`にデコードおよびエンコードすることはできません。

UTF-8であれば扱うことができるのですが、Social IMEのAPIでは、

> ・charset  
>  出力の文字コードです。EUC-JPやSJISが指定できます。デフォルトはEUC-JPです。なお、入力文字列の文字コードは自動的に推定されます。
>
> [Social IME かな漢字変換API ver 0.02](http://www.social-ime.com/api.html)

とあるため、UTF-8で受け取ることができません。

以上を踏まえると、結果を受け取るには

  1. アプリ側でEUC-JPまたはSJISから、UTF-8へ文字コードの変換を行う
  2. 変換不可能な漢字が存在した場合、結果を無視する

という対策が必要になります。1.の方法が望ましいですが、それを実現するには例えば`iconv`を使う方法がありますが、

  * C言語のライブラリをSwiftで使う方法
  * APIが非常にわかりにくい`iconv`を使う方法
  * ポインタのポインタをSwiftで生成して渡す方法

も理解する必要があります。ですので、ここでは2.の例を記載します。

[code]

    let queryString = "キ"
    
    var result = [String]()
    
    if let searchWord = queryString.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet()),
        let url = NSURL(string:"http://www.social-ime.com/api/?string=\(searchWord)") {
            let request = NSURLRequest(URL: url);
    
            do {
                let data = try NSURLConnection.sendSynchronousRequest(request, returningResponse: nil)
                var word = [UInt8]()
                var byte = [UInt8](count: 1, repeatedValue: 0)
                let length = data.length / sizeof(UInt8);
    
                for var count = 0; count < length ; count+=sizeof(UInt8) {
                    data.getBytes(&byte, range: NSRange(location: count, length: sizeof(UInt8)))
                    if byte[0] == 0x09 {
                        if let wordString = String(bytes: word, encoding: NSJapaneseEUCStringEncoding) where word.count != 0 {
                            result.append(wordString)
                        }
                        word = [UInt8]()
                    } else {
                        word.append(byte[0])
                    }
                }
            } catch {
                fatalError()
            }
    }
    print(result)
    
[/code]

Social
IMEのAPIは変換結果をタブ文字（0x09）で分割して返すので、そのことを利用して変換可能な漢字だけを含む変換結果を`String`の配列に変換しています。


CC BY-SA 3.0
2015-09-19T11:17:34.400
16772
2015-09-19T11:25:44.467
2015-09-19T11:25:44.467
5337
5337
16662
answer