SwiftUI Tutorial: 1.2. Building Lists and Navigation (Section2,3,)(진행중)

zam·2023년 4월 18일
0

SwiftUI Tutorial

목록 보기
3/3
post-thumbnail

튜토리얼을 진행하며 생긴 궁금증, 깨달음, 알게된 팁들 (feat. chatGPT와 대화하기)

SwiftUI Tutorial: 1.2. Building Lists and Navigation
https://developer.apple.com/tutorials/swiftui/building-lists-and-navigation

Section2. Create the Row View

미리보기가 왜 작동하지 않는다고?

import SwiftUI

struct LandmarkRow: View {
    var landmark: Landmark // 속성 (저장 property)

    var body: some View {
        Text("Hello, World!")
    }
}

struct LandmarkRow_Previews: PreviewProvider {
    static var previews: some View {
        LandmarkRow() //landmark 속성에 대한 초기화가 이루어지지 않음
    }
}

위 코드에서 LandmarkRow 구조체는 landmark라는 속성을 가지고 있습니다. 하지만 LandmarkRow_Previews 구조체의 preview 메서드에서 LandmarkRow 구조체를 인스턴스화 할 때 landmark 속성에 대한 초기화가 이루어지지 않아서 미리보기가 작동하지 않습니다.

LandmarkRow() //LandmarkRow 구조체 초기화하려는 중
LandmarkRow(landmark: landmarks[0]) //landmark 속성 전달해야함

즉, LandmarkRow 구조체의 초기화 시에는 반드시 landmark 속성을 전달해야 하며, LandmarkRow_Previews 구조체의 preview 메서드에서도 landmark 속성을 전달하여 초기화해야 합니다. 그렇지 않으면 landmark 속성이 초기화되지 않아 오류가 발생하게 됩니다.

LandmarkRow의 인스턴스를 초기화하려면 landmark 매개변수를 전달해야 합니다. 하지만 LandmarkRow_Previews에서 LandmarkRow()를 호출할 때 landmark 매개변수를 전달하지 않았습니다. 따라서 컴파일러는 오류를 표시합니다.

LandmarkRow 구조체를 초기화하는 거랑 LandmarkRow의 인스턴스를 초기화하는게 차이가 있어?

LandmarkRow 구조체를 초기화하는 것과 LandmarkRow의 인스턴스를 초기화하는 것은 사실상 같은 것입니다. 인스턴스를 초기화한다는 것은 해당 타입의 새로운 객체를 생성하고 메모리에 할당하는 것을 의미합니다. 새로운 인스턴스를 생성하면 해당 타입의 프로퍼티와 메소드 등을 사용할 수 있게 됩니다. 이 과정에서 구조체는 값 타입이므로 복사되어 생성됩니다. 함수와 메소드에서 인스턴스를 초기화할 때는 초기화 구문(Initializer)을 사용합니다. 예를 들어 LandmarkRow에서 landmark 프로퍼티를 초기화하는 것도 초기화 구문을 사용합니다.

왜 초기화를 해야해?

객체를 만들기 위해서는 해당 객체의 인스턴스를 생성해야 합니다. 이때 인스턴스를 생성하는 것을 초기화(initialization)라고 합니다. 초기화를 통해 해당 객체의 속성(property)들에 대한 값을 설정하거나 다른 초기화 작업들을 수행합니다.

예를 들어, 앱에서 사용자가 가입을 하면 User라는 객체의 인스턴스를 생성하여 사용자의 정보를 저장할 수 있습니다. 이때 User 객체의 인스턴스를 생성하고 속성에 값을 할당하는 것이 초기화 작업입니다.

또 다른 예시로, UIView 객체의 인스턴스를 생성할 때 해당 뷰의 프레임(frame)을 설정하여 초기화하는 것이 있습니다. 이러한 초기화 작업을 통해 해당 뷰가 화면에 올바르게 나타날 수 있습니다.

따라서 객체를 사용하려면 해당 객체의 인스턴스를 생성하고 초기화하는 과정이 필요합니다.

landmark.name의 원리

import SwiftUI

struct LandmarkRow: View {
    var landmark: Landmark

    var body: some View {
        HStack {
            landmark.image
                .resizable()
                .frame(width: 50, height: 50)
            Text(landmark.name)
            
            Spacer()
        }
    }
}

struct LandmarkRow_Previews: PreviewProvider {
    static var previews: some View {
        LandmarkRow(landmark: landmarks[0])
    }
}

코드 기본 해석

var landmark라는 변수에 Landmark 타입의 인스턴스를 저장했고, landmark 인스턴스에 저장된 값 검색 : landmark.name해 Landmark에 액세스

