[iOS] setNeedsLayout & layoutIfNeeded

nnnyeong·2021년 11월 2일
0

iOS

목록 보기
6/11

이게 얼마만의 iOS 포스팅인가.
부끄럽지만 정말 오랜만에 iOS 관련 공부를 다시 시작했고 면접을 겪으며 공부할 필요성을 느꼈던 내용들 위주로 하나씩 공부해보려 한다.
오늘은 UIView 의 위치, 모양 변화를 주면서 차이를 잘 모르고 아무렇게나 사용해왔던, setNeedsLayout()layoutIfNeeded() 메소드에 대해 공부해보았다.




Main Run Loop & Update Cycle

먼저 두 메소드에 대해 알아보기 이전에 Main Run LoopUpdate Cycle 의 개념이 필요하다.

어플리케이션이 실행되면 UIApplication 이 메인 스레드에서 main run loop 를 실행시키게 되고 main run loop 에선 터치 이벤트, 위치 변화, 디바이스 회전 등의 이벤트들을 처리 하게 된다.

이때 이러한 처리 과정은 각 이벤트마다 알맞는 핸들러를 찾아 각 핸들러에게 처리 권한을 위임하는 방식으로 진행되는데 (UIButton 의 터치 이벤트 처리를 @IBAction 이 담당)

이벤트들 처리가 모두 끝난 후 권한이 다시 main run loop로 돌아오는 시점을 update cycle 이라 한다!

즉, update cycle은 어플리케이션이 유저로부터 받은 이벤트들에 대한 핸들링을 진행한 후 다시 main run loop로 권한 및 컨트롤을 반환하는 시점을 말한다!



하지만 main run loop 에서 발생하는 이벤트들에 대한 핸들링은 즉각적으로 그 변화가 반영되는 것이 아니다.

시스템은 layout 이나 position이 변화하는 view들을 체크하고 모든 핸들러가 종료된 후 update cycle 에서 체크해 두었던, 변화가 필요한 view 들의 값을 바꿔주게 된다.

다시말해 view의 layout, position 값을 변경하는 코드의 실행 시점과 실제로 그 변화가 반영되는 시점 사이에 시간차가 발생하게 된다!




UIView Methods

main run loop와 update cycle에 대한 개념이 잡혔다면 uiview 에 내장된 메소드들 중에서 layoutSubviews()와, 오늘 알아볼 두 메소드 setNeedsLayout(), layoutIfNeeded() 를 함께 알아보자!

layoutSubviews()

UIView의 메소드 중 하나인 layoutSubviews()는 호출시 UIView size나 poisition 값을 변화 시켜주는 역할을 하는 메소드이다.

이 메소드를 호출하면 해당 view의 모든 하위 view들을 따라 layoutSubviews()가 재귀적으로 호출되게 되고 자연스레 비용이 큰 메소드임을 알 수 있다. 때문에 직접 이 메소드를 호출하는 것은 지양해야 한다.

이 메소드는 시스템에 의해서 view의 값이 재계산 되어야 하는 시점, update cycle 에 자동으로 호출되게 되고 이를 통해 view의 size, position, layout 등의 값들의 변화가 반영되게 되는 것이다.

이러한 layoutSubviews()를 직접 부르지 않고 update cycle 에서의 호출을 자동으로 예약하는 상황들이 존재하는데

  • View 의 크기를 조절하는 상황
  • Subview 를 추가하는 상황
  • UIScrollView를 스크롤 하는 상황
  • 디바이스 회전 (Portrait, LandScape)
  • View의 auto layout contraint 값 변화

와 같은 상황들이 그러하다! 위와 같은 상황이 발생하면 자동적으로 update cycle 에서 해당 view의 layoutSubviews()가 호출되는 것이다.

하지만 위와 같은 상황 이외에, 수동으로 layoutSubviews() 호출을 예약하는 메소드가 존재하는데 그것이 바로 setNeedsLayout(), layoutIfNeeded() 인 것이다!!



setNeedsLayout()

setNeedsLayout()을 호출하면 해당 view는 재계산이 필요한 view라고 수동으로 체크된다.

비동기적으로 동작하기 때문에 호출 뒤 바로 반환되고 main run loop 가 끝난 뒤 update cycle에 들어갔을 때 값을 재계산해 view의 size, position 등의 값이 변화하게 된다.

적은 비용으로 update cycle 에서 layoutSubviews() 를 예약할 수 있는 메소드이다.



layoutIfNeeded()

layoutIfNeeded() 역시 setNeedsLayout() 와 같이 수동으로 layoutSubviews() 를 예약하는 메소드이다.

하지만 차이점은 setNeedsLayout() 과는 다르게 동기적으로 동작한다는 점이다.

호출시 바로 layoutSubviews() 예약을 실행시켜 변경 사항이 반영되기 때문에 애니메이션과 같은 상황에 사용할 수 있다.

예를 들어 main run loop 에서 어떠한 view가 setNeedsLayout()을 호출 뒤 layoutIfNeeded()를 바로 호출한다면 변경 사항은 그 즉시 반영되기 때문에 update cycle 에서 setNeedsLayout() 호출 시 예약되었던 layoutSubviews()는 호출되지 않게 된다!




결론

setNeedsLayout() 과 layoutIfNeeded() 는 모두 update cycle에서의 layoutSubviews() 호출을 예약하는 메소드 이고 둘은 비동기적, 동기적 작동 차이가 존재하는 것이었다!




Reference

[ios] setNeedsLayout vs layoutIfNeeded

profile
주니어 개발자까지 ☄️☄️

0개의 댓글