

Google Custom Search Engineを用いてGoogle画像検索の結果の画像URLを配列に格納したいのです。

手元の本の「JSONデータを受信する」という項目を確認した所、以下のコードが乗っていました。

[code]

    @IBAction func clickButton(sender: AnyObject){
    let url = NSURL(string: "http://moonmile.net/ios9/persons.json")
    let req = NSURLRequest(URL: url!)
    let task = NSURLSession.sharedSession().dataTaskWithRequest(req,completionHandler:{
        (data,res,err) in
        if data != nil{
            dispatch_async(dispatch_get_main_queue(),{
                do{
                    let jeson = try NSJSONSerialization.JSONObjectWithData(data!,options: NSJSONReadingOptions.MutableContaioners)
    
                    //最初の要素を表示する
                    let item = (json as! NSArray)[0]
                    let name = item["name"] as! String
                    let age = item["age"] as! Int
                    let addr = item["address"] as! String
                    self.text1.text = "\(name)\n\(age)\n\(addr)\n"
                }catch{
                    self.text1.text = "parse error"
                }
            })
        }else {
            dispatch_async(dispatch_get_main_queue(),{
                self.text1.text = "error"
            })
        }
    })
    task.resume()
    
[/code]

}

ですが、Swift2対応の本だったようでうまく動きません。

リクエストURLは  
[https://www.googleapis.com/customsearch/v1?key=?????&cx=????&searchType=image&q=](https://www.googleapis.com/customsearch/v1?key=?????&cx=????&searchType=image&q=)"検索語"

のような形で、  
帰ってくるJSONデータのitem配列の中の"link"に欲しい画像のURLがあることまでは分かっているのですが、Swift3で動くものを作れなくて行き詰まっています。

iOSでGoogle画像検索の結果画像を使用した経験がおありの方がいらっしゃいましたらよろしくお願いします。

初心者ですが、アドバイスをよろしくお願いいたします。

追記

[code]

    @IBAction func clickButton(sender: AnyObject){
    let url = URL(string: "http://moonmile.net/ios9/persons.json")
    let req = URLRequest(url: url!)
    let task = URLSession.shared.dataTask(with: req,completionHandler:{
        (data,res,err) in
        if data != nil{
            DispatchQueue.main.asynchrononusly(execute:){
                do{
                    let jeson = try NSJSONSerialization.JSONObjectWithData(data!,options: NSJSONReadingOptions.MutableContaioners)
    
                    //最初の要素を表示する
                    let item = (json as! NSArray)[0]
                    let name = item["name"] as! String
                    let age = item["age"] as! Int
                    let addr = item["address"] as! String
                    self.text1.text = "\(name)\n\(age)\n\(addr)\n"
                }catch{
                    self.text1.text = "parse error"
                }
            })
        }else {
            DispatchQueue.main.asynchronously(execute:){
                self.text1.text = "error"
            })
        }
    })
    task.resume()
    
[/code]

}

とりあえずXcodeに言われるまま修正してみましたがValue of Type DispatchQueue has no member
asynchronously(execute:)で詰みました。  
正直何をやっているのかさっぱり分かりません。  
Apple公式ドキュメントのクラスの説明全部読まないといけないんでしょうか


CC BY-SA 3.0
2016-12-14T02:41:16.133
31137
2016-12-14T05:48:31.737
2016-12-14T04:33:13.820
19910
19910
question
ios swift3 google-api
iOSアプリでGoogle画像検索を利用する


グレーゾーンな話はさておき :)

let data = str.data(using: .utf8)  
let json = try JSONSerialization.jsonObject(with: data!, options:
.mutableContainers ) as! [String: Any]  
let name = json["Name"] as! String

な感じで、JSONSerialization#jsonObject を使います。


CC BY-SA 3.0
2016-12-14T03:46:39.807
31139
2016-12-14T03:46:39.807
19912
31137
answer


最初にこちらのご質問について。

_Apple公式ドキュメントのクラスの説明全部読まないといけないんでしょうか_

あなたがこの程度のSwift 2のコードをSwift 3に自力で変換できる程度のプログラマーになりたいのであれば、 **詰まったところに関しては**
公式ドキュメントを直接参照されるくせをつけた方が良いでしょう。一生コピペヤーで良いならまぁ…いろんな生き方があります。

* * *

と言う訳で、こちらから

