SwiftUI Essentials(1)

2019 WWDC - SwiftUI Essentials(1)

SwiftUI기반의 프로젝트를 진행하면서 여전히 UIKit를 사용해야할 상황이 많았습니다.. 우선 ARKit를 사용해야했고 추후에 ARKit를 어떻게 SwiftUI에서 사용하는지도 다루어 보겠습니다.

오늘은 SwiftUI에서 어떻게 UIKit를 통합해서 사용하는지? 그리고 화면 전환은 어떻게 이루어 지는지 또 2019 WWDC에서 발표한 SwiftUI Essentials 를 보고 정리를 해볼까 합니다.

SwiftUI의 목적

image

SwiftUI에서 추구하는 것은 간단합니다. 기본적인 피쳐보다는 우리 개발자들만의 개성을 살릴수 있게 개발하는 것이 목적이라고 합니다.

Views and Modifiers

SwiftUI의 구조

image

SwiftUI에서는 코드에서 조금 차별화를 둡니다. 아래와 같이 위의 구조를 코드로 구현할 수 있습니다.

image

Declarative한 SwiftUI

SwiftUI에서는 위와 같이 얼마나 Declarative(선언형)으로 코드를 작성할 수 있는지 보여줍니다. 아보카도 토스트를 만드는 앱을 예시를 들면서 만약 코드가 Imperative(명령형)으로 작성이 되어 진다면 아래와 같이 복잡하고 많은 시퀀스를 따라야 한다는 것입니다.

사실 함수형 프로그래밍 패러다임을 공부하면서 선언형과 명령형 프로그래밍기법에 대해서 익히 잘 알 고 있습니다. Declarative의 특징을 잘 엿볼 수 있는 SwiftUI의 구조를 통해 많은 장점들을 얻을 수 있다고 합니다.

SwiftUI는 데이터 주도 방식으로 앱 개발을 강조하고 있습니다. User Interface 내의 뷰들은 기본 데이터의 변경에 따른 처리 코드를 작성하지 않아도 뷰가 업데이트 되도록 말입니다. 이런 Binding을 통해 Publisher와 Subscriber 사이의 데이터 흐름을 UI와 가능하게끔 구축을 할 수 있습니다.

예시에서 위의 $표시를 통해 각 UI들의 value를 가져오고 있는 것을 확인 할 수 있습니다. 이처럼 데이터의 Binding의 syntax 또한 SwiftUI에서는 조금 달라진 모습을 볼 수 있습니다.

image

SwiftUI에서는 상태 프로퍼티(state property) 를 제공하고 있습니다. $표시를 통해 설계한 Order 구조체의 quantity 에 대해 Stepper에 객체의 상수값을 Binding을 하고있습니다.

Modifier를 통해 조금더 명확하게

image

fontforegroundColor 등 UI의 프로퍼티등을 변경하는 것도 modifier를 통해 조금더 명확하게 할 수 있습니다. (어떻게 보면 HTML 태그문 같기도 합니다)

이런 modifier를 Chaining하는 것에는 몇가지 이점이 있다고 소개합니다. 아래의 경우 modifier의 위치만 변경했을 뿐인데 보여지는 UI의 결과 값은 전혀 다르게 나오게 됩니다. Text저체의 background Color를 우선적으로 설정하고 난 다음 padding을 늘릴 경우에는 배경 색 적용이 text에 국한되게 됩니다. 하지만 padding을 우선 늘리고 배경색을 적용한다면? 전체 padding에 대한 색상이 변경 되는 것을 확인 할 수 있습니다.

image

image

이는 우리가 원하는 커스텀에 대한 가능성을 조금 더 열어두는것에 이점이 있다고 설명하고 있습니다.

또 한가지 이점에는 아래와 같이 공통이 되는 opacity modifier에 대해 전체 VStack에다 줌으로써 중복을 줄이고 있습니다.

image

image

이로써 얻게 되는 장점은 중복을 줄이는 것은 물론이고 각각의 UI가 자기자신만의 값에 대해 조금더 포커싱할 수 있다고 설명할 수 있습니다.

Building custom views

SwiftUI에서 custom view를 구성할때 UIKit이나 AppKit과는 어떤 차이점이 있는지에 대해서 설명하고있습니다.

우선 아래의 예시를 보면 List를 구성하고 있는 OrderHistory 구조체는 View라는 프로토콜을 상속하고 있습니다.

image

UIKit vs SwiftUI

UIKit 에서는 위와 동일하게 만들려면 어떻게 해야할까요? 우선 Super class 의 UIView 를 상속해야합니다. 그 안에는 UIView를 구성하고 있는 alphabackgroundColor 등을 지정할 수 있는 프로퍼티들이 존재하고 있고 거기다가 우리가 만들 OrderHistory 는 UIView를 상속하고 커스텀 프로피터를 계속해서 추가할 수 있습니다.

image

그럼 SwiftUI에서는 어떻게 다를까요?

image

SwiftUI에서는 기본적으로 Modifer를 통해 추가를 했던 opacitybackground 등 뿐만아니라 OrderHistory 모두 개개인의 View를 상속하고 있습니다. View 프로토콜 상속함으로써 더이상 common storage template를 view에게서 제공할 필요가 없게 됩니다.

