APIを使った画像検索システム

受付中

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 588

mountainbook

score 9

swift初心者です。
xcodeで、画像検索APIを使った簡単な画像検索アプリを作っています。
textfield(変数名: text )に何らかの語を書き、サーチをかけるとそれに関する画像が
imageview (変数名: pic )に表示するといった内容になっています。

エラーが出ていないにも関わらず、ボタンを押してもimageviewに画像が表示されません。
なぜ表示されないんでしょうか?

ちなみに、ATSを無効にするため、 "Info.plist" に "App Transport Security Setting" の項目を追加し、 "Allow Arbitrary Loads" を YES にしてあり、APIは取得済みです。

曖昧な質問の仕方で申し訳ありませんがお力添え頂けましたら幸いです。
よろしくお願いします。

Xcode Version 9.2 を使用

下にコード、実際の写真を示します。

import UIKit

class ViewController: UIViewController {

    @IBAction func rightswipe(_ sender: Any) {
        if(imageSub != 0){
            imageSub = imageSub-1
        }
        if let url = URL(string: wordImageArray[imageSub]) {
            let req = URLRequest(url: url)
            let task = URLSession.shared.dataTask(with: req, completionHandler: {data, response, error in
                if let data = data {
                    if let anImage = UIImage(data: data) {
                        DispatchQueue.main.async {
                            self.pic.image = anImage
                        }
                    }
                }
            })
            task.resume()
        }

    }

    @IBAction func leftswipe(_ sender: Any) {
        //imageSubを1つすすめる
        imageSub = imageSub+1

        //画像配列の末尾に到達している場合、配列に新たな10件を登録する
        if((imageSub) == wordImageArray.count){

            //パラメータのstartを決める
            let startPara: String = String(imageSub)

            //検索ワード
            let pasteboard = UIPasteboard.general
            let copiedText = pasteboard.string

            // パラメータを指定する
            let parameter = ["key": apikey,"cx":cx,"searchType":searchType,"q":copiedText,"start":startPara]

            // パラメータをエンコードしたURLを作成する
            let requestUrl = createRequestUrl(parameter: parameter as! [String : String])

            // APIをリクエストする
            request(requestUrl: requestUrl) { result in
                if let url = URL(string: self.wordImageArray[self.imageSub+1]) {
                    let req = URLRequest(url: url)
                    let task = URLSession.shared.dataTask(with: req, completionHandler: {data, response, error in
                        if let data = data {
                            if let anImage = UIImage(data: data) {
                                DispatchQueue.main.async {
                                    self.pic.image = anImage
                                }
                            }
                        }
                    })
                    task.resume()
                }
            }
        }else{
            if let url = URL(string: wordImageArray[imageSub]) {
                let req = URLRequest(url: url)
                let task = URLSession.shared.dataTask(with: req, completionHandler: {data, response, error in
                    if let data = data {
                        if let anImage = UIImage(data: data) {
                            DispatchQueue.main.async {
                                self.pic.image = anImage
                            }
                        }
                    }
                })
                task.resume()
            }
        }

    }

    @IBOutlet weak var pic: UIImageView!

    @IBOutlet weak var text: UITextField!

    // APIを利用するためのアプリケーションID(APIキー)
    let apikey: String = "(APIキー)"

    //APIを利用するためのサーチエンジンキー(検索エンジンキー)
    let cx: String = "(検索エンジンキー)"

    //利用するAPIのサーチタイプ
    let searchType: String = "image"

    // APIのURL
    let entryUrl: String = "(APIのURL)"

    //関連画像URLを格納する配列
    var wordImageArray: [String] = [String]()

    //現在表示している画像の添字を格納する変数
    var imageSub :Int = 0;