[code]

        DispatchQueue.main.asynchrononusly(execute:){
    
[/code]

> value of type 'DispatchQueue' has no member 'asynchronously(execute:)'  
>  `DispatchQueue`型の値は`asynchronously(execute:)`ってメンバーは持ってない!

と言うエラーですから、「いやそんなはずはない、持ってるか代わりがあるはずだ」という視点で公式リファレンスを覗いてやることになります。

[DispatchQueue](https://developer.apple.com/reference/dispatch/dispatchqueue)

> …
>
> ### Type Properties
[code]

>     class var main: DispatchQueue
>  
[/code]

>
> ### Instance Methods
[code]

>     func getSpecific<T>(key: DispatchSpecificKey<T>)
>     func setSpecific<T>(key: DispatchSpecificKey<T>, value: T)
>     func sync(execute: () -> Void)
>     func async(execute: DispatchWorkItem)
>  
[/code]

>
> …

と言うわけで、上記のリンク先ページ内を隅から隅まで探しても、`asynchronously(execute:)`なんてメソッドは見当たりませんが、代わりに`async(execute:)`ってのがあります。(メソッド名を参照する場合は、パラメータラベルは含むがパラメータの型名は省略するというのがSwift流です。)

今の所、どうせリンク先をたどっても大したことは書いてくれていませんので、ある程度は勘を働かせないといけないのですが、その前提として **Swift
3では既存APIのクラス名やメソッド名が大幅に付け替えられた** と言うことを知っておいた方が良いでしょう。(あちこちのSwift
3の解説記事にも書いてありますし、Xcode 8のRelease Notesにも書いてあります。)

※実際には`asynchronously`のメソッド名はSwift
3がβ版の頃のメソッド名候補で、正式版になる前に変更されたのですが、いまだにそんなものを候補に出してくるというのはバグと言って良いと思います。お時間があれば[Report
Bugs](http://developer.apple.com/bug-
reporting/)でバグ報告を出してください。(すでに多数のバグ報告が出ていそうに思うのに、8.2でもいまだに解消されていないわけですが…。)

と言うわけで先の行は、

[code]

        DispatchQueue.main.async(execute:){
    
[/code]

に書き換えれば、コンパイルは通るのですが、`async`メソッドの中でクロージャーを1つ取るメソッドは他にないので、`(execute:)`は書かなくても構いません。(その書き方で`(execute:)`をつける方が珍しいです。)

[code]

        DispatchQueue.main.async {
    
[/code]

2カ所とも同じ修正をすることになります。

※閉じ丸カッコ(`)`)が要らなくなるので`})`あたりにエラーが出ると思いますが、`}`にするだけです。

* * *

上記のエラーを修正すると五月雨式に他のエラーが表示されます。

[code]

    let jeson = try NSJSONSerialization.JSONObjectWithData(data!,options: NSJSONReadingOptions.MutableContaioners)
    
[/code]

> 'NSJSONSerialization' has been renamed to 'JSONSerialization'

今度ははっきり「リネームされた」と書いてあるので、リファレンスを見るまでもありません。素直に従いましょう。Xcodeのサジェスチョンも利用するとこんな風になります。ついでに明らかな綴りミスは修正しておいてください。`.MutableContaioners`
-> `.MutableContainers`

[code]

    let jeson = try JSONSerialization.jsonObject(with: data!,options: JSONSerialization.ReadingOptions.mutableContainers)
    
[/code]

Swiftではenum型の値を使うとき、文脈によっては型名を省略できるのですが、それ以前に`mutableContainers`なんてオプションを指定する必要はないことに気がついてください。mutableは書き換え可能ということを表していますが、このコードは中身を参照するだけで一切書き換えていません…。従って`options:`自体の指定が不要ということになります。(よく見ると`jeson`も`json`の書き間違いですね。)

[code]

    let json = try JSONSerialization.jsonObject(with: data!)
    
[/code]

* * *

上記を修正してもまだ次のエラーが控えているようです。そこら辺を全部↑のような調子で説明されては、かえって読む気が失せそうなので(少なくとも自分なら途中で投げ出します…)、やや簡略化してソースコード中のコメントだけで、オススメの書き方への修正と合わせてメソッド全部を掲載しておきます。

[code]

    @IBAction func clickButton(sender: AnyObject){
        let url = URL(string: "http://moonmile.net/ios9/persons.json")!
        let req = URLRequest(url: url)
        let task = URLSession.shared.dataTask(with: req) {//<-ここもトレーリングクロージャーの構文が使える
            (data,res,err) in
            if let data = data {//<-`data`は後で使うのでオプショナルバインディングを使う
                DispatchQueue.main.async {
                    do {
                        //後で「Dictionaryの配列」として使うので、ここの時点でキャストしておく
                        //予想外のデータが来たときにアプリがクラッシュしないよう、ここもオプショナルバインディング
                        if
                            let json = try JSONSerialization.jsonObject(with: data) as? [[String: Any]],
                        
                            //最初の要素を表示する
                            !json.isEmpty, //空だと「最初の要素」がなくてクラッシュするのでそのチェック
                            case let item = json[0], //オプショナルじゃないときのバインディングの書き方
                            let name = item["name"] as? String, //"name"の値もチェックしてから使う、以下同様
                            let age = item["age"] as? Int,
                            let addr = item["address"] as? String
                        {
                            self.text1.text = "\(name)\n\(age)\n\(addr)\n"
                        } else {
                            self.text1.text = "bad json"
                        }
                    } catch {
                        self.text1.text = "parse error"
                    }
                }
            } else {
                DispatchQueue.main.async {
                    self.text1.text = "error"
                }
            }
        }//<-トレーリングクロージャーにしたので丸カッコは削っている
        task.resume()
    }
    
[/code]

(危険な強制アンラップの`!`や強制キャストの`as!`はほとんど使っていない点に注意してください。)

とりあえずこんな風になります。実際には細かいところを修正しないといけないでしょう。特にGoogle Custom SearchのAPIを使うのであれば、

  * パラメータ付きのURLの作り方
  * 返ってくるJSONを読み込んだ結果は「Dictionaryの配列」(`[[String: Any]]`)にはならないはず

などの点で修正が必要になるかと思われます。少し込み入った話になりそうなときには、別の質問スレを立ててもらった方が良いかもしれません。


CC BY-SA 3.0
2016-12-14T05:48:31.737
31143
2016-12-14T05:48:31.737
2020-06-17T08:14:45.997
-1
13972
31137
answer