Apple Developer 문서에 표현된 SwiftUI 탐방
https://developer.apple.com/documentation/swiftui
해당 글은 wanted 프리온보딩 iOS 챌린지 8월 을 통해 진행된 yagom 님의 강의를 계기로 작성하였습니다!
좋은 내용을 알려주신 wanted와 yagom님께 감사의 말씀을 드립니다!!🙌
UPDATE : 2023-08-10 00:16
SwiftUI 는 Framework 형태로 만들어졌습니다.
모든 플랫폼에서 앱의사용자 인터페이스 및 동작
을선언
한다고 표현합니다.
SwiftUI는 UI로 표시되는
사용자 인터페이스
를 표시하고,사용자의 인터렉션
을 받아올 수 있는 기능들을 모두 제공하며,하나의 Framework
로 묶여서 제공된다 라고 볼 수 있겠습니다!
SwiftUI로 앱을 만들기 위해서는
App
프로토콜로 정의가 필요하며 각 UI 요소들은View
프로토콜을 준수해야 한다고 볼 수 있겠습니다.
그리고 중요한 부분은 각 View의modifier
를 사용하여 커스터마이징을 할 수 있다는 부분이였습니다! 일종의 함수형 프로그래밍처럼 여러 modifier를 거치는 형태로 제공되네요!
그리고 여러 View들을compose
하여 UI를 구성한다 라는 표현도 중요합니다.
다행이도 기존의UIKit
프레임워크 및AppKit
,WatchKit
과도 같이 사용할 수 있게 만들어졌다고 볼 수 있겠습니다.
그리고accessibility
를 지원하기에 국가 또는 문화 지역에 따른 현지화할 수 있습니다.
이렇게 SwiftUI를 정의한 내용을 살펴봤는데, UI를 제공하는 Framework 형태이며 추가적으로 App
프로토콜과 View
프로토콜을 알아봐야겠죠?
그리고 각 View들의 modifier
들이 중요하다고 보여집니다!
그러면 이제 하나하나 탐방을 해보겠습니다.
https://developer.apple.com/documentation/swiftui/app
앱의 구조와 동작을 나타내는 protocol 입니다.
위 코드 형태처럼 App 프로토콜을 준수하는 형태로
앱 프로젝트
를 생성할 수 있습니다. UIKit의 AppDelegate와 같은 역할이라고 볼 수 있겠네요!
그리고body
라는 컴퓨티드 프로퍼티로 앱의content
를 구현할 수 있습니다.
@main
을 선언하여 앱의 entry point(진입점)를 설정할 수 있습니다. 이 진입점은 앱에서 단 하나만 존재해야 합니다!
그리고@main
이 선언된 App 프로토콜은 자동으로main()
메소드를 실행하여default implementation
을 제공합니다.
여기서 default implementation
이 무엇일까요?
제가 이해한 Default Implementation은 쉽게 말해 특정
Protocol
의extension
으로 정의된메소드
를 Protocol 채택으로 사용할 수 있는것을 의미합니다.
class에서 상속을 통해 부모의 메소드를 사용할 수 있는 것과 비슷한 맥락이라고도 볼 수 있죠!
즉, 정리하면 App 프로토콜을 채택함으로써 main() 메소드가 실행되며 이때 main() 동작은 Default Implementation을 통해 동작된다! 라고 이해할 수 있을 것 같습니다!
그러면 위 예시코드처럼 App 프로토콜을 extension하여 main() 메소드를 새롭게 구현할수도 있겠죠? (아마 야곰님께서 말씀하신 부분이 이 부분이지 않을까 생각합니다!)
그러면 main()
메소드도 한번 살펴볼까요?
https://developer.apple.com/documentation/swiftui/app/main()
앱을 초기화하고 실행하는 메소드입니다
위에서 살펴본대로 @main 이 선언된 App 프로토콜로 자동으로 앱을 실행하는 main() 메소드가 실행됩니다.
여기서 중요한점은 SwiftUI는플랫폼에 적합한 방식의 default implementation을 제공
한다고 합니다!
iOS, iPadOS, macOS, 그리고 새롭게 나올 visionOS 등 각 플랫폼별 앱 실행을 위한 동작이 App 프로토콜을 채택함으로써 알아서 실행된다고 볼 수 있겠네요!
App 프로토콜을 알아보다가 Default Implementation, 그리고 main() 메소드로 잠깐 빠졌죠!
다시 App 프로토콜 부분을 이어서 살펴보겠습니다!
https://developer.apple.com/documentation/swiftui/app
위에서
body
라는 컴퓨티드 프로퍼티로 앱의 content를 구현할 수 있다고 봤는데요, 이 body는Scene
프로토콜을 준수하여 구성됩니다.
각scene
은 view 계층구조의root view
와 시스템에서 관리하는life cycle
을 지니고 있다고 합니다
또한앱이 공통적으로 다루는
documents 나setting
와 같은 contrete scene 타입들도 제공한다고 합니다!
Scene 프로토콜을 채택하여 custom scene도 만들 수 있겠네요!
여기서 Scene
프로토콜도 좀 더 살펴봐야겠죠? 그리고 WindowGroup
으로 여러 Secne들을 제공할 수 있는 형태로도 보이네요!
https://developer.apple.com/documentation/swiftui/scene
시스템에서 관리하는
life cycle
이 존재하는 앱의 UI 단위라고 볼 수 있겠습니다!
App 프로토콜의 body 내에서 Scene 프로토콜을 준수하는
하나 이상의 scene 들을 결합
하여 앱을 만든다고 합니다! 이때 통상 내장된WindowGroup
을 사용하겠지만, Scene 프로토콜을 채택하여 새롭게 custom scene을 반환할수도 있습니다.
저희는 custom scene을 만들 단계가 아니므로 여기까지만 확인해보고 다음으로 WindowGroup
프로토콜을 살펴보겠습니다!
https://developer.apple.com/documentation/swiftui/windowgroup
동일하게 구성된
window
들의group
을 나타내는scene
입니다.
앱의
view hierarchy
의container
로써WindowGroup
을 사용합니다.
WindowGroup 내에 선언된view hierarchy
는 생성되는 window 별 탬플릿이 됩니다.
말이 어렵죠? 여기서 window
는 쉽게말해 창
이라고 이해할 수 있어요!
아이폰의 경우는 앱을 하나의 창에서 실행하는 식이지만, 아이패드나 맥에서는 같은 앱이여도 여러 창
을 띄우거나, 탭
들을 띄울 수 있잖아요?
그때 각 window별로 화면이 표시되는 기본세팅
이 바로 WindowGroup 내 선언된 view hierarchy, 즉 View
라고 볼 수 있겠습니다!
view hierarchy 라고 표현한것은 View를 예시코드처럼 MailViewer()
처럼 하나의 View로 표현할수도 있지만
VStack {
Text("Hello")
.font(.title)
Text("World")
.font(.subtitle)
}
이런식으로 계층구조가 있는 View도 WindowGroup 내 명시할 수 있다는 의미인 것 같아요!
아까 말한대로 iPadOS나 macOS에서는 동시에 둘 이상의 창을 열 수 있기에 WindowGroup 형태로 제공한다고 볼 수 있겠습니다!
그리고 SwiftUI는 이런 플랫폼별 동작을 자동으로 처리해주죠!
추가로, iPadOS에서 여러 창을 동시에 표시하려면
UIApplicationSupprotsMultipleScenes = true
여야 한다고 합니다.
각
window
들은독립적인 상태 및 스토리지
를 지닌다고 합니다!
@state나 @stateObject 등과 같은 스토리지들을 개별적으로 할당하여 유지된다고 합니다!
그리고 Document 기반 앱인 경우DocumentGroup
을 사용하여 window를 정의하라고 합니다.
정리해보면, SwiftUI는 Framework로 제공되는데 App 프로토콜을 통해 플랫폼별 앱 실행동작을 자동으로 설정해주고, UI를 만들어 WindowGroup으로 묶으면 플랫폼별로 자동으로 여러창을 지원하거나 창별 독립적인 기능들을 제공한다고 볼 수 있겠습니다!
SwiftUI을 알면 알수록 애플의 여러 플랫폼을 모두를 아우를 수 있으며 매우 쉽고 간단하게 앱을 제작할 수 있는 FrameWork 라고 보여집니다!!
이렇게 WindowGroup을 통해 window 관리와 window별 독립적으로 제공이 된다는 것을 알 수 있었습니다!
그러면 Scene 프로토콜을 이어서 살펴보겠습니다!
https://developer.apple.com/documentation/swiftui/scene
위에서 살펴본대로
App
프로토콜의body
컴퓨티드 프로퍼티 내에서Scene
프로토콜을 준수하여 만든 scene들로 앱을 구성합니다.
이때 scene은 UI로 표시되는view hierarchy
의컨테이너
역할을 합니다!
그리고 SwiftUI는 플랫폼에 따라, 앱의 현재 상태에 따라, 언제 그리고 어떻게 UI를 표시할것인지 결정한다고 합니다!
쉽게 말해 WindowGroup 내 명시된 View
로 UI
를 표시하고, 해당 UI가 플랫폼별로 아이폰의 경우는 전체 화면을, 그 외의 경우는 여러 창을 생성하거나 제거할 수 있다고 볼 수 있겠습니다!
이때 여러창들은 개별적으로 scene으로 상태와 스토리지를 독립적으로 지니도 있다는 것이죠!
이 모든것을 Scene 프로토콜을 채택하면 SwiftUI가 알아서 플랫폼별로 지정된 UI를 표시해주는 역할을 하고 있는 것이죠!
@Emvironment
프로퍼티래퍼를 사용하여scenePhase
값을 통해scene의 활성상태
, 또는 다른 상태인지를 확인할 수 있습니다!
또한 Scene 프로토콜은
modifier
를 제공합니다.
예를들어.onChange(of: poerform:)
modifier를 통해 scenePhase 값의 변화를 수신할 수 있죠!
해당 예시코드는 scenePhase 값이 background가 되었을 때 캐시를 비우고 있습니다!
여기까지가 Scene 프로토콜의 내용이였습니다!
정리하면 Scene은 life cycle이 존재하는 단위이자 view heirarchy의 컨테이너 역할이자 플랫폼별로 여러 창을 생성할 수 있는 경우 scene별로 독립적으로 상태와 스토리지를 지니고 있으며, @Environment(.scenePhase)를 통해 활성상태 여부를 확인할 수 있습니다!
일종의 UIKit의 SceneDelegate 역할도 같이하고있는 것 같네요!
이제 Secne 프로토콜을 알아봤으니, 진짜 마지막으로 App 프로토콜의 나머지 부분들도 확인해보겠습니다!
https://developer.apple.com/documentation/swiftui/app
App 프로토콜 내에서
@StateObject
와 같은 프로퍼티래퍼를 통해 앱 내 모든 scene에서 공유할 수 있는 데이터 모델을 설정할 수 있습니다!
데이터 모델의 공유는environmentObject
방식과observedObject
방식을 통해 전달 및 접근할 수 있습니다.
여기서
하위 View에서 상위 View의 데이터 모델을 접근하는 방법인 environmentObject
방식과
하위 View 내 선언된 변수로 접근하는 방법인 observedObject
방식이 있습니다.
두 방법 모두 ObservableObject
프로토콜을 채택한 데이터 모델의 변화를 감지하여 접근할 수 있습니다!
더 자세한 내용은 EnvironmentObject 내용과 ObservedObject 내용을 추가로 보면 되겠습니다!
이렇게 SwiftUI를 정의한 애플공식문서를 탐방해봤는데.. 역시 애플이 제일 잘하는 여러 플랫폼을 서로 넘나드는 시스템의 장점이 SwiftUI에도 녹아져있다고 느꼈습니다.
하나의 SwiftUI 프레임워크를 사용하여 특정 프로토콜을 채택하는 것 만으로도 Default Implementation 을 통해 각 플랫폼별로 특화되어 제공된다는 점이 정말... 애플답다 라는 느낌이 들었습니다ㅎㅎ
그리고 저희는 이제 View라는 프로토콜 형식으로 반환되는 것들을 compose 하여 UI를 구현하면 되는 것이죠!
단순히 UI 구현하는 방법을 익히는 것을 넘어서 애플이 어떤것들을 생각하여 SwiftUI를 개발했는지를 알 수 있었다고 생각합니다!
그리고 View 프로토콜을 통해 UI를 구현하는 내용은 SwiftUI / View 글을 이어서 보시면 되겠습니다!