🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Google マップ

Google Mapは、Google社がオンラインで提供している地図・ローカル検索サービスです。GIS(Geographic Information System:地理情報システム)の中の「WebGIS」に該当します。地図・航空写真・地形の表示方式があり、それぞれユーザーが縮尺を調整して表示させることができます。地域の情報サービスを検索する機能やルート検索の機能も搭載されています。

Q&A

解決済

1回答

1891閲覧

【Swift】CollectionViewを更新すると起こるエラーの解決策

dacci

総合スコア6

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Google マップ

Google Mapは、Google社がオンラインで提供している地図・ローカル検索サービスです。GIS(Geographic Information System:地理情報システム)の中の「WebGIS」に該当します。地図・航空写真・地形の表示方式があり、それぞれユーザーが縮尺を調整して表示させることができます。地域の情報サービスを検索する機能やルート検索の機能も搭載されています。

0グッド

0クリップ

投稿2020/01/01 06:46

編集2020/01/01 06:48

以下のようなマップの下部にCollectionViewを設置し、リロードボタンを押すとマップのピン、CollectionViewwのセルがリロードされるような画面を現在作っております。
イメージ説明イメージ説明

マップ上のピンを更新することは問題なくできているのですが、CollectionViewの更新がうまくいきません。

以下、CollectionViewControllerのコードです。

swift

1//sakeMapCollectionViewController.swift 2 3import UIKit 4 5class sakeMapCollectionViewController: UICollectionViewController, mapDelegate{ 6 7 @IBOutlet weak var sakeMapCollectionView: UICollectionView! 8 9 var getCollectionShops: [String] = [] 10 var delegate: mapDelegate? 11 var ActivityIndicator: UIActivityIndicatorView = UIActivityIndicatorView() 12 let flowLayout = FlowLayout() 13 14 private var cellSize: CGSize { 15 let width = collectionView.bounds.width * 0.9 16 let height = width / SakeMapCell.aspectRatio 17 return CGSize(width: width, height: height) 18 } 19 20 override func viewDidLoad() { 21 super.viewDidLoad() 22 print("viewDidLoad()") 23 if UserDefaults.standard.array(forKey: "collectionShops") != nil { 24 getCollectionShops = UserDefaults.standard.array(forKey: "collectionShops") as! [String] 25 } 26 loadCollectionView() 27 } 28 29 override func viewDidAppear(_ animated: Bool) { 30 super.viewDidAppear(animated) 31 } 32 33 override func viewDidLayoutSubviews(){ 34 super.viewDidLayoutSubviews() 35 setActivityIndicator() 36 } 37 38 func loadCollectionView() { 39 sakeMapCollectionView?.backgroundColor = UIColor.init(red: 0, green: 0, blue: 0, alpha: 0) // alpha0で透明 40 collectionView.decelerationRate = .fast 41 flowLayout.scrollDirection = .horizontal 42 flowLayout.minimumLineSpacing = 40 43 flowLayout.sectionInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20) 44 flowLayout.itemSize = cellSize 45 sakeMapCollectionView.collectionViewLayout = flowLayout 46 } 47 48 func reload() { 49 print("reloadData()") 50 sakeMapCollectionView.reloadData() //<---sakeMapCollectionViewがnilでエラー 51// loadCollectionView() //<--- Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value 52 } 53 54 override func collectionView(_: UICollectionView, numberOfItemsInSection _: Int) -> Int { 55 return getCollectionShops.count 56 } 57 58 override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 59 let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SakeMapCell", for: indexPath) as! SakeMapCell 60 cell.shopNameLabel.text = getCollectionShops[indexPath.row] 61 cell.shopGenreLabel.text = "酒屋" 62 print("(indexPath.row)番目の店") 63 print(cell) 64 print(indexPath) 65 66 return cell 67 } 68 69} 70

以下が、MapViewControllerです。

swift