위의 코드에서 landmark는 Landmark 타입입니다. 이 구조체는 var 키워드를 사용하여 landmark 변수를 선언하고, 이 변수는 Landmark 타입의 인스턴스를 저장합니다.

그리고 body 프로퍼티는 some View 타입의 반환 타입을 가지는 계산형 프로퍼티입니다. 이는 LandmarkRow 구조체가 SwiftUI에서 렌더링 될 수 있는 뷰를 반환한다는 것을 의미합니다.

body 프로퍼티는 SwiftUI에서 뷰의 내용을 나타냅니다. some View는 뷰 계층 구조 내에서 뷰 타입을 지칭하며, 실제로 뷰 타입이 무엇인지는 컴파일 타임에 결정됩니다.

따라서 body 프로퍼티에서 landmark.image 및 Text(landmark.name)와 같은 뷰를 반환하여 해당 Landmark 타입의 데이터를 보여주는 뷰 계층 구조를 정의합니다.

landmark.name의 원리

LandmarkRow 뷰에서 landmark는 Landmark라는 타입의 프로퍼티입니다. 이 Landmark 타입은 랜드마크에 대한 정보 (예 : 이름, 위치, 이미지 등)를 포함하는 사용자 정의 구조체나 클래스입니다.

HStack 내부의 Text 뷰는 landmark.name 프로퍼티를 사용하여 랜드마크의 이름을 표시합니다. 이는 단순히 landmark 인스턴스에 저장된 이름 값을 검색하는 것입니다.

이것은 Landmark 구조체나 클래스에 name이라는 프로퍼티가 있고 해당 프로퍼티가 구조체나 클래스 외부에서 액세스 가능하기 때문에 작동합니다. landmark 인스턴스는 LandmarkRow 뷰에 매개변수로 전달되며 해당 인스턴스에는 랜드마크의 이름을 포함하는 자체 name 프로퍼티가 있습니다. 따라서 LandmarkRow가 Landmark 인스턴스로 초기화될 때 landmark.name은 해당 랜드마크의 이름을 표시합니다.

Landmark 타입은 다른 파일에 있는데 이렇게 쓸 수 있는거야?

SwiftUI는 컴파일 타임에 코드를 함께 빌드하여 모든 종속성이 해결되도록 보장합니다. 이것은 서로 다른 파일에서 작성한 뷰, 모델 및 유틸리티 등이 함께 사용될 수 있음을 의미합니다. 따라서 파일 간에 데이터 모델 및 뷰 계층 구조를 공유하는 것은 매우 일반적입니다.


미리보기 PreviewProvider

struct LandmarkRow_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            LandmarkRow(landmark: landmarks[0])
            LandmarkRow(landmark: landmarks[1])
        }
        .previewLayout(.fixed(width: 300, height: 70)) // Preview 레이아웃 조정 가능
    }
}

Xcode의 캔버스는 현재 에디터에서 PreviewProvider 프로토콜을 준수하는 모든 타입을 자동으로 인식하고 표시합니다. PreviewProvider는 하나 이상의 뷰를 반환하며, 크기 및 디바이스를 구성할 수 있는 옵션이 있습니다.
일반적으로, SwiftUI의 뷰, 레이아웃 및 사용자 지정 컨트롤러가 PreviewProvider 프로토콜을 준수합니다.

나는 왜 두 개가 한 번에 안보이고 탭으로 구분되어있을까 (해결 못함)


정적과 동적?

You can even mix static and dynamically generated views
  • 정적(static)
    무엇인가가 변하지 않고 고정된 상태를 의미합니다. 예를 들어, 앱에서 이미지나 텍스트와 같은 내용이 고정되어 표시되는 것을 정적으로 표시된다고 합니다. 리스트의 경우, 리스트의 항목들이 미리 정의되어 있고 변하지 않는 것을 의미합니다.

  • 동적(dynamic)
    무엇인가가 변화하며 움직이는 상태를 의미합니다. 런타임에 생성되는 뷰. 예를 들어, 사용자가 앱에서 버튼을 클릭하거나 스크롤을 내리는 것에 따라서 새로운 내용이 생성되거나 화면이 변경되는 것을 동적으로 표시된다고 합니다.
    리스트의 경우, 리스트의 항목들이 사용자와 상호작용하거나 외부 데이터에 따라 런타임에 생성됩니다. 예를 들어, 사용자의 선택에 따라 리스트 항목이 추가되거나 제거되는 경우입니다.

List

List 기본 컴포넌트 스타일이 있음


진행중..

0개의 댓글