육식하는야채의 개발일지
article thumbnail

이 포스트는 스탠포드 강의를 듣고 공부한 내용을 포스팅했다.

오역과 의역이 있을 수 있다.

 

Stanford CS193p

Access all videos (and course materials like homework assignment write-ups) at https://cs193p.stanford.edu. There is no reason to subscribe to this YouTube channel.

www.youtube.com

 

프로젝트를 설정하고 첫 화면은 위와 같이 보이게 된다.

오른쪽에는 프리뷰로 실시간으로 작업물을 보여주게 된다.

 

 

📌 SwiftUI에서의 구조체

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
        .padding()
    }
}

#Preview {
    ContentView()
}

 

SwiftUI에서 구조체는 매우 중요하다.

거의 모든 것이 구조체이다.

struct ContentView: View

ContentView는 구조체 유형이고 :View는 구조체가 뷰처럼 작동한다는 것을 의미한다.

 


View란?
뷰는 무언가를 그리고 이벤트를 얻을 수 있는 화면의 직사각형 영역이라고 보면 된다.

 

이런 방식을 함수형 프로그래밍이라고 하는데

함수형 프로그래밍 방식의 장점은 구조체에 View라는 변수를 추가하는 것만으로도

View안에 포함된 수많은 기능들을 얻을 수 있기 때문이다.

 

 var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
        .padding()
    }

 

변수 body는 중괄호로 코드를 포함하고 있는데

이 것들을 속성(프로퍼티)이라고 부른다.

이 body의 변수의 값은 어딘가에 저장되지 않고 body가 호출될 때마다 이 코드가 실행된다.

이 것들을 Computed(계산 속성)이라고 부른다. 

계산속성?

계산 속성의 주요 특징은 다음과 같다.

  1. 값을 직접 저장하지 않고, 필요할 때 계산하여 제공한다.
  2. getter와 선택적으로 setter를 가질 수 있다.
  3. 다른 속성의 값을 기반으로 값을 동적으로 계산한다.
  4. 클래스, 구조체, 열거형에서 사용할 수 있다.

📌 Some View

var body: some View

some View는 구체적인 뷰 타입을 숨기고, View 프로토콜을 준수하는 어떤 타입이라는 것만 나타낸다.

some은 Swift의 불투명 타입(Opaque Type)을 나타내는 키워드이다.

왜 사용할까?

  • SwiftUI는 내부 구현 세부사항을 숨기면서도 타입 정보를 유지할 수 있다.
  • 복잡한 뷰 계층 구조를 간단하게 표현할 수 있다.
  • 컴파일러는 실제 타입을 알고 있어 안정성을 보장한다.

📌 구조체를 생성하는 방법

구조체는 레고 벽돌과 비슷하다. SwiftUI 라이브러리에 만들어져 있는 레고 블록을 가져와 작성하면 된다.

이미지 구조체, 텍스트 구조체 모두 가져와서 사용하기만 하면 된다.

구조체를 가져와 이름을 작성하고 생성하기 위해 필요한 파라미터를 입력하면 생성할 수 있다.

그리고 이 구조체들은 뷰처럼 작동한다.

 Image(systemName: "globe")
      .imageScale(.large)
      .foregroundStyle(.tint)
 Text("Hello, world!")

 

1  Image(systemName: "globe")

Image 구조체의 인스턴스를 생성한다

 

2 .systemName

파라미터로 "globe" 시스템 이미지를 지정한다.

 

3 .imageScale(.large)Image

인스턴스에 imageScale 수정자를 적용한다.

이는 새로운 Image 인스턴스를 반환한다.

 

4 .foregroundStyle(.tint)

이전 단계에서 반환된 Image 인스턴스에 foregroundStyle 수정자를 적용한다.

다시 새로운 Image 인스턴스를 반환한다.

 

5 Text("Hello, world!")

Text 구조체의 인스턴스를 생성한다.

 

중괄호 안에 있는 것을 함수라고 보면 된다.

 

📌 Vstack

그리고 Vstack은 함수를 인자 값으로 받아서 출력을 한다.

하지만 위에서는 Vstack의 파라미터가 보이지 않는다.

 

