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

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

ただいまの
回答率

90.53%

  • Swift

    7210questions

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

  • Xcode

    4082questions

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

UICollectionView xibに配置したボタンをタップして画像をモーダル表示させたい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 904
退会済みユーザー

退会済みユーザー

前提・実現したいこと

xcode8 swift3 iPad
UICollectionViewを使用して、画像のスライドショーみたいなものを作っています。
各セルのサイズはフルスクリーンです。
各セルのレイアウトは違っていて、indexPathごとにカスタムセルでxibを使っています。
セルにボタンを配置してボタンをタップしたら、画像をモーダル表示したいです。

storyboardにViewControllerをUICollecitonViewを配置したものとは別に、新たに配置しています。
xibのボタンから新たに配置したViewControllerに遷移させたいです。

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

xibにボタンを配置しましたが、そこからのモーダル表示が上手くいきません。
UICollectionViewCellクラスからの遷移方法がわからず、色々と試していますが、上手くいっておりません。
selfのところでエラーとなっていますが、UICollectionViewクラスではないからと思いましたが、解決方法がわかっておりません。

該当のソースコード

// カスタムセルクラス
class CollectionViewCell2: CommonCollectionViewCell {

    @IBOutlet weak var mainImage: UIImageView!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    func setCell(imageName: String) {
        self.mainImage.image = UIImage(named: imageName)
    }

}
// ViewControllerクラス
class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {

    var screenHeight: CGFloat!
    var screenWidth: CGFloat!

    let screenNames = ["main01", "main02", "main03", "main09", "main02", "main03", "main09", "main02"]

    override func viewDidLoad() {
        super.viewDidLoad()

        let statusBar = UIView(frame:CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.width, height: 20.0))
        statusBar.backgroundColor = UIColor.white
        view.addSubview(statusBar)
        self.automaticallyAdjustsScrollViewInsets = false

        self.collectionView!.register(UINib(nibName: "CollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "cell1")
        self.collectionView!.register(UINib(nibName: "CollectionViewCell2", bundle: nil), forCellWithReuseIdentifier: "cell2")
    }

    // 希望のセルサイズを返す
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

        let screenSize: CGRect = UIScreen.main.bounds
        screenWidth = screenSize.width
        screenHeight = screenSize.height
        let returnSize = CGSize(width: screenSize.width, height: screenSize.height)

        return returnSize
    }

    //セルのアイテムのマージンを設定
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsetsMake(20.0 , 0.0 , 0.0 , 0.0 )  //マージン(top , left , bottom , right)
    }

    //セル間のマージンを削除
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 0.0
    }

    //データの個数を返す
    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
    {
        return screenNames.count
    }

    //データを返す
    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
    {
        var cell: CommonCollectionViewCell!
        if(indexPath.row == 0 || indexPath.row == 1) {
            let cell1 = collectionView.dequeueReusableCell(withReuseIdentifier: "cell1", for: indexPath as IndexPath) as! CollectionViewCell
            cell1.setCell(imageName: screenNames[indexPath.row])
            cell = cell1
        }
        else {
            let cell2 = collectionView.dequeueReusableCell(withReuseIdentifier: "cell2", for: indexPath as IndexPath) as! CollectionViewCell2
            cell2.setCell(imageName: screenNames[indexPath.row])
            cell = cell2
        }

        return cell
    }

    // ボタンタップで実行されるメソッド
    @IBAction func modalView(_ sender: UIButton) {
        print("tapButtonA")
    }

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

コンソールでbtコマンドをたたいたときのログ

* thread #1: tid = 0x9380f, 0x0000000196863bdc libobjc.A.dylib`objc_msgSend + 28, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x110000)
    frame #0: 0x0000000196863bdc libobjc.A.dylib`objc_msgSend + 28
    frame #1: 0x000000018988d398 UIKit`-[UIApplication sendAction:to:from:forEvent:] + 96
    frame #2: 0x0000000189876474 UIKit`-[UIControl _sendActionsForEvents:withEvent:] + 612
    frame #3: 0x000000018988cd34 UIKit`-[UIControl touchesEnded:withEvent:] + 592
    frame #4: 0x000000018988c9c0 UIKit`-[UIWindow _sendTouchesForEvent:] + 700
    frame #5: 0x0000000189885efc UIKit`-[UIWindow sendEvent:] + 684
    frame #6: 0x0000000189859120 UIKit`-[UIApplication sendEvent:] + 264
    frame #7: 0x0000000189afa2b8 UIKit`_UIApplicationHandleEventFromQueueEvent + 15424
    frame #8: 0x0000000189857634 UIKit`_UIApplicationHandleEventQueue + 1716
    frame #9: 0x0000000184d98240 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24
    frame #10: 0x0000000184d974e4 CoreFoundation`__CFRunLoopDoSources0 + 264
    frame #11: 0x0000000184d95594 CoreFoundation`__CFRunLoopRun + 712
    frame #12: 0x0000000184cc12d4 CoreFoundation`CFRunLoopRunSpecific + 396
    frame #13: 0x000000018e5df6fc GraphicsServices`GSEventRunModal + 168
    frame #14: 0x00000001898bef40 UIKit`UIApplicationMain + 1488
  * frame #15: 0x00000001000419f0 advicebook`main + 140 at AppDelegate.swift:12
    frame #16: 0x0000000196efaa08 libdyld.dylib`start + 4
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+1

 その1

