
SwiftUI 프레임워크를 사용하면서, UIKit 프레임워크를 사용할 때 ViewController가 어마무시하게 길어지는 문제를 해결했지만,
View를 코딩할 때, 가독성을 고려하는 건 여전히 중요한 문제라고 생각합니다.

다음은 같이 카드 몇개를 보여주는 간단한 작업인데 코드가 매우 복잡하죠??
이렇게 코드를 무조건 늘여놓게 되면 읽기도 힘들고, 유지보수 하기에도 상당히 애를 먹게 될거에요.
struct ContentView: View {
@State var cards = ["♠️", "♣️", "♥️", "♦️"]
let cardShape = RoundedRectangle(cornerRadius: 20)
var body: some View {
VStack {
Text("Card Game")
.font(.bold(.largeTitle)())
.padding()
Spacer()
LazyVGrid(columns: [GridItem(.adaptive(minimum: 80.0))]) {
ForEach(cards, id: \.self) { card in
ZStack {
cardShape
.fill().foregroundColor(.white)
cardShape
.strokeBorder(lineWidth: 3)
Text(card)
.font(.largeTitle)
}
.foregroundColor(.blue)
.aspectRatio(2/3, contentMode: .fit)
}
}
.padding(.horizontal)
Spacer()
}
}
}
그렇다면 View 코드의 가독성을 늘리는 방법에는 어떤 것들이 있을까요?
첫번째, Struct로 View를 객체화 시켜서 사용하기
가장 많이 사용하는 방법은 새로운 view 구조체를 만들어서 이용하는 것입니다.
구조체로 쪼개서 사용하게 되면, 구조체가 가지는 장점들, init의 활용이나 값 자체만 복사된다는 점 등... 을 모두 활용할 수 있습니다.
struct ContentView: View {
@State var cards = ["♠️", "♣️", "♥️", "♦️"]
var body: some View {
VStack {
Text("Card Game")
.font(.bold(.largeTitle)())
.padding()
Spacer()
LazyVGrid(columns: [GridItem(.adaptive(minimum: 80.0))]) {
ForEach(cards, id: \.self) { card in
CardView(cardIcon: card)
}
}
.padding(.horizontal)
Spacer()
}
}
}
struct CardView: View {
var cardIcon: String
let cardShape = RoundedRectangle(cornerRadius: 20)
var body: some View {
ZStack {
cardShape
.fill().foregroundColor(.white)
cardShape
.strokeBorder(lineWidth: 3)
Text(cardIcon)
.font(.largeTitle)
}
.foregroundColor(.blue)
.aspectRatio(2/3, contentMode: .fit)
}
}
다음과 같이 CardView 처럼 View구조체를 하나 만들어서 활용할 수 있습니다.
두번째, view 구조체 내부에 연산프로퍼티를 통해 view를 생성하기
view를 구조체를 통해 새로 생성하는 게 부담스러울 때, 혹은 간단히 해당 구조체 안에서 재사용하기 위한 view를 만들 때,
연산 프로퍼티를 통해 view 변수를 생성해서 사용할 수 있습니다.
struct ContentView: View {
@State var cards = ["♠️", "♣️", "♥️", "♦️"]
let cardShape = RoundedRectangle(cornerRadius: 20)
var body: some View {
VStack {
Text("Card Game")
.font(.bold(.largeTitle)())
.padding()
Spacer()
LazyVGrid(columns: [GridItem(.adaptive(minimum: 80.0))]) {
ForEach(cards, id: \.self) { card in
ZStack {
cardView
Text(card)
.font(.largeTitle)
}
}
}
.padding(.horizontal)
Spacer()
}
}
var cardView: some View {
ZStack {
cardShape
.fill().foregroundColor(.white)
cardShape
.strokeBorder(lineWidth: 3)
}
.foregroundColor(.blue)
.aspectRatio(2/3, contentMode: .fit)
}
}
다음과 같이 View 변수를 구조체 안에 선언한 후, 이를 손쉽게 이용할 수 있습니다.
다만 연산 프로퍼티인 만큼, 변하지 않는 View의 모양을 이용하려고 할 때 사용하시면 됩니다.
세번째, Extension 활용하기
View 구조체가 변수를 너무 많이 가지게 되거나, 구조체 내부가 너무 복잡해졌을 때,
다음과 같이 Extension을 이용해서 변수와 View를 분리하여 정리함으로서 가독성을 향상시킬 수 있습니다.
struct ContentView {
@State var cards = ["♠️", "♣️", "♥️", "♦️"]
let cardShape = RoundedRectangle(cornerRadius: 20)
}
extension ContentView: View {
var body: some View {
VStack {
Text("Card Game")
.font(.bold(.largeTitle)())
.padding()
Spacer()
LazyVGrid(columns: [GridItem(.adaptive(minimum: 80.0))]) {
ForEach(cards, id: \.self) { card in
ZStack {
cardView
Text(card)
.font(.largeTitle)
}
}
}
.padding(.horizontal)
Spacer()
}
}
var cardView: some View {
ZStack {
cardShape
.fill().foregroundColor(.white)
cardShape
.strokeBorder(lineWidth: 3)
}
.foregroundColor(.blue)
.aspectRatio(2/3, contentMode: .fit)
}
}
이렇게 이용하면 복잡한 구조체에서 View와 비즈니스로직을 구분하여 이용할 수 있습니다.
'iOS 개발 > SwiftUI' 카테고리의 다른 글
[SwiftUI] @escaping에 대해서 (2) | 2022.04.11 |
---|---|
[SwiftUI] inout은 어떻게 작동하는가 (C언어의 Call by Reference와 비교) (0) | 2022.03.21 |
[SwiftUI] Generics 타입 제약 (Type Constraints) 다루기 (0) | 2022.03.20 |
[SwiftUI] ForEach에서 \.self를 사용하는 이유와 id 중복 문제 해결 방법 (0) | 2022.03.13 |
[SwiftUI] json parsing 방법 (0) | 2022.03.10 |
[SwiftUI] View protocol과 body 변수에 대한 고찰 (some 키워드를 사용하는 이유) (0) | 2022.02.25 |
[Swift UI] @State에 대한 아주 얕은 고찰 (0) | 2021.11.07 |
[SwiftUI] Swift UI에 대한 첫인상 (2) | 2021.11.07 |