SwiftUI

SwiftUI - View

GREEN.1229 2022. 12. 24. 12:16

안녕하세요. 그린입니다🍏

이번 포스팅에서는 SwiftUI의 View Protocol에 대해 알아보겠습니다🙌

 

SwiftUI로 뷰를 만들면서 꼭 만나는 개념이 있습니다.

바로 View를 채택하는것인데요.

그러니까 이 View는 프로토콜입니다.

이 프로토콜을 별 고민없이 채택하고 뷰를 그려줬었는데 오늘은 이 프로토콜이 어떻게 구성되어 있는지에 대해서 알아보겠습니다.

 

그럼 바로 보시죠🕺🏻

 

View

공식문서에서는 View 프로토콜을 앱 사용자 인터페이스의 일부를 보여주고 뷰를 구성하는데 사용하는 모디파이어 즉 수정자를 제공하는 프로토콜이라고 합니다.

쉽게 정리하면, 뷰를 그리기 위해서 채택하는 프로토콜이라고 이해하고 어떻게 구성되어 있는지 보시죠~!

public protocol View {
  associatedtype Body : View
  @ViewBuilder @MainActor var body: Self.Body { get }
}

공식문서에는 나와 있지 않지만 소스 코드를 들어가보면 View 프로토콜의 정의를 볼 수 있습니다.

연관 타입으로 View 즉, 자신을 Body라고 칭하고 @ViewBuilder와 @MainActor 프로퍼티 래퍼를 지닌 body 프로퍼티를 가집니다.

이 타입은 자신의 View 타입이죠.

결국 이 프로토콜을 채택하면 body 프로퍼티를 구현해야되고 우리는 습관처럼 아래와 같이 구현하고 있었죠.

struct MyView: View {
  var body: some View {
      Text("Hello, World!")
  }
}

MyView 구조체 즉 해당 뷰는 View 프로토콜을 채택하고 프로토콜에서 필요한 body 프로퍼티에 원하는 형태의 뷰 컴포넌트를 나열해 뷰를 만들어주게 되는것이죠.

 

여기서 View 프로토콜에서 @ViewBuilder와 @MainActor 개념이 나왔는데 이 부분을 조금 더 들여다 보겠습니다👀

 

@ViewBuilder

공식문서에서는 뷰빌더를 구조체로 클로저에서 뷰를 구성하는 커스텀 매개변수 속성이라고 소개합니다.

@resultBuilder struct ViewBuilder

정의는 위와 같아요.

여기서 또, @resultBuilder를 사용하는데 이건 또 밑에서 간단히 알아보도록해요.

우선 요약만 해보자면 뷰를 구성하기 위해 들어갈 뷰 컴포넌트들의 배열을 컴마(,) 없이 나열하여 사용할 수 있도록 도와줍니다.

 

마찬가지로 @ViewBuilder에 대해 소스코드에서 확인해보면 아래와 같이 정의되어 있습니다.

@resultBuilder public struct ViewBuilder {
  public static func buildBlock() -> EmptyView
  public static func buildBlock<Content>(_ content: Content) -> Content where Content : View
}

제네릭으로 들어가는 Content는 View 타입으로 해당 뷰를 받아 결국 최종 뷰를 그려주도록 buildBlock 메서드를 이용합니다.

 

결국 우리는 @ViewBuilder를 이용해 View를 구성 시 아래와 같이 컴마 없이 뷰 컴포넌트를 나열해 하나의 원하는 뷰를 만들 수 있어요.

struct MyView: View {
  var body: some View {
    Text("Hello, World!")
      
    Text("Green")
      
    Button(
      action: { },
      label: { Text("Button") }
    )
      
    Image(systemName: "close")
  }
}

 

공식문서에서 buildBlock을 보면 다양하게 존재합니다.

즉, 파라미터로 넘겨주는 뷰의 갯수에 따라서 다양하게 존재하죠.

즉 뷰 컴포넌트의 배열을 가지고 하나의 뷰로 합쳐 만들어주는 역할을 하는것이죠.

추측하기론, 간혹 한 뷰에 너무 많은 뷰 컴포넌트를 혼합하면 아래와 같이 너무 많은 인자를 호출했다는 에러가 납니다.

이 경우가 여기에 정의된 뷰의 갯수를 넘어서지 않을까 생각이 드네요🤔

 

그럼 아주 간단히 아까 짚으려했던 @resultBuilder에 대해 알아 보시죠!

 

@resultBuilder

여기서는 아주 간단히만 알아보고 다른 포스팅으로 조금 구체적으로 알아볼께요!

Swift 5.4에서부터 도입된 개념으로 컴마(,) 없이 배열을 구성하는 기능에 사용합니다.

즉, 해당 프로퍼티 래퍼로 선언하면 필요한 buildBlock 메서드를 정의해야합니다.

@resultBuilder
struct SimpleStringBuilder {
  static func buildBlock(_ parts: String...) -> String {
      parts.joined(separator: "\n")
  }
}

위와 같이 샘플로 보여드린것처럼 받아온 타입들을 합쳐주는것이죠.

해당 메서드가 있기에 컴마(,) 없이도 선언이 가능한것입니다.

결과적으로 다시 SwiftUI로 돌아와서 resultBuilder로 선언된 ViewBuilder를 사용함으로 뷰 컴포넌트들을 컴마(,) 없이 나열하여도 괜찮다는것이죠🙌

 

그럼 이어서 @MainActor에 대해 알아보겠습니다!

 

@MainActor

동시성의 API중 하나로 공식문서에서는 메인 스레드에서 동작을 시켜주도록 해줍니다.

즉 DispatchQueue.main으로 감싸줘서 다루지 않아도 늘 뷰는 메인 스레드에서 동작할 수 있게 해주는것이죠.

뷰의 업데이트는 메인 스레드에서 이뤄져야한다는것은 이미 아실거라 이걸 내포해주는 기능입니다.

@globalActor final actor MainActor

선언은 위와 같습니다.

 

자 그럼 View 프로토콜에 대해 어느정도 구성과 왜 채택하여 사용해야 되는지에 대해 알아봤습니다!

다음 포스팅에서는 조금 더 심층적으로 들어가 왜 SwiftUI에서는 View를 class가 아닌 struct로 만드는지에 대해 알아볼께요!

 

마무리

어느정도 View 프로토콜에 대해 이해가 되었네요!

이번 포스팅에서 조금 미비한 부분들은 다음 포스팅에서 조금 더 심화적으로 다뤄보겠습니다🙌

 

[참고 자료]

https://developer.apple.com/documentation/swiftui/view

 

Apple Developer Documentation

 

developer.apple.com

https://ios-development.tistory.com/1065

 

[iOS - swiftUI] View Protocol (뷰 프로토콜)

목차) SwiftUI의 기본 - 목차 링크 View Protocol View 프로토콜 프로토콜이고, body라는 computed property를 가지고 있는 타입 view를 입력할 수 있게하는 인터페이스를 제공하는 역할 @available(iOS 13.0, macOS 10.15

ios-development.tistory.com

https://developer.apple.com/documentation/swiftui/viewbuilder

 

Apple Developer Documentation

 

developer.apple.com

https://www.hackingwithswift.com/swift/5.4/result-builders

 

Result builders – available from Swift 5.4

Link copied to your pasteboard.

www.hackingwithswift.com

https://developer.apple.com/documentation/swift/mainactor

 

Apple Developer Documentation

 

developer.apple.com