チンチラのフンみたいなもの

毎日の学んだことを書いていきます

ライブラリ「Instructions」で[ERROR] The overlay view added to the window has empty bounds, Instructions will stop.が出た

Instructions」はチュートリアル画面を簡単に作れるようになると言うライブラリである。そのライブラリのREADMEのチュートリアルに従って書いたが、なぜかエラーになる。

import UIKit
import Instructions

class ViewController: UIViewController {

    @IBOutlet var textFieldCollection: [UITextField]!
    @IBOutlet weak var sumResultLabel: UILabel!
    let coachMarksController = CoachMarksController()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.coachMarksController.dataSource = self
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.coachMarksController.start(in: .window(over: self))
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        self.coachMarksController.stop(immediately: true)
    }

    @IBAction func tappedSumButtom(_ sender: Any) {
        sumResultLabel.text = String(textFieldCollection.compactMap{Int($0.text!)}.reduce(0,+)
    }
    
}

extension ViewController:CoachMarksControllerDataSource,CoachMarksControllerDelegate{
    func numberOfCoachMarks(for coachMarksController: CoachMarksController) -> Int {
        return 1
    }
    
    func coachMarksController(_ coachMarksController: CoachMarksController,
                              coachMarkAt index: Int) -> CoachMark {
        return coachMarksController.helper.makeCoachMark(for: sumResultLabel)
    }
    
    func coachMarksController(
        _ coachMarksController: CoachMarksController,
        coachMarkViewsAt index: Int,
        madeFrom coachMark: CoachMark
    ) -> (bodyView: UIView & CoachMarkBodyView, arrowView: (UIView & CoachMarkArrowView)?) {
        let coachViews = coachMarksController.helper.makeDefaultCoachViews(
            withArrow: true,
            arrowOrientation: coachMark.arrowOrientation
        )

        coachViews.bodyView.hintLabel.text = "Hello! I'm a Coach Mark!"
        coachViews.bodyView.nextLabel.text = "Ok!"

        return (bodyView: coachViews.bodyView, arrowView: coachViews.arrowView)
    }
    
}

このコードはアプリ道場サロンの課題で書いたものにお試しでInstructionsを当てはめたもの。エラーの文章には「[ERROR] The overlay view added to the window has empty bounds, Instructions will stop.とある。日本語にすると「ウィンドウに追加されたオーバーレイビューの境界が空であるため、命令が停止します。」イマイチよくわからん。このエラーメッセージはこのライブラリで定義されているものなので、エラーメッセージで検索して定義を見てみる。

// The delegate might have paused the flow, we check whether or not it's
        // the case.
        if !self.isPaused {
            if coachMarksViewController.instructionsRootView.bounds.isEmpty {
                print(ErrorMessage.Error.overlayEmptyBounds)
                self.stopFlow()
                return
            }

            coachMarksViewController.show(coachMark: &currentCoachMark!, at: currentIndex) {
                self.canShowCoachMark = true

                self.delegate?.didShow(coachMark: self.currentCoachMark!,
                                       afterChanging: change, at: self.currentIndex)
            }
        }

この中のoverlayEmptyBoundsがこのエラーメッセージを定義つけている定数。なのでこの部分で引っかかってデバッグエリアにエラーメッセージが出ている。見た感じだとコーチマークの描写がそもそもできて無さそうなのでcoachMarksViewControllerがそもそもインスタンス化できていないのではと思った。そこでブレークポイントを使って中身を見てみたが普通に出来てた。

原因がわからず、READMEをもう一度読み直しているとあることに気づく。僕のコードだとviewWillAppearに書いている部分をREADMEではviewDidAppearに書いているということを・・・・!僕がviewWillAppearに書いたのは理由があります。それはREADMEのこの部分

Be careful, you can't call start in the viewDidLoad method, since the view hierarchy has to be set up and ready for Instructions to work properly.

viewDidAppearとしか書いてないもん・・・。ならの次のviewWillAppearに書こうとなるのが普通の発想だと思うが、viewWillAppearじゃダメだった。READMEではviewDidAppearがきちんとが使われいた。結局上のコードも

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.coachMarksController.start(in: .window(over: self))
    }

override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        self.coachMarksController.start(in: .window(over: self))
    }

に直したら普通に動いた😅 ちょっとREADMEに問題があるじゃねえの?と思うのでisseで問い合わせてみたいと思います!この件については次回!