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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Xcode

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

Swift

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

Q&A

解決済

1回答

1266閲覧

CollectionView, didSelectItemAtで遷移できない。SegementSlideを使用。

SadajiroOkuno

総合スコア4

Xcode

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

Swift

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

0グッド

0クリップ

投稿2020/07/15 08:02

編集2020/07/15 10:14

前提・実現したいこと

いつもお世話になってます。
SegementSlideを使ってスクロールメニューを実装していますが、collectionViewのdidSelectItemAtで遷移ができません。storyboard?.instantiateViewControllerを使った場合
(コンパイルにて)エラー
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)が表示されます。

Segueで繋いだ場合、
(デバッグにて)エラー
reason: 'Receiver (<SegementSampleApp.Page1ViewController: 0x7fea13630390>) has no segue with identifier 'toDetailView''が表示されます。

どちらもidを間違いなく入れて普段通りにコーディングしていますが、
SegementSlideやスクロールメニューの実装の場合、元になるページとそこに関わるpageViewの関係性を明示する為に何か他にコードが必要なんでしょうか?お分かりになる方よろしくお願い致します。

該当のソースコード

import UIKit import SegementSlide class ViewController: SegementSlideViewController{ override func viewDidLoad() { super.viewDidLoad() reloadData() scrollToSlide(at: 0, animated: true) self.navigationController?.navigationBar.shadowImage = UIImage() } override var titlesInSwitcher: [String]{ return["2020","2019","2018","2017","アイルトン セナ","ミハエル シューマッハ"] } override func segementSlideContentViewController(at index: Int) -> SegementSlideContentScrollViewDelegate? { switch index{ case 0: return Page1ViewController() case 1: return Page2ViewController() case 2: return Page3ViewController() case 3: return Page4ViewController() case 4: return Page5ViewController() case 5: return Page6ViewController() default:return Page1ViewController() } } }
import UIKit import SegementSlide class Page1ViewController: UIViewController,SegementSlideContentScrollViewDelegate { let keyForStoryborad = "DetailViewController" let keyForSegue = "toDetailView" var searchBar: UISearchBar! var collectionView: UICollectionView! var fileredArray: Array<Array<String>>! var name = String() var place = String() var point = String() var selectedIndex = 0 var carArray: Array<Array<String>> = [["フェラーリ", "Italy","19","ferrari"], ["マクラーレン", "England","39", "maclauren"], ["ルノー", "France","8","renault"], ["レッドブル", "Austria","27","redbull"], ["メルセデス", "Germany","80","amg"], ["ウィリアムズ", "England","0", "wil"], ["アルファタウリ", "Italy","7","alpha"], ["アルファロメオ", "Switzerland","2","alfa"],["ハース","USA","0","haas"],["レーシングポイント","England","22","racing"], ["レッドブル", "Austria","27","redbull"], ["レッドブル", "Austria","27","redbull"], ["レッドブル", "Austria","27","redbull"], ["レッドブル", "Austria","27","redbull"], ["レッドブル", "Austria","27","redbull"], ["レッドブル", "Austria","27","redbull"]] override func viewDidLoad() { super.viewDidLoad() fileredArray = carArray let viewWidth = self.view.frame.width let viewHeight = self.view.frame.height let collectionFrame = CGRect(x: 0, y: 0, width: viewWidth, height: viewHeight) let statusBar: CGFloat = 44 let searchBarHeight: CGFloat = 44 let switcherHeight: CGFloat = 35 let navigationBarHeight = self.navigationController?.navigationBar.frame.size.height let header = statusBar + searchBarHeight + switcherHeight + (navigationBarHeight ?? 44) let tabBarHeight = tabBarController?.tabBar.frame.size.height ?? 49 let layout = UICollectionViewFlowLayout() layout.itemSize = CGSize(width: 125, height: 180) layout.sectionInset = UIEdgeInsets(top: 6, left: 13, bottom: 6, right: 13) layout.minimumInteritemSpacing = 3 layout.minimumLineSpacing = 6 layout.headerReferenceSize = CGSize(width: viewWidth, height: searchBarHeight) layout.footerReferenceSize = CGSize(width: viewWidth, height: header + tabBarHeight) collectionView = UICollectionView(frame: collectionFrame, collectionViewLayout: layout) collectionView.register(UINib(nibName: "CustomCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "CellForCollection") collectionView.delegate = self collectionView.dataSource = self collectionView.backgroundColor = .white self.view.addSubview(collectionView) searchBar = UISearchBar() searchBar.delegate = self searchBar.frame = CGRect(x: 0, y: 0, width: viewWidth, height: 44) searchBar.showsCancelButton = true searchBar.placeholder = "チーム名検索" self.collectionView.addSubview(searchBar) } @objc var scrollView: UIScrollView { return collectionView } } //MARK: - UISearchBarDelegate extension Page1ViewController:UISearchBarDelegate{ func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { searchItems(searchText: searchText) } func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { searchBar.text = "" self.view.endEditing(true) fileredArray = carArray collectionView.reloadData() } func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { self.view.endEditing(true) searchItems(searchText: searchBar.text! as String) } func searchItems(searchText: String) { if searchText != "" { fileredArray = carArray.filter { car in return car.first!.contains(searchText) } as Array<Array<String>> } else { fileredArray = carArray } collectionView.reloadData() } } //MARK: - UICollectionViewDelegate,DataSource extension Page1ViewController: UICollectionViewDelegate, UICollectionViewDataSource{ func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return fileredArray.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CellForCollection", for: indexPath) as! CustomCollectionViewCell cell.layer.borderColor = #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1) cell.layer.borderWidth = 1.0 cell.layer.cornerRadius = 8.0 cell.carImage.image = UIImage(named: fileredArray[indexPath.row][3]) cell.carImage.contentMode = .scaleAspectFill cell.carName.text = (fileredArray?[indexPath.row][0]) cell.carName.font = cell.carName.font.withSize(13) cell.carName.adjustsFontSizeToFitWidth = true cell.point.text = (fileredArray[indexPath.row][2]) selectedIndex = indexPath.row return cell } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { ****どちらの方法も上手く遷移できません**** 使用時はどちらかをコメントアウトしてビルドしています。 let nextVC = storyboard?.instantiateViewController(identifier: keyForStoryborad) as! DetailViewController name = fileredArray[indexPath.row][0] place = fileredArray[indexPath.row][1] point = fileredArray[indexPath.row][2] nextVC.carName = name nextVC.pointToChampionship = point navigationController?.pushViewController(nextVC, animated: true) performSegue(withIdentifier: keyForSegue, sender: nil) } ****どちらの方法も上手く遷移できません**** override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if (segue.identifier == keyForSegue){ let nextVC: DetailViewController = segue.destination as! DetailViewController nextVC.carName = name nextVC.pointToChampionship = point } } }

試したこと

StoryboardにUIViewControllerでPage1ViewControllerとDetailViewControllerを紐付けてsegueのwithIdentifier、もしくわstoryboardのidentiferを明記した。
イメージ説明
イメージ説明
全体のstoryboardはこちらです。ここが悪いのでしょうか?
イメージ説明

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

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

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

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

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

fuzzball

2020/07/15 08:12 編集

セグエで繋いだとき(下のコードを使ったとき)、本当にそのエラーが出ますか?
TsukubaDepot

2020/07/15 08:13

問題の原因はなんとなく推測つくのですが、確認のためお伺いします。 1. Page1ViewController から DetailViewController へ遷移するだけのプログラムを作った場合は正常に動作しますでしょうか(つまり、Page1ViewControllerとDetailViewControllerだけから構成されるアプリを作る) 2. あるいは、もっと簡単にして、あるビューから違うビューに遷移させるプログラムを作ったとして、それは正常に動作しますでしょうか。 遷移させる部分で問題があるのであれば、基本的にはその部分で問題が生じていると推測されます。 なので、まずは最低限の構成にしてみて検証されてはいかがでしょうか。
fuzzball

2020/07/15 08:16

あー、すみません、下のコードを使うとき、上のコードは、 navigationController?.pushViewController(nextVC, animated: true) ここまでコメントアウトして、 performSegue(withIdentifier: keyForSegue, sender: nil) これは残してますかね?
SadajiroOkuno

2020/07/15 09:05

fuzzballさん 素早いご返信本当にありがとうございます! はい、コメントアウトはきっちり分けて。 storyboardを使うときはNavigationControllerを継承させ、 is Initial View Controllerにcheckを入れるとその時は遷移致します。恐らくページの繋ぎかたがおかしいのかもしれません。
SadajiroOkuno

2020/07/15 09:07

TsukubaDepotさん 早急のご返信戴き本当にありがとうございます! はい、 is Initial View Controllerにチェックを入れるとsegueでの遷移はできます!
SadajiroOkuno

2020/07/15 09:10

新たに全体のstoryboardの写真を掲載しました!
TsukubaDepot

2020/07/15 10:39

実装の経験がないので何とも言えませんが、直接インスタンス化した viewController に対して segue は使えるのでしょうか。 いま改めてコードを眺めていて気づいたのですが、 override func segementSlideContentViewController(at index: Int) -> SegementSlideContentScrollViewDelegate? { switch index{ case 0: return Page1ViewController() // 以下略 と、直接 viewController のインスタンスを作っています。 これだと、StoryBoard とは関連づかなくなるため、当然Segueも使えないかと思いますが、いかがでしょうか。
SadajiroOkuno

2020/07/15 11:18

理解力が乏しくお恥ずかしいです。ご返信ありがとうございます! 直接インスタンス化した場合、紐付けられないので他のページへの遷移ができないんですね。 勉強になりました。ありがとうございます! 話が少し外れますが、このようなケースの場合おすすめのできるライブラリなど、実装の方法がもしございましたらアドバイス頂けると幸いです。
TsukubaDepot

2020/07/15 11:27

Page1ViewController はストーリーボード上にも配置してあるようですので、そちらをインスタンス化してみてはいかがでしょうか(クラス内での制約などの辻褄が合わない可能性があるかもしれませんが、それについては調整をお願いします)。 case 0: let page1VC = self.storyboard?.instantiateViewController(withIdentifier: "Page1ViewController") as! Page1ViewController return page1VC のような感じでやってみるといかがでしょうか。
TsukubaDepot

2020/07/15 11:28

withIdentifier の部分は、StoryBoard で Page1 View Controller に名付けた Identifier となりますので、ここも適切に変更していただければと思います。
SadajiroOkuno

2020/07/15 12:11

TsukubaDepotさん 遷移できました!またひとつ勉強させて戴きました!! ベストアンサーにさせて戴きたいんですが、お時間ありましたら回答欄に御回答を簡単にお願いしたいです ! よろしくお願いします!
TsukubaDepot

2020/07/15 12:48

一番決定的だったのは、質問者さんご自身が「StoryBoard Entry Point」を変更したら正常に動く、とおっしゃられた一言です。 コード中では直接インスタンス化した形跡があるので、辻褄が合わないなと感じ原因を正確に判断できました。 そういう意味では、おそらく質問者さんもすぐに矛盾にきづかれ自己解決されたのかとおもいますが、今回はありがたくBAをいただきたいと思います。
TsukubaDepot

2020/07/15 12:48

あ、簡単ではなくて長々と回答を書いてしまいましたが、ナレッジとしては使い回しが聞くかと思います。
guest

回答1

0

ベストアンサー

以下の場所では Page1ViewController()`のインスタンスを直接作っていますが、

Swift

1class ViewController: SegementSlideViewController{ 2 3 // 中略 4 override func segementSlideContentViewController(at index: Int) -> SegementSlideContentScrollViewDelegate? { 5 switch index{ 6 7 case 0: 8 return Page1ViewController() 9 // 後略 10}

遷移しようとする場所では

Swift

1 performSegue(withIdentifier: keyForSegue, sender: nil)

を実行しているため、StoryBoard 上で設定した viewController に遷移しようとして失敗していると思われます。

また、別に試されたコードだと

Swift

1 let nextVC = storyboard?.instantiateViewController(identifier: keyForStoryborad) as! DetailViewController 2 name = fileredArray[indexPath.row][0] 3 place = fileredArray[indexPath.row][1] 4 point = fileredArray[indexPath.row][2] 5 nextVC.carName = name 6 nextVC.pointToChampionship = point 7 navigationController?.pushViewController(nextVC, animated: true)

と、最初にsegementSlideContentViewController(at:)で指定した viewController とはクラス名は同じでも違うインスタンスを新たに生成し、navigationController で遷移しようとしてるため、矛盾が生じているのだとおもます。

解決方法はいくつか考えられますが、ひとつはsegementSlideContentViewController(at:)`で生成する viewController を

Swift

1class ViewController: SegementSlideViewController{ 2 3 // 中略 4 override func segementSlideContentViewController(at index: Int) -> SegementSlideContentScrollViewDelegate? { 5 switch index{ 6 7 case 0: 8 return storyboard?.instantiateViewController(identifier: keyForStoryborad) as! DetailViewController 9 // 後略 10}

という具合に StoryBoard 経由で生成したインスタンスとして、

その後performSegue()で遷移するのが良いかもしれません。

navigationController を使う場合であっても、遷移する viewController のインスタンスに矛盾が生じないようにすればうまくいくかもしれません(その場合は階層構造についてさらに慎重に検討する必要があるかもしれません)。

投稿2020/07/15 12:46

TsukubaDepot

総合スコア5086

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

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

SadajiroOkuno

2020/07/15 13:10

TsukubaDepotさん とてもわかりやすく御回答戴きました。本当にありがとうございます! 大変勉強になりました。参考にさせて戴きます! 本当にありがとうございます!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問