なぜUINavigationControllerを挟んでいるのでしょうか?

let modalView = ModalViewController()
// 画面遷移.
self.present(modalView, animated: true, completion: nil)

これでダメですか?

 その2

ViewControllerからpresentして下さい。
cellじゃダメです。

 その3

タップ後の処理を、CollectionViewCell1の中ではなく、ViewControllerに書いて下さい。
セル内のボタンだからといって、セルの中にタップ処理を書く必要はありません。

 その4

xibのFile's OwnerのCustom ClassにViewControllerを設定した後、xibのボタンからActionを作成して下さい。

 その5

ボタンイベントをコードで追加します。
setCellを呼んでいる前後(どっちでもいいです)に、下記のコードを追加して下さい。
(xib上で繋いだActionや、その4で設定したCustom Classは削除して下さい)

cell1.button.addTarget(self, action: #selector(ViewController.modalView(_:)), for: .touchUpInside)

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/02/13 16:46

    ご回答ありがとうございます。
    UINavigationControllerは、色々と試行錯誤しているときにそのまま消し忘れていました。

    ご回答にある部分をViewControllerに記述し、
    xibに設置したボタンが押されたら、カスタムセルクラスからViewControllerのpresentが書かれたメソッドを呼ぶようにしました。

    しかし、ボタンをタップするとエラーになってしまいます。
    ViewControllerクラスのメソッドに書いたprint文は実行されています

    エラー内容
    ```
    Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'UICollectionView must be initialized with a non-nil layout parameter'
    ```

    初回表示時にレイアウトの設定をしていますが、その設定が反映されていなくてエラーになっているのでしょうか?

    キャンセル

  • 2017/02/13 16:51

    ModalViewControllerの親クラスは何でしょうか?

    キャンセル

  • 2017/02/13 17:04

    UIViewControllerクラスです。

    キャンセル

  • 2017/02/13 17:08

    「カスタムセルクラスからViewControllerのpresentが書かれたメソッドを呼ぶようにしました」のコードを書いて下さい。

    キャンセル

  • 2017/02/13 17:41 編集

    ※質問に追記のため削除

    キャンセル

  • 2017/02/13 17:44

    ここに書かないで下さい。見にくいです。

    キャンセル

  • 2017/02/13 18:01

    失礼しました。
    質問に追記しました。

    キャンセル

  • 2017/02/13 18:34

    こっちのコードは削除して下さい。見にくいです。

    で、セルでViewControllerのインスタンスを新たに生成していますが、それではダメです。すでにあるViewControllerのインスタンスに対してmodalView()を呼ばないといけません。

    キャンセル

  • 2017/02/13 19:01

    > ViewControllerのインスタンスに対してmodalView()を呼ばないといけません。

    これを実現するにはどのようにすれば良いでしょうか?
    調べてみましたが、よくわかりませんでした。

    キャンセル

  • 2017/02/14 09:41

    その3を書きました。
    元のActionを削除するのを忘れずに。

    キャンセル

  • 2017/02/14 16:21 編集

    元のActionを削除しました。
    しかし、xibのボタンをcontrol+クリックで線をViewControllerに持っていっても接続できないのですが、何か設定が必要なのでしょうか?

    キャンセル

  • 2017/02/14 16:37 編集

    xibはほとんど使ったことがないので分かりません。

    キャンセル

  • 2017/02/14 16:47

    xibの、
    ・ViewのCustom Class
    ・File's OwnerのCustom Class
    を教えて下さい。

    キャンセル

  • 2017/02/14 17:09

    > ・ViewのCustom Class
     CollectionViewCell(カスタムセルクラス)
     上記、xibに配置したcollectionviewcellのCustom Classですが、これがViewという認識でよろしいでしょうか?

    >・File's OwnerのCustom Class
     何も書いていません。(NSObjectと薄く書かれています。)

    キャンセル

  • 2017/02/14 17:11 編集

    ちょっとxibってみました。その4を書いたので見て下さい。

    キャンセル

  • 2017/02/14 18:14

    ありがとうございます。
    何度もすみません。


    > xibのFile's OwnerのCustom ClassにViewControllerを設定した後、xibのボタンからActionを作成して下さい。

    こちらの作業のあと、アクションのメソッドにprint("test")と書いてビルドしました。
    しかし、ボタンを押してもコンソールにtestと表示されずに、
    Thread1: EXC_BAD_ACCESS(code=..........
    となって、実機が固まってしまいます。

    キャンセル

  • 2017/02/14 18:16

    どこで落ちているのでしょうか?

    キャンセル

  • 2017/02/14 18:18

    あと、質問内のコードは常に最新にして下さい。

    キャンセル

  • 2017/02/14 18:38

    失礼しました。
    コードはビューコントローラーとカスタムセルクラスを最新の状態にし、クラスの内容を全て書きました。

    落ちる場所はThread1のmainで、AppDelegateクラスにThread1: EXC_BAD_ACCESS(code=..........
    となっております。

    キャンセル

  • 2017/02/14 19:13

    とりあえずですが、register(セルの登録)はviewDidLoadで行って下さい。最初に一度やっておけばいいです。

    続きは明日になります。

    キャンセル

  • 2017/02/14 21:51

    > とりあえずですが、register(セルの登録)はviewDidLoadで行って下さい。最初に一度やっておけばいいです。
    質問のコードを更新しました。


    ありがとうございます。
    よろしくお願いします。

    キャンセル

  • 2017/02/15 09:28

    こちらでは質問のコード(ほぼ)そのままで正常に動作しました。

    下記の回答を参考にして、どこで落ちているか特定して下さい。
    https://teratail.com/questions/30571

    キャンセル

  • 2017/02/15 16:12

    すみません。
    何度も呼んでみましたが、あまり理解できませんでした。

    キャンセル

  • 2017/02/15 16:36

    ・Breakpoint Navigatorを表示(Command+7)
    ・左下の+を押して「Add Exception Breakpoint...」を選択
    ・設定の吹き出しが出ますが何もせずに閉じる(ESCを押す、など)

    これで設定できますので、この状態で実行してみて下さい。

    キャンセル

  • 2017/02/15 17:31

    ご丁寧に有難うございます。

    > 左下の+を押して「Add Exception Breakpoint...」を選択
    この部分で「Add Exception Breakpoint...」という項目がなく、「Exception Breakpoint...」があったのでこちらを選択して実行してみました。
    しかし、エラー内容も全く同じで何も変わりませんでした。

    キャンセル

  • 2017/02/15 17:37

    落ちた後、Console(下部の黒いところ)で、btと打ち込んでEnterを押して表示されるログを教えて下さい。

    キャンセル

  • 2017/02/15 17:44

    質問に追記いたしました。

    キャンセル

  • 2017/02/15 17:52 編集

    接続の切れているAction/Event/Outletの残骸が無いかどうか調べてみて下さい。
    Connections inspectorを表示させておくと良いです。(Option+Command+6)

    昨日、「元のActionを削除しました」と書いていましたが、コードを削除するだけじゃダメですよ。

    キャンセル

  • 2017/02/15 18:23

    調べてみましたが、特に接続が切れていたりはしてないと思います。

    キャンセル

  • 2017/02/15 18:27 編集

    二種類のセルの両方ともタップすると落ちるのでしょうか?

    キャンセル

  • 2017/02/15 18:35 編集

    落ちる方のセルにしかボタンを配置しておりません。

    試しにもう一種類のセルにも配置しましたが、やはり同じように落ちました。。

    キャンセル

  • 2017/02/15 19:10

    ボタンだけではなく、セルなどの他のUIにも残骸が無いか調べてみて下さい。

    キャンセル

  • 2017/02/15 22:48

    全て見ましたが、残骸などは見つけられませんでした。

    ずっと実機でテストしていたんですが、シミュレーターでは動くことが確認できました。
    しっかりとprintの内容がコンソールに出ていました。
    実機のみで固まってしまうようです。。。

    キャンセル

  • 2017/02/15 22:56

    ちなみにiPadの何でしょうか?
    実機と同じ機種のシミュレータではどうなりますか?
    OSのバージョンも教えて下さい。

    あと、実機の方で、一度アプリを削除してから試してみて下さい。

    キャンセル

  • 2017/02/16 09:27

    実機のOSとバージョン
    iPad Air 2
    iOS8.4

    実機と同じシミュレータでも、動きます。
    アプリを一度削除してビルドし直しましたが、実機のみで落ちてしまいます。

    キャンセル

  • 2017/02/16 09:30

    一度クリーンしてみて下さい。
    Shift+Command+Option+K です。

    そろそろネタ切れです。

    キャンセル

  • 2017/02/16 09:46

    8.4だと落ちるのを確認しました。機種は関係ないです。
    ちょっと調べてみます。

    キャンセル

  • 2017/02/16 10:31

    その5を書きました。
    原因が分かりそうにないので、ボタンイベントをコードで追加するようにしました。

    キャンセル

  • 2017/02/16 10:50

    できました!
    printの内容がコンソールに出力されました。

    日をまたいでご指導いただきありがとうございます。
    とても助かりました。

    キャンセル

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

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

関連した質問

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

  • Swift

    7210questions

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

  • Xcode

    4082questions

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