UIView를 상속받은 view class가 인스턴스화될 때, CALayer가 함께 인스턴스화 됩니다. 그 이유는 UIView class가 CALayerDelegate를 채택하고 있기 때문입니다. 따라서 모든 view는 하나의 layer를 갖습니다.
사실 UIView는 스스로를 drawing하는 것이 아니라 layer위에 drawing을 하는 것입니다. view.backgroundColor를 변경하는 것도 사실은 layer의 backgroundColor를 변경하는 것이고 반대로, layer의 backgroundColor를 변경하면 view에 반영이 됩니다. 마찬가지로 view의 frame은 사실 layer의 frame입니다. 즉, 모든 view의 drawing은 layer에서 이루어 집니다.
실제로 view의 대부분의 속성은 layer의 속성에 접근하는 역할을 수행합니다. view가 layer의 '대리자(delegate)' 이기 때문이죠.
layer는 drawing에 있어 UIView의 속성보다 훨씬 더 많은 속성들을 제공합니다. 즉, layer의 속성에 접근 하면 view를 drawing할 수 있는 많은 옵션을 관리할 수 있습니다.
layer는 다른 layer(sublayers)를 포함할 수 있습니다. 이를 이용하여 UIView를 여러 조각으로 쪼갤 수 있고 각각은 objecet로 간주되기 때문에 더욱 효과적으로 drawing을 관리할 수 있습니다. 하나의 파트으로 관리하던 view를 여러 파트로 쪼개어 drawing하고 합치는 개념이라고 이해하시면 되겠습니다.
layer를 사용하면 애니메이션 효과를 컨트롤 할 수 있습니다. CALayer의 'CA'는 Core Animation의 약자입니다. 즉, animation을 정복하기 위해서는 CALayer를 정복해야 합니다.
view는 최대한 다시그려지는 것을 방지합니다. 작업의 효율성을 높이기 위함이죠. 이를 위해 사용하는 것이 bitmap 백업저장소 입니다. view가 layer위에 그려지면 layer는 이를 캐싱하여 bitmap 캐쉬에 저장하였다가 재사용합니다. view의 경계가 변경되면 캐쉬된 layer의 이미지를 확장시키거나 재배치하는 방식으로 재사용합니다.
만약 view에 표시될 content를 수정하고 redraw를 하고 싶다면, setNeedsDisplay() method를 호출해줍니다. setNeedsDisplay()를 호출하면 caching되어있는 것을 삭제하고 redraw된 결과를 다시 caching합니다.
contentMode의 Scale to Fill, Aspecti Fit, Aspect Fill 등은 모두 bitmap 캐쉬를 이용한 방식입니다.
class SomeView: UIView {
override class var layerClass: AnyClass {
return CustomLayer.self
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let firstLayer = CALayer()
firstLayer.backgroundColor = UIColor.red.cgColor
firstLayer.frame = CGRect(x: 111, y: 111, width: 132, height: 194)
let secondLayer = CALayer()
secondLayer.backgroundColor = UIColor.blue.cgColor
secondLayer.frame = CGRect(x: 41, y: 56, width: 132, height: 194)
let thirdLayer = CALayer()
thirdLayer.backgroundColor = UIColor.green.cgColor
thirdLayer.frame = CGRect(x: 43, y: 197, width: 132, height: 194)
self.view.layer.addSublayer(firstLayer)
firstLayer.addSublayer(secondLayer)
self.view.layer.addSublayer(thirdLayer)
}
}
위의 예에서는 하나의 view와 3개의 layer를 이용하여 아래 그림과 같이 view가 3개인 듯 한 화면을 구현해보았습니다. 여기서 firstLayer와 thirdLayer는 sibling관계에 있고 secondLayer는 firstLayer의 sublayer입니다.
만약에 여기서 새로운 view를 self.view에 addSubview() 하게 되면 주의할 점이 생깁니다. 이 경우 superView 혹은 superLayer 경계에서 sub객체를 자를 것인지 말 것일지 정할 때, layer.maskToBounds를 쓸지 view.clipsToBounds를 쓸지 구분해야한다는 점입니다. layer가 곧 View는 아니지만 View에는 무조건 layer가 있습니다. view의 기본 layer로 이미지절단이 가능하면 clipsToBounds를 사용해도 무방하지만 그렇지 않은 경우에는 반드시 layer.maskToBounds를 사용해야합니다. 즉, 정리하면 View가 있는 layer에서 작업한다면 view.clipsToBounds를 사용해도 무방하지만 View가 없는 layer라면 layer.maskToBounds를 사용해야합니다.