본문 바로가기

Swift & SwiftUI

CS 193p Lecture 3~4 정리

수업 내용 정리.

https://www.youtube.com/watch?v=W1ymVx6dmvc&t=984s

 

struct과 class 차이점 

 

 

초기화 변경 과정과 후행 클로저(Trailing Closures)

뷰모델에서 모델을 가져오기 위해 초기화 설정을 위해 private var model: MemoryGame<String> = MemoryGame<String>() 인수없이 생성하려고 하면 에러가 발생. MemoryGame은 struct 구조인데, 여기안의 cards는 초기화 되지 않은 배열 타입의 변수가 있음(제네릭).  그러나 이 MemoryGame을 쓰려고 하는 뷰모델에서는 인수를 넣어서 초기화 해줘야 함.

이 때 모델에서 필요한 인수가 아닌 뷰모델 자체적으로 생성하는데 필요한 정보 numberOfPairsOfCards: 4 를 넣어줌, 모델에 가서도 매개변수를 만들어줌. 

 

모델을 초기화하기 위해 마지막 인수는 클로저로 사용

private var model = MemoryGame(

numberOfPairsOfCards: 4,

cardContentFactory: (forPairAtInext index: Int) -> String {

return ["👻", "🎃", "🕷️", "😈", "💀", "🕸️", "🧙‍♀️", "🙀", "👹", "😱", "☠️", "🍭"][index]

}

)

 

cardContentFactory 이렇게 바꿔줌 ->>

cardContentFactory: { (index: Int) -> String in

return ["👻", "🎃", "🕷️", "😈", "💀", "🕸️", "🧙‍♀️", "🙀", "👹", "😱", "☠️", "🍭"][index]

}

 

타입 추론으로 Int, String 삭제 → 더 간결하게 만듬

cardContentFactory: { index in

return ["👻", "🎃", "🕷️", "😈", "💀", "🕸️", "🧙‍♀️", "🙀", "👹", "😱", "☠️", "🍭"][index]

}

 

마지막 인수가 함수라면 마지막 인수를 () 밖으로 따로 빼어 후행 클로저(Trailing Closures))로 만들 수 있음

private var model = MemoryGame(numberOfPairsOfCards: 4){ index in

return ["👻", "🎃", "🕷️", "😈", "💀", "🕸️", "🧙‍♀️", "🙀", "👹", "😱", "☠️", "🍭"][index]

}

 

 

Static var 

let emojis = ["👻", "🎃", "🕷️", "😈", "💀", "🕸️", "🧙‍♀️", "🙀", "👹", "😱", "☠️", "🍭"]

emojis라는 변수를 만들어 배열을 여기다 넣으려고 하지만 에러 발생!

Cannot use instance member 'emojis' within property initializer; property initializers run before 'self' is available

 

속성 초기화할 때 순서가 결정되지 않음. 언제 초기활 될지 모르기 때문에 let의 변수를 다른 초기화를 할 때 사용할 수 없음 → 더 빨리 초기화하는 static 을 사용

변수가 초기화 되기전에 먼저 초기화 되도록 → 이것을 정적변수라 한다

private static let emojis = ["👻", "🎃", "🕷️", "😈", "💀", "🕸️", "🧙‍♀️", "🙀", "👹", "😱", "☠️", "🍭"]

 

모델 - 뷰모델 - 뷰 연결하는 방법 

 

 

mutating

 

모델에 있는 cards를 변경하려고 하는 메서드를 만들었는데 에러 발생.

Cannot use mutating member on immutable value: 'self' is immutable

클래스는 참조 타입이고  구조체는  값 타입인데

값 타인인 구조체 안의 프로퍼티를 변경하는 메서드를 실행할 경우 에러 발생

이 때 메서드 앞에 mutating 키워드를 입력하여 준다.

	mutating func shuffle() {
        cards.shuffle()
 }

 

 

전체코드

MemoryGame

// 어떤 타입이 들어올지 몰라 제네릭 타입으로 설정. 뷰모델에서 어떤 타입인지 결정.
struct MemoryGame<CardContent> {
    
    //외부에서 접근하지 못하도록 private
    private(set) var cards: Array<Card>
    
    // struct은 초기화 설정 하지 않아도 되지만, CardContent타입의 종류와 카드의 갯수를 받아 올 수 있도록 설정.
    init(numberOfPairsOfCards: Int, cardContentFactory: (Int) -> CardContent) {
        //카드 타입의 배열을 추론함
        cards = []
        
        // add numberOfPairsOfCards x 2 cards
        // for in
        for pairIndex in 0..<max(2,numberOfPairsOfCards) {
            //content: CardContent 타입 추론 가능하여 삭제하여도 됨
            let content = cardContentFactory(pairIndex)
            cards.append(Card(content: content))
            cards.append(Card(content: content))
        }
        
    }
    
    func choose(_ card: Card) {
        
    }
    
    mutating func shuffle() {
        cards.shuffle()
    }
    
    struct Card {
        var isFaceUp: Bool = true
        var isMatched: Bool = false
        var content: CardContent
    }
}

 

 

EmojiMemoryGame

// 뷰모델은 class로 만들어주는데, 여러 뷰에서 공유할 수 있도록 하기 위해. heap data
class EmojiMemoryGame: ObservableObject {
    
    //여기도 private, 초기화 진행을 위해 모델을 만들기 위해 필요한 변수를 static 변수로 만들어줌.
    // 변수 model에 초기화하기 위해 쓰는 변수에 static을 해주면 그 파일 내에 가장 먼저 초기화됨. -> 그 후 변수 model 초기화때 쓰임.
    private static let emojis = ["👻", "🎃", "🕷️", "😈", "💀", "🕸️", "🧙‍♀️", "🙀", "👹", "😱", "☠️", "🍭"]
    
    // private, static
    private static func CreateMemoryGame()-> MemoryGame<String> {
        return MemoryGame(numberOfPairsOfCards: 8){ index in
            // 배열 인덱스 범위를 벗어난 경우를 대비하여 if..else 구문
            if emojis.indices.contains(index) {
                return emojis[index]
            } else {
                return "⁉️"
            }
        }
    }
    
    // private 외부에 노출되지 않으면서, @Published - 변화가 있으면 감지하여 뷰에게 알려줌.
    @Published private var model = CreateMemoryGame()
    
    
    var cards: Array<MemoryGame<String>.Card> {
        return model.cards
    }
    
    // MARK - Intents
    
    func shuffle() {
        model.shuffle()
    }
    
    
    func choose(_ card: MemoryGame<String>.Card) {
        model.choose(card)
    }
}

 

'Swift & SwiftUI' 카테고리의 다른 글

Simple Task App  (0) 2023.12.21
100days of SwiftUi - project 7  (0) 2023.12.09
Networking for beginners  (0) 2023.10.11
Optional Binding, Chaining  (0) 2023.10.09
사용자의 위치정보 가져오기  (0) 2023.10.05