
뭐라도 만들어보자는 마음으로 앱 개발을 시작해버렸습니다


위의 강의 2개를 통해 빠르게 문법을 파악한 뒤
국룰 프로젝트인 투두리스트를 만들기로 결정했습니다
아직 배우는 단계에서 기획과 디자인 등의 전체적인 부분은 클로드에게 맡겼습니다 (AI 만세 🙌)
사실상 클로드의 코드를 보면서 각각의 요소를 이해해나갔습니다
결과적으로는 다음과 같이 개략적인 뷰를 완성했습니다

위와 같이 클로드와 함께 만들어나가면서 알게 된 부분들을 정리해보겠습니다
SwiftUI에서 가장 중요하고 이해해야할 부분으로
앱의 사용자 인터페이스를 선언하는데 사용하는 구성요소입니다
프로젝트를 생성하면 다양한 파일이 생성되는데 그 중에서 ContentView라는 파일이 있는데
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Hello, World!")
}
}
위와 같이 View 프로토콜을 따르는 구조체로 선언되어
내부에 body 프로퍼티를 가지고 있어야 합니다
View 프로토콜은 앱 레이아웃에서 뷰를 구성하는 데 사용하는 수정자(modifier)를 제공합니다
수정자는 해당 수정자를 호출하는 뷰 인스턴스를
지정된 특성을 가진 다른 뷰로 래핑하는 방식으로 작동합니다
Text("Hello, World!")
.opacity(0.5)
위와 같이 opacity(_:) 수정자를 추가하면 일정 수준의 투명도를 가진 새 뷰가 반환됩니다
body 프로퍼티는 하나의 뷰만 리턴하기 때문에
여러 개의 뷰를 사용한다면 하나로 묶어주어야 하는데
이때 사용되는 것으로 Stack, Group 등이 있습니다
그 중에 Stack에 대해 알아보겠습니다
Stack에는 다음과 같이 간단하게 3가지 종류가 있습니다

이 3가지 하나씩만 보면 심플하지만
뷰 수정자, Spacer, Divider 뷰를 사용하여 Stack을 결합하면
매우 유연하고 복잡한 레이아웃도 만들 수 있습니다
struct MyView: View {
var body: some View {
VStack(alignment: .trailing) {
Text("Hello, World!")
.font(.title)
Text("Glad to meet you.")
}
.frame(width: 200, height: 300)
}
}
@State는 SwiftUI에서 뷰의 상태(state)를 저장하고 추적하기 위해 사용하는 프로퍼티 래퍼입니다
struct PlayButton: View {
@State private var isPlaying: Bool = false
var body: some View {
Button(isPlaying ? "Pause" : "Play") {
isPlaying.toggle()
}
}
}
State value 값이 변경되면 해당 뷰를 자동으로 다시 렌더링해줍니다
결론적으로
@State는 SwiftUI에서 뷰의 생명주기와 독립적으로 값을 유지하면서
값이 바뀔 때 자동으로 UI를 리렌더링해주는 가장 기본적인 상태 관리 도구입니다
SwiftUI는 상태를 @State로 관리하지만 이 상태는 해당 View 내부에서만 사용됩니다
다른 뷰에서 @State 속성으로 선언된 프로퍼티를 사용한다면 @Binding이 필요합니다
import SwiftUI
struct ParentView: View {
@State private var isOn = false
var body: some View {
ToggleView(isOn: $isOn)
}
}
struct ToggleView: View {
@Binding var isOn: Bool
var body: some View {
Toggle("스위치 상태", isOn: $isOn)
.padding()
}
}
@State를 바인딩으로 넘길 때는 $ 기호를 붙여서 사용합니다
$는 @State가 내부적으로 가지고 있는 Binding 객체를 꺼내는 역할을 합니다
그리고 @Binding 값은 다른 뷰가 소유하고 있으며 해당 뷰는 참조만 합니다
따라서 @State와 달리 @Binding은 초기값을 가질 수 없습니다
struct ContentView: View {
var body: some View {
Text("Hello world!")
}
}
위의 body 프로퍼티를 보면 some이란 키워드가 보이는데
코드를 쓰다 중간중간 보이는 이 키워드에 대해서 알아보자!
some 키워드는 불투명 반환 타입을 정의할 때 사용하는 키워드입니다
그럼 여기서 불투명 반환 타입의 예시를 보겠습니다
func getDog() -> some Animal {
return Dog()
}
위 함수는 Dog라는 타입을 반환하지만 밖에서는 그걸 모릅니다
단, 내부에서는 항상 Dog 하나만 반환해야 합니다
이게 불투명 타입 입니다
some Animal은 Animal을 준수하는 어떤 타입 하나라는 의미입니다
이걸 왜 써야 할까요?
some 키워드가 없다면 SwiftUI에서 body의 타입을 이런 식으로 작성해줘야 합니다
var body: TupleView<(Text, Text)>
매우 귀찮겠죠?
그리고 라이브러리 제작자 입장에서 내부 구현을 감추고 싶을 때 some은 매우 유용합니다
타입을 은닉하고 컴파일 타임 고정함으로서 성능 최적화도 가능합니다
유연함은 줄지만 보안성과 성능은 좋아진다고 볼 수 있겠습니다
뭔가 그때 그때 배우다 보니 아직 덜 맞춰진 퍼즐처럼
완벽하게 이해되지 않는 부분들이 존재합니다
하지만 이전처럼 추상적인 방식이 아닌
실제로 앱을 만들면서 배우다 보니 확실히 전보다 발전할 거라고 믿습니다
View | Apple Developer Documentation
Building layouts with stack views
[Swift] some 키워드 언제 쓰면 좋을까?
State | Apple Developer Documentation
Binding | Apple Developer Documentation
[iOS] SwiftUI - @State, @Binding