しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

UIViewのdraw(rect:)が呼ばれるタイミングを調べてみる

アプリの高速化のため、UIViewのdraw(rect:)が呼ばれるタイミングを調べてみました。

下のように、普通に画面に貼り付ける時はdraw(rect:)が呼ばれました。

import UIKit

class ViewController: UIViewController {
    let myView = MyView(frame: UIScreen.main.bounds)
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.addSubview(myView)
    }
}

class MyView: UIView {
    override func draw(_ rect: CGRect) {
        print("draw")
    }
}

ちなみに貼付け後、すぐにremoveFromSuperviewをしたらdraw(rect:)は呼ばれませんでした。

view.addSubview(myView)
myView.removeFromSuperview()

そのあと更にaddSubviewを呼んだ場合、draw(rect:)が1回だけ呼ばれます。

view.addSubview(myView)
myView.removeFromSuperview()
view.addSubview(myView)

下のように、タイミングをずらしてaddSubviewを呼んだ場合はdraw(rect:)が2回呼ばれます。

class ViewController: UIViewController {
    let myView = MyView(frame: UIScreen.main.bounds)
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.addSubview(myView)
    }
    
    override func viewDidAppear(_ animated: Bool) {
        myView.removeFromSuperview()
        view.addSubview(myView)
    }
}

frameの値を編集した場合はdraw(rect:)は呼ばれません。

override func viewDidAppear(_ animated: Bool) {
    myView.frame.origin.x = 10
    myView.frame.size.width = 10
    myView.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
}

setNeedsDisplayメソッドを呼んだ時もdraw(rect:)が呼ばれます。

myView.setNeedsDisplay()

addSubviewして、直後にsetNeedsDisplayを呼んだ場合は1回だけdraw(rect:)が呼ばれます。

view.addSubview(myView)
myView.setNeedsDisplay()

下のように、親ビューをremoveFromSuperviewしたりaddSubviewした時もdraw(rect:)は呼ばれました。

import UIKit

class ViewController: UIViewController {
    let baseView = UIView(frame: UIScreen.main.bounds)
    let myView = MyView(frame: UIScreen.main.bounds)
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        baseView.addSubview(myView)
        view.addSubview(baseView)
    }
    
    override func viewDidAppear(_ animated: Bool) {
        baseView.removeFromSuperview()
        view.addSubview(baseView)
    }
}

class MyView: UIView {
    override func draw(_ rect: CGRect) {
        print("draw")
    }
}

ただ、親ビューのsetNeedsDisplayを呼んだ時はdraw(rect:)は呼ばれませんでした。

class ViewController: UIViewController {
    let baseView = UIView(frame: UIScreen.main.bounds)
    let myView = MyView(frame: UIScreen.main.bounds)
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        baseView.addSubview(myView)
        view.addSubview(baseView)
    }
    
    override func viewDidAppear(_ animated: Bool) {
        baseView.setNeedsDisplay()
    }
}