SwiftUI View Protocol 과 Primitive View

View Protocol 의 경우 body 프로퍼티를 통해 view의 content나 behavior등을 정의할 수 있습니다.

image

SwiftUI에서 제공하는 Primitive View들입니다. view들의 그 끝에는 아래의 원자적인 가장 작은 단위의 view들이 존재하게 됩니다. 모든 view의 구성들이 말이죠

image-20200520002652926

SwiftUI Data biding

다시 예제로 돌아와서 OrderHistory view 구조체 내부에는 previousOrders 라는 프로퍼티가 존재합니다. 이것은 List에 담을 객체데이터의 배열 형태로 보관하고 있습니다. SwiftUI에서 View는 선언적으로 input을 function의 형태로 선언하게 됩니다. 만약 이 input이 값이 업데이트 될때 SwiftUI는 Fetch된 새로운 body 프로퍼티를 call하게 됩니다 .

image

만약 Cloud에 위에 리스트에 보여진 데이터들이 저장되어있다고 생각해봅시다. 이는 다른 디바이스와 연동이 되어있어서 삭제되고 추가될 수 있습니다. SwiftUI에서는 서버와 연결이 되어있고 이런 데이터들을 요청하여 가져올때 값이 이전과 비교하여 업데이트 되어있으면 앞에서 말했듯이 UI를 자동적으로 fetch된 즉 변경된 데이터들을 반영하여 automatically 하게 변하게 됩니다.

친절하게도 어떤 추가 코드 없이 변경될때의 List가 변경될때의 default한 animation은 탑재가 되어있습니다

결과적으로 SwiftUI에서 이런 persistant render state 와 같이 값이 변경 하는 것에 대해 생각할 필요 없이 그저 현재의 데이터 기반의 코드를 body 안에 추가를 하면 됩니다.

이 모든게 선언적 코드의 장점이 됩니다.

그리고 Modifier를 최대한 활용하여 SwiftUI에서 지향하는 코드의 모습또한 볼 수 있습니다.

image

우선 위의 작업은 AppIcon을 180도 로테이션 하는 구문을 작성했습니다. if-else로 분기를 나누어 .degrees 를 통해 rotate상태를 확인하고 .rotationEffect 라는 SwiftUI 에서 default 로 제공하는 animation modifier를 호출하는 모습입니다.

SwiftUI에서 지향하는 것은 아래와 같이 Modifier에 최대한 condition을 주는 것이고, SwiftUI가 자동으로 변화를 감지 하게 됩니다.

image

그리고 앞에서 List에 Custom Cell을 추가하는 코드를 설명하고 있습니다. 기존의 UIKit에서 작업하는 것과 형식이 상당히 다릅니다. Xib 로 Cell 을 Custom해서 불러오는 과정 또한 없고 단순하게 또다른 Cell View를 만든다음 List에서 데이터를 하나씩 넘겨주어서 Cell을 생성하여 보여지게 됩니다.

image

상당히 코드가 간결한 것을 볼 수 있습니다. 기존의 tableView작업과 비교해보시면 말입니다. 우리는 tableView에 관련된 protocol을 채택하고 성능을 위해 dequeuereusable등을 생각해야 하는 등의 작업이 SwiftUI에서는 존재하지 않습니다.

SwiftUI가 뒤에서 이런 view code의 앱 최적화와 관련된 작업을 개발자가 알게모르게 해줄 것이며 이것은 SwiftUI의 declaratively code의 장점이고 더이상 우리는 최적화된 작업을 추가적으로 해줄 필요가 없게되었습니다!

SwiftUI의 automatically data handling - ForEach

앞에서의 예제에서 List가 데이터를 하나씩 넘기고 Cell을 호출하는 것을 볼 수 있습니다. 그 Cell은 넘겨받은 order 데이터를 통해 body를 생성하고 변경된 List의 Cell을 확인 할 수 있었습니다. 그 Cell에서 넘겨받은 order 객체에서 소금이 포함되어있는지?(includeSalt) 고춧가루가 포함되어있는지?(includeRedPepperFlakes) 를 하나씩 체크하면서 Cell에 우측에 Icon을 삽입하고 있는 작업입니다.

image

하지만 이러한 작업은 결국 객체 자체에 bool 타입의 프로퍼티만 늘릴뿐이고..(왜이렇게 한지는 모르겠습니다.. 극단적인 방법을 보여주는걸까요) 이를 해결하기 위해 SwiftUI에서는 ForEach 를 통해 toppings 라는 배열에 소금, 고춧가루, 후추, 계란 등등의 시퀀스를 담고있는 정보를 하나씩 체크하여 토핑아이콘을 추가하는 것을 볼 수 있습니다.

image

여기서 중요한것은 SwiftUI는 automatically 하게 data chainging을 감지하고 이를 default animation 등으로 대응을하기 때문에 추가적인 코드를 필요로 하지 않는다는 것이 SwiftUI의 장점이라 할 수 있습니다. 아래와 같이 List에 아이콘을 추가하는 것 뿐만 아니라 다크모드에 대한 때응 까지 말입니다.

image

Reference





© 2020. by Gaki

Powered by gaki