質問をすることでしか得られない、回答やアドバイスがある。

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

ただいまの
回答率

89.97%

Swift Type '' does not conform to protocol ''エラー

解決済

回答 1

投稿 編集

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

プログラミング歴2ヶ月独学150時間程度の初心者です。2日ハマってしまったので皆様のお力を貸して下さい。

現在、以下のような自作アプリ開発をしています。
「WEB APIで取得したデータをタプル配列で格納して、Table Viewで一覧表示する」

今回お聞きしたい内容は以下の2点。

  1. 必要なメソッドは追加しているが、Type '' does not conform to protocol ''となる原因
  2. tableView.dataSource = self でのUse of local variable 'tableView' before its declarationとなる原因

下に問題のコードを記載していますのでよろしくお願いします。

[経緯]

タプル配列で格納する所までは出来たのですが、題記のようなエラーが出てしましました。

Table VIewで表示するためにやったこと

  1. calssにUITableViewDataSource追加
  2. tableView.dataSource = self 追加
  3. func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return hogehoge.count
    } 追加
  4. func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "hogehoge", for: indexPath)
    cell.textLabel?.text = venueList[indexPath.row].name
    return cell
    } 追加

Table Viewを実装する際に必要なメソッドは追加できていると思っていたのですが、下記エラーが出てしまいました。

  1. Type '' does not conform to protocol ''
  2. Use of local variable 'tableView' before its declaration

[推測]

原因としては、これらのコードをviewDidLoad内に全てコードを書いていること?と推測しています。
画面を読み込んだ際にWEB API取得からデータ格納、Table View表示までやりたいので、viewDidLoad内に書いています。
ここも何かいい手がないか検討している所です。

長くなりましたが、改めて今回お聞きしたい内容は以下の2点です。

  1. 必要なメソッドは追加しているが、Type '' does not conform to protocol ''となる原因
  2. tableView.dataSource = self でのUse of local variable 'tableView' before its declarationとなる原因

どうぞよろしくお願いいたします。

//  Foursquare APIを利用したTweet機能実装

import UIKit
import FoursquareAPIClient
import Social

class SettingViewController: UIViewController,UITableViewDataSource {

    //,UITableViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.

        //Use of local variable 'tableView' before its declaration
        tableView.dataSource = self

        //viewDidLoadにコード書いて画面起動時に実行する
        //Foursquare APIを利用してリクエストURLからJSONコードを生成し格納する機能を実装

        //認証KeyであるIDとSecretの宣言
        let clientId = "hoge"
        let clientSecret = "hoge"

        // 現在位置を東京駅に指定
        // to do GPSから現在位置を取得する
        let currentLocation_latitude    = 35.681236
        let currentLocation_longitude   = 139.767125

        //緯度経度からvenue検索するreq_URL作成するfunc
        //venue search, 検索数=5、範囲を指定
        //guard letもdo catch 構文と同じ考えか。サンプルアプリはデコード作業していたのでエラー回避無理になるのか。

            guard let req_url = URL (string : "https://api.foursquare.com/v2/venues/search?v=20180228&ll=\(currentLocation_latitude),\(currentLocation_longitude)&intent=checkin&limit=5&radius=4000&client_id=\(clientId)&client_secret=\(clientSecret)")
                else {
                    return
                }

        //req_URLのデバック
        print(req_url)


        //以下で、req_urlにアクセスし構造体にレスポンスデータを格納する処理を行う
        //取得したレスポンスデータ(JSON)を記録する構造体を宣言

        //ItemJson構造体に以下のレスポンスデータを格納
        struct ItemJson  : Codable { //Codable : JSONを変換にした時に、一括して変数にデータを格納するプロトコル
            let response : JsonResponse?
        }

            struct JsonResponse : Codable {
                let venues      : [JsonVenues]
            }

                //JSONデータがオブジェクトだったのに配列で宣言していたので格納エラーになっていた
                struct JsonVenues : Codable {
                    let name      : String?
                    let location  : Jsonlocation?
                }

                    struct Jsonlocation : Codable {
                        let city        : String?
                        let state       : String?
                        let country     : String?
                    }

        // structの配列化 venuesで配列型の宣言しているので 多分不要
        //struct ResultJson : Codable {
          //  let item      : [ItemJson]?
        //}

