본문 바로가기

IOS

3. IOS 강의 Reactive UI + Protocols + Layout

www.youtube.com/watch?v=SIYdYpPXil4&list=PLpGHT1n4-mAtTj9oywMWoBx0dCGd51_yG&index=3

 

Slides.pdf
0.84MB

 

소스

MemoryGame.swift

//
//  MemoryGame.swift
//  Memorize
//
//  Created by user on 2021/01/16.
//

import Foundation

struct MemoryGame<CardContent> {
    var cards: Array<Card>
    
    mutating func choose (card: Card){
        print("card chosen: \(card)")
        let choseIndex: Int = index(of: card)
        cards[choseIndex].isFaceUp = !cards[choseIndex].isFaceUp
    }
    
    func index(of card: Card) -> Int {
        for index in 0..<cards.count {
            if cards[index].id == card.id {
                return index
            }
        }
        return 0
    }
    
    
    init (numberOfPairsOfCards: Int, cardContentFactory: (Int)-> CardContent) {
        cards = Array<Card>()
        
        for pairIndex in 0 ..< numberOfPairsOfCards {
            
            let content = cardContentFactory(pairIndex)
            cards.append(Card(content: content, id: pairIndex * 2))
            cards.append(Card(content: content, id: pairIndex * 2 + 1 ))
        }
        
    }
    
    
    struct Card: Identifiable {
        var isFaceUp: Bool = true
        var isMatched: Bool = false
        var content: CardContent 
        var id: Int
    }
    
}

 

 

EmojiMemoryGame.swift

//
//  EmojiMemoryGame.swift
//  Memorize
//
//  Created by user on 2021/01/16.
//

import SwiftUI

class EmojiMemoryGame: ObservableObject {
    
    @Published private var model: MemoryGame<String> = EmojiMemoryGame.createMemoryGame()
    
    static func createMemoryGame() -> MemoryGame<String>{
        
        let emojis: Array<String> = ["😊", "😱", "😎"]
        
        return MemoryGame<String>(numberOfPairsOfCards: emojis.count) { parIndex in
            return emojis[parIndex]
        }
    }
    
    // MARK: - Access to the Model
    
    var cards: Array<MemoryGame<String>.Card> {
        model.cards
    }
    
    
    // MARK: - Intent(s)
    
    func choose(card: MemoryGame<String>.Card){
        model.choose(card: card)
    }
}

  • ObservableObject는 Protocol으로 Combine 프레임워크의 일부다.
  • 이것을 사용하기 위해서는, Protocol을 준수하고 @Published를 사용하면 된다.
  • @Published를 사용하면 변수의 값이 추가되거나 삭제 되었다는 것을 View가 알 수 있게 해준다.
  • ObservableObject는 MVVM 아키텍쳐의 ViewModel에 적용하기 좋은 프로토콜이다.

 

 

 

ContentView.swift

//
//  ContentView.swift
//  Memorize
//
//  Created by user on 2021/01/15.
//

import SwiftUI

struct ContentView: View {
    
    @ObservedObject var viewModel: EmojiMemoryGame
    
    var body: some View {
        HStack{
            ForEach(viewModel.cards) { card in
                CardView(card: card).onTapGesture {
                    viewModel.choose(card: card)
                }
            }
        }
        .padding()
        .foregroundColor(Color.orange)
        
    }
}

struct CardView: View {
    
    var card: MemoryGame<String>.Card
    
    var body: some View {
        
        // GeometryReader는 SwiftUI 에서 View가 포함된 부모뷰(컨테이너)의 
        // 크기를 기준으로 View의 frame 조절하는 방법
        GeometryReader(content: { geometry in
            ZStack {
                if card.isFaceUp {
                    RoundedRectangle(cornerRadius: conrnerRadius)
                        .fill(Color.white)
                    
                    RoundedRectangle(cornerRadius: conrnerRadius)
                        .stroke(lineWidth: edgeLineWidth)
                    
                    Text(card.content)
                } else {
                    RoundedRectangle(cornerRadius: conrnerRadius)
                        .fill()
                }
            }
            .font(Font.system(size: fontSize(for: geometry.size)))
        })
    }
    
    // MARK: - Drawing Constants
    let conrnerRadius: CGFloat = 10
    let edgeLineWidth: CGFloat = 3
    
    func fontSize(for size: CGSize) -> CGFloat {
        min(size.width, size.height) * 0.75
    }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView(viewModel: EmojiMemoryGame())
    }
}
  • View에는 Model을 Binding하여 View를 다시 그리게 하는 @ObservedObject를 이용

 

프로토콜(Protocol)

특정 작업이나 기능의 조각에 맞게 메서드, 속성 및 기타 요구 사항 정의

요구 사항의 실제 구현을 제공하기 위해 클래스, 구조 또는 열거에서 프로토콜을 채택 

 

 

확장(Extension)

기존 유형을 확장하여 새 프로토콜을 채택하고 준수

 

확장은 기존 유형에 새 속성, 메서드 및 첨자를 추가 할 수 있으므로 프로토콜이 요구

 

docs.swift.org/swift-book/LanguageGuide/Protocols.html

 

Protocols — The Swift Programming Language (Swift 5.3)

Protocols A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of tho

docs.swift.org