47887


前提・実現したいこと  
Swiftでグルメアプリを製作中なのですが、エラーがなかなか解決できずかなりつまづいています。解決法やアドバイスなど頂けると幸いです。

やりたいこと  
FirebaseのFirestoreから取得したデータを元に、CoreLocationを用いて現在地から近い順にデータを並べ替え、TableViewに表示したい。

今やろうとしていることは、CoreLocationを用いて現在地と店舗との距離を測定し、keyをDistanceとしてデータに追加しようとしています。しかし下記のエラーが出てしまい、うまくいきません。

まずこの方法で現在地から近い順にソートできるかも自身もないため、そのほかにもやり方などあれば教えていただきたいです。

* * *

発生している問題・エラーメッセージ

[code]

    Type 'Shop' has no subscript members
    
[/code]

該当のソースコード  
shopArrayにShop型のデータが突っ込んであります。

[code]

    func locationManager(_ manager: CLLocationManager, didUpdateLOcations locations: [CLLocation]){
        let localValue:CLLocationCoordinate2D = manager.location!.coordinate
        print("locations =\(localValue.latitude) \(localValue.longitude)")
    
        for i in 0 ..< self.shopArray.count{
            let currentLocation : CLLocation = CLLocation(latitude: localValue.latitude, longitude: localValue.longitude)
            let shopLocation : CLLocation = CLLocation(latitude: self.shopArray[i].latitude, longitude: self.shopArray[i].longitude)
            let distance = shopLocation.distance(from: currentLocation)
            shopArray[i]["distance"] = "distance" # エラーはこの行に出ます。
    
[/code]

データの形式は下記です。

[code]

    struct Shop {
        var title: String
        var recomendation: String
        var tel: String
        var station: String
        var latitude: Double
        var longitude: Double
        var price: Int
        var img: String
    
        var dictionary: [String: Any] {
            return [
                "title": title,
                "recomendation": recomendation,
                "tel": tel,
                "station": station,
                "latitude": latitude,
                "longitude": longitude,
                "price": price,
                "img": img
            ]
        }
    }
    
[/code]

ーーーーーーーーーーーーーーーーーーーーーーーーーー  
追記 shopArrayにデータを格納するコード

[code]

    func loadData() {
        let db = Firestore.firestore()
        let shopsRef = db.collection("shops")
    
        shopsRef.getDocuments() { (snapshot, err) in
            if let err = err {
                print("Error getting documents: \(err)")
            } else {
                if let snapshot = snapshot{
                    for document in snapshot.documents {
    
                        print(document.data())
                        let data = document.data()
                        let title = data["title"] as? String ?? ""
                        let recomendation = data["recomendation"] as? String ?? ""
                        let tel = data["tel"] as? String ?? ""
                        let station = data["station"] as? String ?? ""
                        let latitude = data["latitude"] as? Double ?? Double()
                        let longitude = data["longitude"] as? Double ?? Double()
                        let price = data["price"] as? Int ?? Int()
                        let img = data["img"] as? String ?? ""
                        let distance = data["distance"] as? CLLocationDistance ?? Double()
    
                        let newShop = Shop(title: title, recomendation: recomendation, tel: tel, station: station, latitude: latitude, longitude: longitude, price: price, img: img, distance: distance)
                        self.shopArray.append(newShop)
    
                        func locationManager(_ manager: CLLocationManager, didUpdateLOcations locations: [CLLocation]){
                            guard let currentLocation = manager.location else {
                                print("location is nil")
                                return
                            }
                            print("locations =\(currentLocation.coordinate)")
    
                            for i in self.shopArray.indices{
                                //                let currentLocation : CLLocation = CLLocation(latitude: localValue.latitude, longitude: localValue.longitude)
                                let shopLocation : CLLocation = CLLocation(latitude: self.shopArray[i].latitude, longitude: self.shopArray[i].longitude)
                                let distance = shopLocation.distance(from: currentLocation)
                                self.shopArray[i].distance = distance //<-
    
                            }
                            self.shopArray.sort{$0.distance ?? 0.0 < $1.distance ?? 0.0}
                            self.cafeTableView.reloadData()
                        }
                    }
                }
            }
        }
    }
    
[/code]

一部抜粋することによりわかりにくくなってしまっていたのでコード全文も掲載いたします。  
ご迷惑をおかけして申し訳ありません。（いくつかのご指摘をいただき修正が加えてあるため、上のコードとは相違があります。）

[code]

    protocol DocumentSerializeable {
    init?(dictionary:[String:Any])
    }
    
    struct Shop {
    var title: String
    var recomendation: String
    var tel: String
    var station: String
    var latitude: Double
    var longitude: Double
    var price: Int
    var img: String
    var distance: CLLocationDistance?
    
    }
    
    
    
    class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource,UISearchBarDelegate,CLLocationManagerDelegate{
    
    @IBOutlet var cafeTableView: UITableView!
    
    var shopArray = [Shop]()
    var db: Firestore!
    
    private var mySearchBar: UISearchBar!
    private weak var refreshControl: UIRefreshControl!
    
    var locationManager: CLLocationManager!
    var currentLocation: CLLocation!
    
    //検索結果が入る配列
    private var searchResult = [String]()
    private var myItems = [String]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        locationManager = CLLocationManager()
        locationManager.requestWhenInUseAuthorization()
        loadData()
        let myNavBar = UINavigationBar()
        //大きさの指定
        myNavBar.frame = CGRect(x: 0, y: UIApplication.shared.statusBarFrame.height, width: self.view.frame.size.width, height: 44)
        mySearchBar = UISearchBar()
        //デリゲートを設定
        mySearchBar.delegate = self
        //大きさの指定
        mySearchBar.frame = CGRect(x: 0, y: UIApplication.shared.statusBarFrame.height, width: self.view.frame.size.width, height: 44)
        //キャンセルボタンの追加
        mySearchBar.showsCancelButton = true
        mySearchBar.placeholder = "カフェ名を入力してください"
    
        cafeTableView.tableHeaderView = mySearchBar
        cafeTableView.contentOffset = CGPoint(x: 0,y :44)
    
        self.cafeTableView.delegate = self
        self.cafeTableView.dataSource = self
             getTitle()
        initializePullToRefresh()
            }
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        refresh()
    }
    
    func loadData() {
        let db = Firestore.firestore()
        let shopsRef = db.collection("shops")
    
        shopsRef.getDocuments() { (snapshot, err) in
            if let err = err {
                print("Error getting documents: \(err)")
            } else {
                if let snapshot = snapshot{
                for document in snapshot.documents {
    
                    print(document.data())
                    let data = document.data()
                    let title = data["title"] as? String ?? ""
                    let recomendation = data["recomendation"] as? String ?? ""
                    let tel = data["tel"] as? String ?? ""
                    let station = data["station"] as? String ?? ""
                    let latitude = data["latitude"] as? Double ?? Double()
                    let longitude = data["longitude"] as? Double ?? Double()
                    let price = data["price"] as? Int ?? Int()
                    let img = data["img"] as? String ?? ""
                    let distance = data["distance"] as? CLLocationDistance ?? Double()
    
                    let newShop = Shop(title: title, recomendation: recomendation, tel: tel, station: station, latitude: latitude, longitude: longitude, price: price, img: img, distance: distance)
                    self.shopArray.append(newShop)
                    self.cafeTableView.reloadData()
    
    
    
                    }
    
    
                }
    
                }
    
    
    
     }
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLOcations locations: [CLLocation]) {
        guard let currentLocation = manager.location else {
            print("location is nil")
            return
        }
        print("locations =\(currentLocation.coordinate)")
    
        for i in shopArray.indices {
            let shopLocation : CLLocation = CLLocation(latitude: shopArray[i].latitude, longitude: shopArray[i].longitude)
            let distance = shopLocation.distance(from: currentLocation)
            shopArray[i].distance = distance
        }
    
        //`locationManager(_:didUpdateLOcations:)`のように非同期に呼び出されるメソッドの中で
        //UIスレッドで実行する必要のある処理は`DispatchQueue.main.async {...}`の中に書く
        DispatchQueue.main.async {
            //`distance`プロパティの値(nilなら0.0に置き換え)でソートする
            //(SwiftのArrayはスレッドセーフではないので、ソートもUIスレッドの中で行う)
            self.shopArray.sort {$0.distance ?? 0.0 < $1.distance ?? 0.0}
            //`UITableView`の`realod()`と言ったUI操作はUIスレッドで実行するのが必須
            self.cafeTableView.reloadData()
        }
    }
    
    
    func getTitle(){
        let db = Firestore.firestore()
    
        db.collection("shops").whereField("title", isEqualTo: true)
            .getDocuments() { (snapshot, err) in
                if let err = err {
                    print("Error getting documents: \(err)")
                } else {
                    if let snapshot = snapshot{
                    for document in snapshot.documents {
                        print("\(document.documentID) => \(document.data())")
                        let data = document.data()
                        let title = data["title"] as? String ?? ""
    
                        self.myItems.append(title)
                        }
    
                    }
                }
        }
    
    }
    
    
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    
    @IBAction func searchTapped(_ sender: Any) {
        if cafeTableView.contentOffset == CGPoint(x: 0,y :0)  {
            cafeTableView.contentOffset = CGPoint(x: 0,y :44)
            self.view.endEditing(true)
    
        }else{
    
            cafeTableView.contentOffset = CGPoint(x: 0,y :0)
            self.view.endEditing(true)
    
        }
    }
    //MARK: - 渡された文字列を含む要素を検索し、テーブルビューを再表示する
    func searchItems(searchText: String){
    
        //要素を検索する
        if searchText != "" {
            searchResult = myItems.filter { myItem in
                return (myItem).contains(searchText)
                }
    
        }else{
            //渡された文字列が空の場合は全てを表示
            searchResult = myItems
        }
                cafeTableView.reloadData()
    }
    
    // MARK: - SearchBarのデリゲードメソッドたち
    //MARK: テキストが変更される毎に呼ばれる
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        //検索する
        searchItems(searchText: searchText)
    }
    
    //MARK: キャンセルボタンが押されると呼ばれる
    func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
    
        mySearchBar.text = ""
        self.view.endEditing(true)
        searchResult = myItems
    
        //tableViewを再読み込みする
        cafeTableView.reloadData()
    }
    
    //MARK: Searchボタンが押されると呼ばれる
    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
    
        self.view.endEditing(true)
        //検索する
        searchItems(searchText: mySearchBar.text! as String)
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.shopArray.count
    }
    
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
        let cell = tableView.dequeueReusableCell(withIdentifier: "ShopListTableViewCell", for: indexPath)
        let shop = shopArray[indexPath.row]
    
        let img = UIImage(named:  "\(shop.img).jpg")
        cafeTableView.separatorColor = UIColor.white
    
    
        // Tag番号 1 で UIImageView インスタンスの生成
        let imageView = cell.viewWithTag(1) as! UIImageView
        imageView.image = img
    
    
        // Tag番号 ２ で UILabel インスタンスの生成
        let shopName = cell.viewWithTag(2) as! UILabel
        shopName.text = "\(shop.title)"
    
        let placeName = cell.viewWithTag(3) as! UILabel
        placeName.text = "\(shop.station)"
    
        let distanceLabel = cell.viewWithTag(4) as! UILabel
        distanceLabel.text = "\(String(describing: shop.distance))"
    
    
    
        self.view.bringSubview(toFront: imageView)
    
        return cell
    
    }
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    func tableView(_ table: UITableView,
                   heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 135.0
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    
       let storyBoard = UIStoryboard(name: "Main", bundle: nil)
       let DvC = storyBoard.instantiateViewController(withIdentifier: "DetailViewController") as! DetailViewController
       let shop = shopArray[indexPath.row]
    
    
       DvC.getName = "\(shop.title)"
       DvC.getImage = UIImage(named:  "\(shop.img).jpg")!
       DvC.getNumber = "\(shop.tel)"
       DvC.getRecomend = "\(shop.recomendation)"
       DvC.getPrice = "\(shop.price)"
    
       self.navigationController?.pushViewController(DvC, animated: true)
    
    }
    
    
    @IBAction func getInfo(_ sender: Any) {
    
        print("\(shopArray)")
        print("\(currentLocation)")
    
    }
    
    
    // MARK: - Pull to Refresh
    private func initializePullToRefresh() {
        let control = UIRefreshControl()
        control.addTarget(self, action: #selector(onPullToRefresh(_:)), for: .valueChanged)
        cafeTableView.addSubview(control)
        refreshControl = control
    }
    
    @objc private func onPullToRefresh(_ sender: AnyObject) {
        refresh()
    }
    
    private func stopPullToRefresh() {
        if refreshControl.isRefreshing {
            refreshControl.endRefreshing()
        }
    }
    
    // MARK: - Data Flow
    private func refresh() {
        DispatchQueue.global().async {
            Thread.sleep(forTimeInterval: 1.0)
            DispatchQueue.main.async {
                self.completeRefresh()
            }
        }
    }
    
    private func completeRefresh() {
        stopPullToRefresh()
        cafeTableView.reloadData()
    }
    
[/code]


CC BY-SA 4.0
2018-08-28T04:56:22.407
47870
2018-09-02T12:59:44.180
2018-09-01T15:45:08.897
29892
29892
question
swift xcode firebase
SwiftエラーType '' has no subscript membersを解決して、Dictionaryを現在地からの近さ順に並べたい


Swiftは読めるのですが、あまりかけないのですこし構文が間違っているかもしれません。

1.Shop Structからディクショナリは不要だと思います。削除しましょう。  
2.一つクラスを追加します。

[code]

    class ShopDistance
    {
        var shop : Shop
        var distance : CLLocationDistance
    }
    
[/code]

3.locationManager関数内に配列を準備します

[code]

    func locationManager(_ manager: CLLocationManager, didUpdateLOcations locations: [CLLocation]){
        let localValue:CLLocationCoordinate2D = manager.location!.coordinate
        print("locations =\(localValue.latitude) \(localValue.longitude)")
    
        var arrayShopDistance: [ShopDistance] = []
    
[/code]

4.エラーの出ている箇所でShopDistanceのインスタンスを作り、対象のShopのデータと計算結果の距離をセットします。  
その後、arrayShopDistanceに情報をためていきます。

[code]

    for i in 0 ..< self.shopArray.count{
        let currentLocation : CLLocation = CLLocation(latitude: localValue.latitude, longitude: localValue.longitude)
        let shopLocation : CLLocation = CLLocation(latitude: self.shopArray[i].latitude, longitude: self.shopArray[i].longitude)
        let distance = shopLocation.distance(from: currentLocation)
    
        var oneShop = ShopDistance()
        oneShop.shop = shopArray[i]
        oneShop.distance
    
        arrayShopDistance.append(oneShop)
    
[/code]

5.すべてのお店への距離の計算が終わったら、arrayShopDistanceを並べ替えます

[code]

    arrayShopDistance.sort(by: {$0.distance < $1.distance})
    
[/code]

6.並べ替え終わったarrayShopDistanceから順番にお店の情報を取り出して表示しましょう。

以上になります。

・ポイント  
数値を文字列で比較するのはやめましょう。  
数値で比較すると9は10より小さくなりますが、文字列で比較すると"9"は"10"より大きくなります。

■追記  
なぜこのエラーが出ているのかを書き忘れました。  
まずエラーの出ている「shopArray[i]["distance"]」の個所ですが、  
shopArray[i]はShop Struct型の変数だと思います。  
このShop Struct型の変数に対して、配列のようにキーを与えてアクセスしようとしていますが、  
Shop Struct型がこのアクセス方法を受け取れないからこのようなエラーが出ていると考えられます。


CC BY-SA 4.0
2018-08-28T07:46:46.003
47876
2018-08-28T08:20:42.387
2018-08-28T08:20:42.387
17014
17014
47870
answer


teratailさん含めてあれこれの回答がすでについていますし、以下の内容もちょっとかぶるんですが、とりあえず私なりの例を。

* * *

まずは質問の仕方なのですが、コードを示す場合、関連する情報を可能な限り具体的に載せるようにしてください。例えば、

> shopArrayにShop型のデータが突っ込んであります。

なんて曖昧な言い方よりも、

> `shopArray`は
[code]

>     var shopArray: [Shop] = []
>  
[/code]

>
> と定義しています。

と書いてくれた方が何倍もわかりやすいでしょう。(これさえあれば、どのようにデータを「突っ込んで」いるのかはわからなくても回答が書けます。今回のあなたの質問の内容だけだと`shopArray`が`[Shop]`型であることはコードを熟読して推定する必要があります。)

またメソッドを途中で切ってしまうのも、思わぬ誤解を招く元になります。

* * *

`shopArray[i]["distance"] = "distance"`がエラーになる理由については、user17014
さんの回答にもありますが、`shopArray[i]`(のデータ型の`Shop`)には`subscript`と言うものが定義されていないからです。

`subscript`が定義されている代表的なデータ型に`Array`や`Dictionary`があるわけですが、例えば`shopArray`は`Array<Shop>`型であり、`Array`型には`subscript`が定義されているから`shopArray[i]`なんて(`[]`…subscriptを使った)書き方ができるのです。

あなたのコードの場合、`shopArray[i]`は`Shop`型であり、`Shop`型には`subscript`が定義されていませんから、`shopArray[i]["distance"]`なんて書き方は代入でも参照するだけでもエラーになります。

* * *

距離を`Shop`型に持たせたいのであれば、素直にプロパティとして追加してやるべきでしょう。

[code]

    struct Shop {
        var title: String
        //...
        
        var distance: CLLocationDistance?
        
        var dictionary: [String: Any] {
            return [
                //...
            ]
        }
    }
    
[/code]

(`distance`プロパティの値は代入してやるまで決まらないので、Optional型にしてあります。使うときにちょっと面倒くさくなるんで、初期値を0.0とか負の値にして非Optionalの`CLLocationDistance`型にしても良いでしょう。)

上のようにしておけば、`distance`の設定は通常のプロパティ値の変更をするだけです。

[code]

        for i in self.shopArray.indices {
            let shopLocation : CLLocation = CLLocation(latitude: self.shopArray[i].latitude, longitude: self.shopArray[i].longitude)
            let distance = shopLocation.distance(from: currentLocation)
            shopArray[i].distance = distance //<-
        }
    
[/code]

ちなみに`currentLocation`の値はループの中で変化しないので、ループの外で宣言しておくべきでしょう。ソートまで入れるとこんな感じになります。

[code]

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let currentLocation = manager.location else {
            print("location is nil")
            return
        }
        print("locations =\(currentLocation.coordinate)")
        
        for i in shopArray.indices {
            let shopLocation : CLLocation = CLLocation(latitude: shopArray[i].latitude, longitude: shopArray[i].longitude)
            let distance = shopLocation.distance(from: currentLocation)
            shopArray[i].distance = distance
        }
        
        //`locationManager(_:didUpdateLOcations:)`のように非同期に呼び出されるメソッドの中で
        //UIスレッドで実行する必要のある処理は`DispatchQueue.main.async {...}`の中に書く
        DispatchQueue.main.async {
            //`distance`プロパティの値(nilなら0.0に置き換え)でソートする
            //(SwiftのArrayはスレッドセーフではないので、ソートもUIスレッドの中で行う)
            self.shopArray.sort {$0.distance ?? 0.0 < $1.distance ?? 0.0}
            //`UITableView`の`reload()`と言ったUI操作はUIスレッドで実行するのが必須
            self.cafeTableView.reloadData()
        }
    }
    
[/code]

とりあえずUIスレッドがらみの修正を行いました。コードというのはどんな文脈で実行されているのかで気をつけなければいけないことなどが変わってきます。ご質問を書かれる際にはそこら辺の文脈を省略しすぎないようご留意ください。

* * *

さらにあなたが現在示されているコード(インデントが正しくないので気づくのが遅れましたが)では、`locationManager(_:didUpdateLOcations:)`メソッドが`loadData()`内に含まれてしまっています。

[code]

    func loadData() {
        //...
        func locationManager(_ manager: CLLocationManager, didUpdateLOcations locations: [CLLocation]){
            //...
        } // locationManager(_:didUpdateLOcations:)の終わり
    
        //...
    
    } // loadDataの終わり
    
[/code]

Swiftではこのように他のメソッド内に埋め込まれた関数は外部からは見えません。`locationManager(_:didUpdateLOcations:)`は、`loadData()`の外に出して、クラスのメソッドとなるようにしてください。

[code]

    func loadData() {
        //...
    
        //...
    
    } // loadDataの終わり
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){
        //...
    } // locationManager(_:didUpdateLOcations:)の終わり
    
[/code]

* * *

## 最新のコード全文とコメントより

まずTableView内に表示される値が`Optional(0.0)`になる点ですが、`loadData()`と`tableView(_:cellForRowAt:)`の2箇所を修正してもらった方がいいでしょう。

### `loadData()`内:

[code]

    let distance = data["distance"] as? CLLocationDistance ?? Double()
    
[/code]

↓

[code]

    let distance = data["distance"] as? CLLocationDistance
    
[/code]

この回答の最初の方の部分で、「distanceプロパティの値は代入してやるまで決まらないので、Optional型にしてあります」と言うのはお読みいただいたでしょうか。`distance`の値が決まるまでは`nil`のままにしておこうと言う意図で`Shop`に追加した`distance`プロパティをOptionalの`CLLocationDistance?`にしてあります。他の非Optionalプロパティのように、値が見つからない場合のデフォルト値を`??`で与える必要はありません。

(ちなみに`Double()`と書くより`0.0`と書いた方が、どんな値がデフォルト値になるかが遥かにわかりやすいと思うのですが。)

### `loadData()`と`tableView(_:cellForRowAt:)`内:

上に書いたように「distanceプロパティの値は代入してやるまで決まらないので、Optional型にしてあります」から、`distance`の値が`nil`の場合の表示は考えてやらないといけません。以下では`"\---"`を表示することにしていますので適切に修正してください。`String.init(describing:)`は値が`nil`の時に`"nil"`なんて文字列を返して来ます(普通のユーザには`nil`なんて何のことかわからないでしょう)し、値が非nilの場合に`Optional(`
`)`なんて余計なものがくっついてきます。Xcodeが勧めてくる時もあるのですが、
**`String.init(describing:)`はどんな動作になるのかわからない限り使わない** と覚えておいた方が良いでしょう。

他にもあまりお勧めできない書き方をしている部分もあるので、こちらはメソッド全体を掲載しておきます。

[code]

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "ShopListTableViewCell", for: indexPath)
        let shop = shopArray[indexPath.row]
        
        let img = UIImage(named:  "\(shop.img).jpg")
        cafeTableView.separatorColor = UIColor.white
        // Tag番号 1 の UIImageView インスタンスを取得する
        //### 「インスタンスを生成」することと既に存在するインスタンスを取得することとは全く違います
        //### この辺を理解しておいてもらわないと、Q&Aサイトの「回答」を読む時に誤解する恐れがあるので、
        //### コメントではありますが、あえて修正しました
        let imageView = cell.viewWithTag(1) as! UIImageView
        imageView.image = img
        // Tag番号 ２ の UILabel インスタンスを取得する
        let shopName = cell.viewWithTag(2) as! UILabel
        shopName.text = shop.title //###`String`型の値を`String?`型のプロパティに代入するのに文字列補間の構文を使用する必要はない
        //
        let placeName = cell.viewWithTag(3) as! UILabel
        placeName.text = shop.station
        //
        let distanceLabel = cell.viewWithTag(4) as! UILabel
        //### `distance`がnilなら"---"を、非nilならDoubleをStringに変換
        distanceLabel.text = shop.distance == nil ? "---" : String(shop.distance!)
        
        self.view.bringSubview(toFront: imageView) //###<-なぜこんなものが必要か不明(Storyboardの構成がおかしいせい?)なので残しておきます
        
        return cell
    }
    
[/code]

(この辺はカスタムセルクラスを使った方が、コード的には綺麗に見えるところですね。何かカスタムセルを使わない理由でもあるのでしょうか?)

* * *

## そして一番肝心なところ

あなたのクラス内には、どこにも`locationManager.startUpdatingLocation()`や`locationManager.stopUpdatingLocation()`を呼んでいるところが見当たりません。`CLLocationManager`の使い方のサンプルコードをネット上で探せば、ちゃんとしたコードを載せているサイトならすぐ見つかるはずですが…。

とりあえず、適切な場所で`locationManager.startUpdatingLocation()`を呼ぶようにして、それから、`print("locations
=\\(currentLocation.coordinate)")`に対応する出力が確実にデバッグコンソールに表示されているか確認してみてください。


CC BY-SA 4.0
2018-08-28T12:06:51.047
47887
2018-09-02T12:59:44.180
2020-06-17T08:14:45.997
-1
13972
47870
answer