Swift 프로토콜
낯선 언어를 매일 학습하며 몰입과 성장을 기록하는 일지
· 4 min read
프로토콜 #
Java의 interface와 유사- 메서드, 프로퍼티 등의 정의만 존재, 구현부는 존재하지 않음
Java Interface와의 차이
- Java Interface는 필드를 가질 수 없지만, Swift Protocol은 프로퍼티 요구사항 명시 가능
- { get }: 읽기 전용 프로퍼티
- { get set }: 읽기/쓰기 모두 필요
- Protocol Extension
- extension 키워드를 사용해 프로토콜을 확장, 기본 구현을 제공 가능
protocol Brake {
func applyBrake()
}
// 프로토콜 확장으로 기본 구현 제공
extension Brake {
func stop() {
print("Engine Stopped")
}
}
class Car: Brake {
func applyBrake() {
print("Brake Applied")
}
// stop()은 구현하지 않아도 extension에서 제공됨
}
ObservableObject #
- SwiftUI에서 해당 객체 상태 변경 시 View를 자동으로 업데이트되도록 알려주는 역할
- Property Wrapper인
@Published를 이용하여 해당 프로퍼티가 변경 시 View에게 자동으로 변경을 알리게 됨
Async #
async 패턴 #
await MainActor.run {
self.isLoading = true
self.errorMessage = nil
}
- MainActor는 UI 스레드이며 Main Thread임
- IOS에서는 UI 업데이트는 반드시 Main Thread에서 해야 됨
- 즉 MainActor.run은 Main Thread에서 실행하라는 의미
do-try-catch #
do {
try
} catch {
}
- try await 부분은 비동기 함수이면서 에러를 던질 수 있는 부분임
if let result = try await ~~를 통해 옵셔널 바인딩 사용- 옵셔널 바인딩을 통해 링esult는 nil이 아님을 보장됨
- @Published 프로퍼티를 업데이트하면 자동으로 View가 리렌더링
함수 #
func setWinningNumbers(_ input: String){}
_를 통해 외부 파라미터 이름 생략 가능(라벨 생략)
guard #
guard numbers.count == LottoConstants.lotteryNumberSize else{return}
/*
Java Code
if(numbers.size() != LOTTERY_NUMBER_SIZE){
return;
}
*/
guard는 조건이 false면 빠지는 Early return 패턴
func matchCount(for ticket: LottoTicket) -> Int {
guard !winningNumbers.isEmpty else {return 0}
}
/*
Java code
int matchCount(ticket){
if(winningNumbers.size()){
return 0;
}
....
}
*/
Intersection #
- Swift의 Set은 Intersection 연산 가능
- 당첨 번호와 내 로또 번호의 Intersection의 size를 통해 당처 결과 판단 가능
View 구조체 #
- Swift의 View는 대부분 struct로 생성
- View는 immutable이 추천됨
- struct는 값 타입이라 복사가 가벼움
- : View 프로토콜을 사용
@StateObject #
@StateOBject는 ViewModel의 lifecycle을 관리하는 Property Wrapper@StateObject는 View가 생성될 때 한 번만 ViewModel을 만들고, View가 사라질 때까지 유지@ObservedObject와의 차이는@StateObject는 ViewModel을 소유하지만 전자는 외부에서 받은 ViewModel을 관찰@State는 간단한 값 저장을 위한 Property WrapperView 내부에서만 사용
값 바뀌면 View 리렌더링
@StateObject는 복잡한 객체에 사용, 간단한 값은@State@ObservableObject를 따르는 객체를 가질 때 사용
some View #
- Opaque Type(불투명 타입)
- 어떤 View인지는 모르나, View Protocol을 따르는 것을 반환
- 와일드카드처럼 복잡한 타입(
VStack<TupleView<...>>)를 간단히some View로 줄임
Button #
Button("display_text") {
// code
}
- 버튼 괄호 안에 있는 코드는 버튼 터치 시 실행될 코드를 의미
- 이 때 괄호는 후행 클로저임
Button("display_text", action : {
print()
})
- 이름을 쓰고 클로저를 넣어야 하나, 후행 클로저(Trailining Closure)를 사용하여, 마지막 매개변수가 클로저인 경우, 소괄호 밖으로 빼서 사용 가능
ForEach #
- 배열의 요소가 Identifiable protocol을 따라야 사용 가능
ForEach(viewModel.tikets) { ticketi in
// make View by each element
}
ID of ForEach #
ForEach(viewModel.winningNumbers, id: \.self) { number in
}
id: \.self는 Idenfiable을 따르지 않는 리스트일 때 사용 가능id: \.self를 통해 값 자체를 ID로 사용하라는 의미- 단, 배열에 중복이 있으면 ID가 중복되기류때문에 오류
Binding #
TextField("복권 당첨 번호를 입력하세요", test: $inputNumber)
$inputNumber는 $를 통해 양방향 바인딩 되어 있음- TextField에서의ㄴ타이핑이
inputNumber를 자동 업데이트 - inputNumber 변경을 통해 TextField가 자동으로 업데이트
Computed Property #
- 형태는 함수와 비슷하지만, 변수처럼 사용
- 원본 형태는
get {}을 사용한 형태임 - Stored propery와 달리 Computed Propery는 메모리에 저장되지 않으므로 호출 시마다 새로 만듦
- 따라서 매번 계산되므로 var로 선언
- 파라미터가 없고, 상태 기반이며, UI 조각이라면 Computed Property 추천
- 파라미터가 있고, 명확한 동작을 하며, 부수 효과가 있다면 함수를 사용해야 함
private var headerSection: some View {
get {
return VStack {
Text("Hello")
}
}
}
private var headerSection: some View {
VStack{
Text("Hello")
}
}
오늘의 포커스 #
- 공식 문서 섹션 또는 학습 주제
- 구현/실험할 기능 또는 예제
- 집중을 위해 설정한 제약 조건(시간, 도구 제한 등)
몰입 로그 #
- 타임 블록별 진행 상황 (예:
09:00-10:30 공식 문서 Section 3.1 정독) - 학습 중 느꼈던 감정 변화와 몰입 유지 전략
- 즉시 실습한 코드 스니펫 요약 또는 결과 스크린샷 메모
문제와 돌파 #
- 오늘 맞닥뜨린 낯선 개념/에러
- 해결 과정에서 참조한 공식 문서/레퍼런스와 핵심 이해 포인트
- 대체 시도나 포기한 접근법까지 기록
배운 점과 인사이트 #
- Swift 문법/프레임워크에서 새롭게 이해한 부분
- 기존 언어/경험과 비교했을 때의 차이점
- 내일 심화하고 싶은 질문 리스트
몰입 지표 체크 #
집중도: ★★★★★ 중 몇 점? 이유를 함께 작성실행 시간: 순수 학습/구현에 쓴 총 시간자기주도성: 오늘 스스로 설계하고 조정한 실험/공부 방법
내일의 도전 #
- 이어서 파고들 Swift 공식 문서 섹션 또는 프로젝트 파트
- 목표 달성을 위해 개선할 몰입 전략 한 가지
- 준비해야 할 자료나 환경 정리
도전 마무리 한 문장 >
낯설수록 더 몰입한다.처럼 오늘 느낀 결심을 문장으로 남겨 보세요.