[SwiftUI] .id(_:)는 뭐하는 놈인가

Valse·2023년 3월 28일
3

Swift

목록 보기
8/8

.id 모디파이어?


  • 복잡한 레이아웃이나 뷰를 구성하기 전까지는 쓸 일이 많이 없었다. 단순한 State를 관리하거나 기본 애니메이션을 쓸 때도 마찬가지.
  • 그러던 중, 진행중인 프로젝트에서 이상한 에러를 자주 마주치게 되는데... 바로 괴상한 애니메이션(weird animation)과 ForEach, LazyVStack의 조합에서 발생하는 특정 값의 반복으로 인한 보라색 에러이다.
    • 괴상한 애니메이션 예시:

해결법


  • 알고보면 굉장히 간단한 방법으로 해결이 가능하더라. 정답은 .id(_:) 모디파이어를 각 텍스트에 입혀주는 것.
/* at Name, Date Text */
Text("from: **\(eachKnock.sentUserName)**")
  .font(.body)
  .id(eachKnock.sentUserName)
  
Text("\(eachKnock.knockedDate.dateValue().timeAgoDisplay())")
  .font(.subheadline)
  .foregroundColor(Color(.systemGray))
  .padding(.leading, -10)
  .id(eachKnock.knockedDate.dateValue().timeAgoDisplay())
  • 그런데 각 텍스트가 id를 갖는 것이 왜 이상하고 괴상한 애니메이션을 해결해준다는 건가? 이 모디파이어가 뭐하는 놈인데?

.id(_:)의 작동원리


  • 간단히 말하면, .id(_:)가 붙은 뷰들은 해당 id의 값이 변하면 해당 뷰의 identity를 reset한다.

    When the proxy value specified by the id parameter changes, the identity of the view — for example, its state — is reset.
    출처: https://developer.apple.com/documentation/swiftui/view/id(_:)

  • 그럼 뷰의 identity에 대한 내용도 알아야 할 것인데, 해당 내용은 이전 WWDC 영상 내용을 정리한 내 게시글에 일부 담겨있다.

  • 특정 뷰의 id가 명시적으로 주어지지 않을 때, 뷰 계층은 계층 내의 placement에 따라 id를 제공한다(SwiftUI가 자체적으로). 뷰 transition이나 문제가 생기지 않는다면,

  • 위에 공유된 게시글 내용대로, 랜덤한 id는 안정적이지 않기 때문에 동일한 동작을 보장하지 않을 수 있다.

    • UUID().uuidString 같은 id는 뷰가 그려질 "때마다" 새로 생성될 것이고, .id(_:) 모디파이어에 걸리는 모든 뷰는 동적으로 또 다시 id를 갖게 되기 때문에 상당히 이상한 결과를 보인다.
    • 왜냐하면 SwiftUI의 Transition은 새로운 id가 들어올 때 Insertionremoval 을 동작하기 때문이다.
  • 만약 당신이 if절을 통해 2개 이상의 뷰를 분기처리한다고 해보자. 이 경우, 각 뷰는 서로 다른 id를 가지는 뷰 타입으로 SwiftUI에 의해 추론되어 transition을 일으킨다.

  • 흥미로운 사실은 id에 전달하는 값들도 메소드나 삼항연산자로 처리하여 "identity를 건드려서 특정 조건에서만 애니메이션이 작동하도록" 할 수가 있다는 점이다.

  • 내 경우, 간단한 커스텀 Transition을 활용해서 뷰를 구성하면서 id를 이해하는 것이 더 도움이 되었다!

/* Transition 예시코드 */
public let trailingTransition = AnyTransition
		.asymmetric(
			insertion: .move(edge: .trailing),
			removal: .move(edge: .trailing)
		)
	
public let leadingTransition = AnyTransition
		.asymmetric(
			insertion: .move(edge: .leading),
			removal: .move(edge: .leading)
		)

결론

  • id를 명시적으로 주는 게 좋은지, 구조적으로 추론하게 내버려두는 게 좋은지는 당연히 상황에 따라 다를 것이다.
  • 분기처리에 의해 뷰가 분기되는데, 해당 뷰에서 이상한 애니메이션을 보인다면 id를 명시적으로 달아보는 것이 도움이 될 것으로 보인다.

23.03.28.

profile
🦶🏻🦉(발새 아님)

0개의 댓글