        //レスポンスデータのリスト(タプル配列)
        var venueList : [(name:String, city:String, state:String, country:String)] = []

        //req_urlをロードするプロトコルを宣言
        let req = URLRequest(url:req_url)

        //リクエストのデータ転送方法の複雑なコードをひとまとめにしているクラス ら し い
        let session = URLSession(configuration: .default, delegate: nil, delegateQueue: OperationQueue.main)

        //ダウンロード先URL:req、data格納、通信状態データ格納、エラー内容格納
        let task = session.dataTask(with: req, completionHandler: {
            (data, response, error) in

            session.finishTasksAndInvalidate()

            // パースの際にエラーになった場合の例外処理でdo catch
            //コード内でプログラムが完結しないのでエラーチェックができない+外部と通信しているのでエラー条件が多すぎてif分では回避できない
            //そこでこのdo catch構文 
            do {

                //JSONをデコードするためのオブジェクトを作成
                let decoder = JSONDecoder()

                //受け取ったJSONデータをパースして格納
                //decode(ResultJson)からdecode(ItemJson)にしたら上手くいった

                let json = try decoder.decode(ItemJson.self, from: data!)

                //デバック用
                print (json)

                if let Venues = json.response?.venues {

                    //検索結果のタプル配列を初期化
                    venueList.removeAll()

                    for venues in Venues {

                        if  let name       = venues.name,
                            let city       = venues.location?.city,
                            let state      = venues.location?.state,
                            let country    = venues.location?.country {

                            let tupleVenue = (name,city, state, country)

                            venueList.append(tupleVenue)
                        }

                    }


                    self.tableView.reloadData()

                    if let tupleVenuedbg = venueList.first {
                        print ("-------------------------------")
                        print ("venueList[0] = \(tupleVenuedbg)")
                    }

                }


            } catch {
                print("エラーが発生しました")
            }

        })

        //ダウンロード開始
        task.resume()

        //-------------------------------------------------------------------------------
        //ここで宣言しているが、エラー Type 'SettingViewController' does not conform to protocol 'UITableViewDataSource'

        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return venueList.count
        }

        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

            let cell = tableView.dequeueReusableCell(withIdentifier: "venueCell", for: indexPath)

            cell.textLabel?.text = venueList[indexPath.row].name

            return cell
        }

    }   //viewDidLoad end

    //storyboardとViewControllerでtableViewを関連付け
    @IBOutlet weak var tableView: UITableView!





}   //class end
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+2

viewDidLoad内で以下を宣言してるのが悪いと思います。
viewDidLoadの外に移動するのに合わせてvenueListもメンバ変数にする必要がありますね。

        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return venueList.count
        }

        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

            let cell = tableView.dequeueReusableCell(withIdentifier: "venueCell", for: indexPath)

            cell.textLabel?.text = venueList[indexPath.row].name

            return cell
        }

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/03/10 11:26

    nakasho_dev様
    ご教授頂きありがとうございます!
    やはり、viewdidload内に書いたのが原因でしたか。何となくでも推測があっていたのである意味嬉しかったです笑。
    さて、教えて頂いたようにまずは外に出す所から再挑戦してみます。
    今回は基礎力が足りなく、funcについての知識が足らなかったことが原因と思うので合わせてそこらへんの知識も深めたいと思います。
    進めていく中でエラーがまた出ると思うので、その時はお時間がある時にお付き合い頂ければ幸いです。
    今回はありがどうございます。

    キャンセル

  • 2019/03/14 21:21

    nakasho_dev様
    無事に題記の件が解決することが出来ました。ありがとうございました。
    自分なりに原因を分析してみたのですが、
    1. tableViewを利用するので、dateSource必須メソッド2つを記載する必要がある
    2. func viewDidLoad() {
      func 1
    func 2
    } とメソッド内メソッドを宣言していたのが失敗?ここが合っているか疑問です。
    3.2の必須メソッドを外に出す必要があるが、そうするとタプル配列がスコープ外にあるのでタプル配列をメンバー変数にしてやる

    こんな感じで解決しました。今回学んだのは、変数にはスコープが存在するということでした。
    参考書をベースに作っているのでスコープを意識しなくても物が作れてしまうのでいい気づきになりました。

    キャンセル

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

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