한결과 레지아이스

TIL in Swift, 22/02/15 본문

Today I Learned/SwiftUI

TIL in Swift, 22/02/15

miniwho 2022. 2. 15. 20:05

Stanford 유튜브에서 제공하는 SwiftUI 2021 Lecture 3을 보고 클론코딩 하며 정리해본 부분입니다. https://www.youtube.com/watch?v=--qKOhdgJAs

객체지향을 써보는게 첨이라 틀린 부분이 많을 수 있습니다...(매우 높은 확률)

/* Swift에서는 객체라는 말을 쓰지 않는다! 다른 많은 객체지향 언어들의 struct가 프로퍼티만 가질 수 있는 것과 달리, Swift에서는 메서드도 가질 수 있습니다. 그래서 보통의 언어들이 class 인스턴스만을 객체라고 부르지만, Swift에서는 struct 인스턴스도 포괄할 수 있는 단어인 인스턴스를 쓴다고 합니다. 그러면 Swift에서 Struct와 Class의 차이가 무어냐? Struct는 밸류 타입, Class는 참조 타입이라고 합니다..
    이하는 2강에서 만든 클래스와 스트럭쳐에서 몰랐던 부분들을 주석으로 설명해봤습니다. */

/* <Model> */

import Foundation

struct MemoryGame<CardContent> { 
/* <>꺾쇠 안의 부분이 무엇이냐? C++의 템플릿과 비슷하다고 생각했습니다. 이 자리에 들어오는 
CardContent는 어떤 이름이어도 상관 없고, Type Parameter라고 부릅니다. 
이 struct가 실제로 쓰일 때 여기에 어떤 자료형이 와도 되고, MemoryGame<String>으로 쓰면 
이하에 존재하는 CardContent들이 String으로 쓰입니다. */
    
    private(set) var cards: [Card] 
/* private라는 접근제한자에 (set)을 더해주면, 값을 얻어올 순 있지만 변경은 불가능하게 쓸 수 있습니다.
 private로만 선언하면 얻어올 수도 없는 것과 대조되는 부분. */
    
    init(numbersOfPairsOfCards: Int, createCardContent: (Int) -> CardContent) { // CardContent가 쓰인 부분1
        cards = [Card]()
        for pairIndex in 0..<numbersOfPairsOfCards {
            let content  = createCardContent(pairIndex)
            cards.append(Card(content: content, id: pairIndex * 2))
            cards.append(Card(content: content, id: pairIndex * 2 + 1))
        }
    }
    
    func choose(_ card: Card) { 
        
    } 

/* Swift에서는 parameter마다 label을 정해주고, 호출할 때에도 이 label을
 붙여서 인자를 넣어줘야합니다. 근데 호출시와 선언시의 라벨 이름을 다르게 할 수 있는데, 
func someFunction(outlabel inlabel: variableType) -> (Return Type) {...} 
뭐 이렇게 쓰는 것 같습니다. 근데 outlabel 자리에 예시처럼 언더바를 넣으면, 
함수 호출시에 라벨을 쓰지 않아도 됩니다. */
    
    struct Card: Identifiable { 
        var isFaceUp: Bool = false
        var isMatched: Bool = false
        var content: CardContent // CardContent가 쓰인 부분2
        var id: Int
    }
/* identifiable은 ForEach에 쓰기 위해 존재하는 것 같은데(다른 데 어디에 쓰는지 몰겄슈..) 
	protocol이라고 합니다. 아직 protocol에 대해 배우진 않았는데, 
	struct에도 쓸 수 있는 상속같은 느낌인 것 같고(추상 클래스처럼 정의만 할 뿐 구현은 안되어있는), 
	protocol을 준수하기 위해 책임이 필요한 것 같어요.. 
	여기선 id라는 프로퍼티를 가지는 것이 그 책임입니다. 
	여기서는 Int로 했지만 String도 되고 그런댑니다... */
}

/* <ViewModel> */

import SwiftUI

class EmojiMemoryGame {
    static let emojis = ["🦆", "🦅", "🦉", "🐿", "🦔"] 
/* static이라는 키워드가 Swift가 어떻게 쓰이냐! C랑은 사뭇 다른 느낌이라 좀 어려웠습니다... 
	 class 혹은 struct에 존재하는 메서드와 프로퍼티들은 인스턴스가 생성되기 전까지 메모리에 
	 올라가지 않습니다..! 그래서 클래스 내부에서도 참조가 안됩니다.. 
	 하지만 static키워드를 쓰게 되면 타입 프로퍼티, 타입 메서드라고 부르고, 
	 이제는 해당 타입이 갖는 것이 되어 인스턴스를 생성하지 않고도 쓸 수 있습니다..! 
	 class/struct 내부에서 쓰려면 static이 필요합니다. 
	 예컨데 이 emojis라는 프로퍼티가 static이 아니면, 이 밑에서는 emojis라는 프로퍼티를 쓸 수가 없습니다.
	 메서드도 마찬가지.. */
    
    static func createMemoryGame() -> MemoryGame<String> {
        MemoryGame<String>(numbersOfPairsOfCards: 5) { pairIndex in
            emojis[pairIndex]
        }
    }
    
    private(set) var model: MemoryGame<String> = createMemoryGame()
    
    var cards: [MemoryGame<String>.Card] { 
        model.cards
    } /* 모델에서 정의된 MemoryGame<CardContent>에서 CardContent를 String 자료형으로 
	지정해주고 -> 그 내부의 Card라는 구조체를 타입으로 삼는 배열. */
}
Comments