1// 2// sakeMapViewController.swift 3// sakeai_ver1 4// 5// Created by 新山大地 on 2019/10/22. 6// Copyright © 2019 Daichi Niiyama. All rights reserved. 7// 8 9import UIKit 10import GoogleMaps 11import Alamofire 12import SwiftyJSON 13 //UICollectionViewController 14class sakeMapViewController: UIViewController{ 15 var googleMap: GMSMapView? 16 var locationManager = CLLocationManager() 17 //画面中心の緯度経度 18 var centerMapCoordinate:CLLocationCoordinate2D! 19 let marker = GMSMarker() 20 var markers : [GMSMarker] = [] 21 //取得した周辺のお店配列 22 var collectionShops: [String] = [] 23 //ContainerViewに表示するためのお店配列 24 var getCollectionShops: [String] = [] 25 var collectionViewController:sakeMapCollectionViewController = sakeMapCollectionViewController() 26 //delegateを設定 27 var delegate: mapDelegate? 28 let pinIcon = UIImage(named: "pinIcon") 29 30 @IBOutlet weak var locationButton: UIButton! 31 @IBOutlet weak var listButton: UIButton! 32 @IBOutlet weak var containerView: UIView! 33 @IBOutlet weak var closeButton: UIButton! 34 @IBOutlet weak var restartButton: UIButton! 35 @IBAction func closeButton(_ sender: Any) { 36 //MapViewに移る前にローカルDBをリセットしておく 37 UserDefaults.standard.removePersistentDomain(forName: "collectionShops") 38 39 self.dismiss(animated: true, completion: nil) 40 } 41 42 //このエリアで再検索 43 @IBAction func restartButton(_ sender: Any) { 44 let latitude = self.googleMap?.camera.target.latitude 45 let longitude = self.googleMap?.camera.target.longitude 46 centerMapCoordinate = CLLocationCoordinate2D(latitude: latitude!, longitude: longitude!) 47 self.getPlaces(coordinate: centerMapCoordinate) 48 self.delegate?.reload() 49 } 50 51 override func viewDidLoad() { 52 super.viewDidLoad() 53 self.googleMap = GMSMapView() 54 setupMapView() 55 setupButton() 56 self.googleMap?.delegate = self 57 self.delegate = collectionViewController 58 } 59 60} 61 62protocol mapDelegate: class { 63 func reload() 64} 65

restartButtonを押すと、self.getPlaces(coordinate: centerMapCoordinate)で現在地周辺の店をAPIで取得し、
self.delegate?.reload()でCollectionViewをリロードしようとしています。
getPlaceは問題なく実行することができ、店情報は取得できています。
CollectionViewControllerのreload()でprint("reloadData()")を問題なく出力できているため、mapDelegateのreload()も問題なさそうです。

func reload() { print("reloadData()") sakeMapCollectionView.reloadData() //<---sakeMapCollectionViewがnilでエラー // loadCollectionView() //<--- Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value }

エラーが出ているのは上記コードの部分なのですが、
sakeMapCollectionView.reloadData()でリロードしようとすると、

Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value

となってしまいます。おそらく、sakeMapCollectionViewがnilになってしまっているとおもうのですが、理由がわかりません。

また、sakeMapCollectionView.reloadData()をコメントアウトし、loadCollectionView()にすると、

Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value

となってしまいます。loadCollectionView()を実行したから、CollectionViewのセルを更新できるわけではなさそうなのでこちらは
意味ないと思いますが。。

以下が、現在実装している画面です。
イメージ説明

改善方法などご教示願います。
よろしくお願いいたします。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/01/01 11:33 編集

UICollectionViewControllerは使ったことがあまりないので、解決の糸口になったら程度に聞いてほしいのですが、UICollectionViewControllerのサブクラスでUICollectionViewをOutlet接続すると、numberOfItemsInSectionが更新するのはUICollectionView? UICollectionViewController上のCollectionView?
dacci

2020/01/03 17:43

tyobigorou様 ありがとうございます! CollectionViewのoutletをやめ、self.collectionViewに変更したところ、 collectionViewController.collectionView.reloadData()でエラーが出ずにうまく行きました! TakeOne様の言う通り、UICollectionViewControllerの中で最初から定義されているcollectionViewを使用しました。
guest

回答1

0

ベストアンサー

まず、エラーが発生する直接の原因ですが、
sakeMapViewControllerの中で

swift

1var collectionViewController:sakeMapCollectionViewController = sakeMapCollectionViewController()

このようにしてsakeMapCollectionViewControllerのインスタンスを生成して
いますが、この方法だとStroyboardを使用せずにインスタンスを生成します。

そのため、sakeMapCollectionViewControllerの中で

swift

1@IBOutlet weak var sakeMapCollectionView: UICollectionView!

このようにしてStoryboardからoutlet接続する形でsakeMapCollectionViewが
定義されていますが、Stroyboardを使用せずにインスタンス生成した場合、
sakeMapCollectionViewはnilになります。
そのため、

swift

1sakeMapCollectionView.reloadData()

はnilのため実行できないというエラーになったのだと思います。
Storyboardに貼り付けられたUI部品を読み込んだViewControllerを生成したいのであれば、
instantiateViewControllerWithIdentifierを使用する必要があります。

そもそも、tyobigorouさんも追記・修正依頼の中で少し触れられていますが、
sakeMapCollectionViewControllerがUICollectionViewControllerを
継承したものであれば、sakeMapCollectionViewをoutlet接続して使用するのではなく
UICollectionViewControllerの中で最初から定義されているcollectionViewを
使用する必要があると思います。

投稿2020/01/02 07:00

TakeOne

総合スコア6299

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dacci

2020/01/03 17:41

TakeOne様 ありがとうございます! CollectionViewのoutletをやめ、self.collectionViewに変更したところ、 collectionViewController.collectionView.reloadData()でエラーが出ずにうまく行きました! collectionViewが、reloadData()しても見た目が変わらないのでそれをこれからやっていきます。ここもわからないのでまた別の質問を立てると思いますが。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問