Vstack의 파라미터는 총 3개로 정렬, 간격, 콘텐츠 부분이 있다.

 Image(systemName: "globe")
      .imageScale(.large)
      .foregroundStyle(.tint)
 Text("Hello, world!")

이 코드를 넣어서 콘텐츠 파라미터의 인자 값으로 함수를 넘겨주는 것이다.

 

VStack(content: {
	Image(systemName: "globe")
		.imageScale(.large)
		.foregroundStyle(.tint)
	Text("Hello, world!")
})

원래는 이런 모양에서 content를 생략하는 클로저 문법으로 함수를 넘겨주는 것이다.

Vstack은 Image, Text뷰들을 포함한 TupleView로 패키징 한다.

 

📌 .padding, .imageScale, .foregroundStyle

View modifier라고 불리며 함수이다.

이 함수를 뷰로 보내면 뷰는 해당하는 기능을 뷰에 적용하고 기능을 적용한 뷰가 반환된다.

이 방식의 장점은 View modifier를 연결해서 수정할 수 있다는 점이다.

 

import SwiftUI

struct ContentView: View {
	var body: some View {
		ZStack {
			RoundedRectangle(cornerRadius: 12)
			Text("🐔").font(.largeTitle)
		}
		.foregroundStyle(.orange)
		.imageScale(.small)
		.padding()
	}
}

이 코드를 적용하면 아래와 같은 결과물을 얻을 수 있다.

Zstack에 RoundRectangle을 적용하고 그 안에 텍스트를 넣고 .font를 사용해서 크기를 조절했다.

그리고 Zstack에 .foregroundStyle을 적용하고 거기에 imageScale, padding을 순차적으로 적용한다.

RoundedRectangle(cornerRadius: 12).stroke(lineWidth: 10)

 


RoundedRectangle에 stroke View modifier를 추가하면 테두리도 그릴 수 있다.

 

📌 View Composition ( 뷰 모듈화)

뷰는 모듈화를 하여 재사용도 가능하다.

import SwiftUI

struct ContentView: View {
	var body: some View {
		CardView()
			.foregroundStyle(.orange)
			.imageScale(.small)
			.padding()
	}
}

struct CardView: View {
	var body: some View {
		ZStack {
			RoundedRectangle(cornerRadius: 12)
				.stroke(lineWidth: 2)
			Text("🐔")
            .font(.largeTitle)
		}
	}
}

구조체 CardView를 만들고 그 안에 View의 코드를 담으면 CardView라는 뷰 함수가 만들어지게 되고 이를 재사용하여 간결하게 코드를 작성할 수 있다.

 

import SwiftUI

struct ContentView: View {
	var body: some View {
		VStack {
			CardView()
			CardView()
			CardView()
			CardView()
		}
		.foregroundStyle(.orange)
		.imageScale(.small)
		.padding()
	}
}

View Composition을 통해 반복 사용되는 뷰들을 위처럼 활용할 수 있다.

 

📌 if문을 사용해서 카드 앞 뒷면 정하기 

내가 정한 뷰만 앞면이 나오게 하고 나머지가 보이지 않게 하려면 어떻게 해야 할까?

var isFaceUp: Bool = false

우선 앞면인지 뒷면인지를 판별할 변수를 선언해 준다.

모든 변수는 초기값이 필요하다. 초기값은 false로 해준다.

 

struct CardView: View {
	var isFaceUp: Bool = false
	var body: some View {
			ZStack {
				if isFaceUp {
				RoundedRectangle(cornerRadius: 12)
					.stroke(style: StrokeStyle(lineWidth: 2))
				Text("🐔")
					.font(.largeTitle)
				} else {
					RoundedRectangle(cornerRadius: 12)
				}
		}
	}
}

만약 isFaceUp이 true이면 원래대로 카드가 나오고

false이면 사각형에 배경색이 가득 찬 뒷면 형태로 표시된다.

 

struct ContentView: View {
	var body: some View {
		VStack {
			CardView(isFaceUp: true)
			CardView()
			CardView()
			CardView()
		}
		.foregroundStyle(.orange)
		.imageScale(.small)
        .padding()
    }
}

여기서 명시적으로 true라고 지정한 CardView 이외의 뷰들은 기본값으로 설정된 false로 동작하게 된다.

 

 

profile

육식하는야채의 개발일지

@육식하는야채

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!