読者です 読者をやめる 読者になる 読者になる

酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

UIScrollView#scrollViewDidZoomが呼ばれなくなった

iPhone Swift

Swift 1.xの頃からメンテしているアプリがあって、コンテンツのアップデートを兼ねてSwift 3に更新しました。いきなりSwift 3に上げたのではなくて一応Swift 2.3からのアップデートになります。

そのアプリの、とある画面でズームイン・ズームアウトする機能があるのですが、アプリの更新作業を契機にズーム機能が使えなくなっていました。なかなか仕様が複雑でテストが一番後回しになっていたのもあって発見が遅くなってしまいました。

Xcode 8.2.1のせいなのか?iOS SDKの影響か?と悩んで、StackOverFlowで検索するも「delegateが設定されてないんじゃないか?」という回答のものしか見当たりません。

そこは既に確認済み……。とりあえず現状を把握して何が問題なのかを検証していこうと考えて、ログを仕込んで確認してみました。

//ズームを開始すると呼ばれる
func scrollViewWillBeginZooming(_ scrollView: UIScrollView, 
    with view: UIView?) {
    print(#function)
}

//ズームを終了すると呼ばれる
func scrollViewDidEndZooming(_ scrollView: UIScrollView, 
    with view: UIView?, atScale scale: CGFloat) {
    print(#function)
}

//ズーム中に呼ばれる
func scrollViewDidZoom(_ scrollView: UIScrollView) {
    print(#function)
}

出力されたログは以下のようになっていました。

scrollViewWillBeginZooming(_:with:)
scrollViewDidEndZooming(_:with:atScale:)

本来であればログは下記のように出力されるはず……

scrollViewWillBeginZooming(_:with:)
scrollViewDidZoom
scrollViewDidZoom
scrollViewDidZoom
...
scrollViewDidZoom
scrollViewDidEndZooming(_:with:atScale:)

scrollViewDidZoomが呼ばれずにズーム処理ができていないのがわかりました。

でもなんで急に呼ばれなくなったんだろう?

原因

viewForZooming(in:)でズーム対象のviewが返せていませんでした。

func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
    return view
}

下記のように変更するとズーム機能が正しく動作するようになりました。

//func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
//    return view
//}

func viewForZooming(in scrollView: UIScrollView) -> UIView? {
    return view
}

他の画面でもズーム機能は使っていてSwift 3.0への移行ツールで正しくアップデートできていたようなのですが、該当の画面でだけ変更がかかっていなかったようです。他の画面では動いているからマイグレーションツールがよしなにしてくれたのだと思い込んでいたので原因の発見が遅くなりました*1

まとめ

去年末に書いた記事の中で、引数自体が変更になっているケースについて言及しているにも関わらずハマってしまっていました。

*1:書き方によって正しくSwift 3にアップデートしてくれないのは以前確認しているのですが、自分でチェックマークを外して可能性もあります。