    @IBAction func button(_ sender: Any) {
        let query = text.text
        //配列の要素全削除
        wordImageArray.removeAll()
        wordImageArray.append(text.text!)
        // パラメータを指定する
        let parameter = ["key": apikey,"cx":cx,"searchType":searchType,"q":query]

        // パラメータをエンコードしたURLを作成する
        let requestUrl = createRequestUrl(parameter: parameter as! [String : String])

        // APIをリクエストする
        request(requestUrl: requestUrl) { result in
            if let url = URL(string: self.wordImageArray[0]) {
                let req = URLRequest(url: url)
                let task = URLSession.shared.dataTask(with: req, completionHandler: {data, response, error in
                    if let data = data {
                        if let anImage = UIImage(data: data) {
                            DispatchQueue.main.async {
                                self.pic.image = anImage
                            }
                        }
                    }
                })
                task.resume()
            }
        }
}

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        // textField の情報を受け取るための delegate を設定
        text.delegate = self as? UITextFieldDelegate

    }

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


    func textFieldShouldReturn(_ textField: UITextField) -> Bool{
        // キーボードを閉じる
        textField.resignFirstResponder()

        return true
    }

    // パラメータのURLエンコード処理
    func encodeParameter(key: String, value: String) -> String? {
        // 値をエンコードする
        guard let escapedValue = value.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) else {
            // エンコード失敗
            return nil
        }
        // エンコードした値をkey=valueの形式で返却する
        return "\(key)=\(escapedValue)"
    }

    // URL作成処理
    func createRequestUrl(parameter: [String: String]) -> String {
        var parameterString = ""
        for key in parameter.keys {
            // 値の取り出し
            guard let value = parameter[key] else {
                // 値なし。次のfor文の処理を行なう
                continue
            }

            // 既にパラメータが設定されていた場合
            if parameterString.lengthOfBytes(using: String.Encoding.utf8) > 0 {
                // パラメータ同士のセパレータである&を追加する
                parameterString += "&"
            }



            // 値をエンコードする
            guard let encodeValue = encodeParameter(key: key, value: value) else {
                // エンコード失敗。次のfor文の処理を行なう
                continue
            }
            // エンコードした値をパラメータとして追加する
            parameterString += encodeValue

        }
        let requestUrl = entryUrl + "?" + parameterString
        return requestUrl
    }

    // 検索結果をパース
    func parseData(items: [Any], resultHandler: @escaping (([String]?) -> Void)) {

        for item in items {

            // レスポンスデータから画像の情報を取得する
            guard let item = item as? [String: Any], let imageURL = item["link"] as? String else {
                resultHandler(nil)
                return
            }
            print(imageURL)

            // 配列に追加
            wordImageArray.append(imageURL)
        }

        resultHandler(wordImageArray)
    }

    // リクエストを行なう
    func request(requestUrl: String, resultHandler: @escaping (([String]?) -> Void)) {
        // URL生成
        guard let url = URL(string: requestUrl) else {
            // URL生成失敗
            resultHandler(nil)
            return
        }

        // リクエスト生成
        let request = URLRequest(url: url)

        // APIをコールして検索を行う
        let session = URLSession.shared
        let task = session.dataTask(with: request) { (data:Data?, response:URLResponse?, error:Error?) in
            // 通信完了後の処理
            print(NSString(data: data!, encoding: String.Encoding.utf8.rawValue) ?? "")

            // エラーチェック
            guard error == nil else {
                // エラー表示
                let alert = UIAlertController(title: "エラー", message: error?.localizedDescription, preferredStyle: UIAlertControllerStyle.alert)

                // UIに関する処理はメインスレッド上で行なう
                DispatchQueue.main.async {
                    self.present(alert, animated: true, completion: nil)
                }
                resultHandler(nil)
                return
            }

            // JSONで返却されたデータをパースして格納する
            guard let data = data else {
                // データなし
                resultHandler(nil)
                return
            }

            // JSON形式への変換処理
            guard let jsonData = try! JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as? [String: Any] else {
                // 変換失敗
                resultHandler(nil)
                return
            }

            // データを解析
            guard let resultSet = jsonData["items"] as? [Any] else {
                // データなし
                resultHandler(nil)
                return
            }
            self.parseData(items: resultSet, resultHandler: resultHandler)
        }
        // 通信開始
        task.resume()
    }
}

引用テキスト
実際の画像

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

0

これは質問に対する回答ではありません。

エラーが出ていないにも関わらず、ボタンを押してもimageviewに画像が表示されません。

と書かれていますが、これはあなたがエラーを無視しているからエラーが出ていないだけです。

適当に抜き出します

if let url = URL(string: wordImageArray[imageSub]) {
  ...
}


このif文ではurlがnilであった場合は何も行わずに処理が終了します。

あなたがいうところの「エラーが出ていないにも関わらず」は、正しくはあなたがエラーを表示していないだけです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.22%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る