본문 바로가기

IOS

3. IOS 강의 Grid enum Optionals

 

www.youtube.com/watch?v=eHEeWzFP6O4&list=PLpGHT1n4-mAtTj9oywMWoBx0dCGd51_yG&index=4

Assignment 2.pdf
0.50MB
GridLayout.swift
0.00MB
Reading 2.pdf
0.12MB
Slides.pdf
0.84MB

 

 

소스

EmojiMemoryGameView.swift

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

import SwiftUI

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

struct CardView: View {
    
    var card: MemoryGame<String>.Card
    
    var body: some View {
        
        
        GeometryReader(content: { geometry in
            ZStack {
                if card.isFaceUp {
                    RoundedRectangle(cornerRadius: conrnerRadius)
                        .fill(Color.white)
                    
                    RoundedRectangle(cornerRadius: conrnerRadius)
                        .stroke(lineWidth: edgeLineWidth)
                    
                    Text(card.content)
                } else {
                    if !card.isMatched {
                        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 {
        EmojiMemoryGameView(viewModel: EmojiMemoryGame())
    }
}

 

 

MemoryGame.swift

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

import Foundation

struct MemoryGame<CardContent> where CardContent: Equatable {
    var cards: Array<Card>
    
    var indexOfTheOneAndOnlyFaceUpCard: Int? {
        get {cards.indices.filter { cards[$0].isFaceUp }.only}
        
        set {
            for index in cards.indices {
                cards[index].isFaceUp = index == newValue
            }
        }
    }
    
    mutating func choose (card: Card){
        
        if let choseIndex = cards.firstIndex(matching: card), !cards[choseIndex].isFaceUp, !cards[choseIndex].isMatched {
            
            if let potentialMatchIndex = indexOfTheOneAndOnlyFaceUpCard {
                if cards[choseIndex].content == cards[potentialMatchIndex].content {
                    cards[choseIndex].isMatched = true
                    cards[potentialMatchIndex].isMatched = true
                }
                cards[choseIndex].isFaceUp = true
            }else {
                indexOfTheOneAndOnlyFaceUpCard = choseIndex
                
            }
        }
    }
    
    
    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 = false
        var isMatched: Bool = false
        var content: CardContent 
        var id: Int
    }
    
}

Equatable 프로토콜

- 값이 동일한 지 어떤지를 비교 할 수 있는 타입

class Num {

    var num : Int

    init(_ num :Int) {

        self.num = num

    }

}

 

if A(1) == A(2){} //error!

 

 

Where 절

타입 제약은 타입 인자에 요구사항에 제네릭 함수나 타입을 연관하여 정의할 수 있게 한다.

 

연관된 타입을 위한 요구사항을 정의하는데 유용

Where 절은 연관 타입이 특정 프로토콜에 일치하도록 특정 타입 인자와 연관 타입이 같게 필요하다. Where 절은 where 키워드를 타입 인자 목록 뒤에 위치하며, 연관 타입을 위한 하나 이상의 제약과 타입과 연관 타입 간의 하나 이상의 관계가 따른다.



 

 

 

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)
    }
}

 

Grid.swift

 

//
//  Grid.swift
//  Memorize
//
//  Created by user on 2021/01/17.
//

import SwiftUI

struct Grid<Item, ItemView>: View  where Item: Identifiable, ItemView: View{
    
    var items: [Item]
    var viewForItem: (Item) -> ItemView
    
    init (_ items: [Item], viewForItem: @escaping (Item)-> ItemView) {
        self.items = items
        self.viewForItem = viewForItem
    }
    
    var body: some View {
        GeometryReader { geometry in
            body(for: GridLayout(itemCount: items.count, in: geometry.size))
        }
    }
        
    
    func body(for layout: GridLayout) -> some View {
        ForEach(items) { item in
            body(for: item, in: layout)
        }
    }
    
    func body(for item: Item, in layout: GridLayout) -> some View {
        let index = items.firstIndex(matching: item)!
//        return Group {
//            if index != nil {
//                 viewForItem(item)
//                    .frame(width: layout.itemSize.width, height: layout.itemSize.height)
//                    .position(layout.location(ofItemAt: index!))
//            }
//        }
        
        return viewForItem(item)
            .frame(width: layout.itemSize.width, height: layout.itemSize.height)
            .position(layout.location(ofItemAt: index))
        
    }
}


Array+Identifible.swift

//
//  Array+Identifiable.swift
//  Memorize
//
//  Created by user on 2021/01/17.
//

import Foundation

extension Array where Element: Identifiable {
    func firstIndex(matching: Element) -> Int? {
        for index in 0..<self.count {
            if self[index].id == matching.id {
                return index
            }
        }
        return nil
    }
}

 

 

Array+Only.swift

//
//  Array_Only.swift
//  Memorize
//
//  Created by user on 2021/01/18.
//

import Foundation


extension Array {
    
    var only: Element? {
        count == 1 ? first: nil
    }
    
}

Enum

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

 

Enumerations — The Swift Programming Language (Swift 5.3)

Enumerations An enumeration defines a common type for a group of related values and enables you to work with those values in a type-safe way within your code. If you are familiar with C, you will know that C enumerations assign related names to a set of in

docs.swift.org

열거 관련 값의 그룹에 대한 일반적인 유형을 정의하고 코드 내에서 형태 보증 된 방법으로 그 값으로 작업 가능

 

각 열거 형 케이스에 대해 값 ( 원시  이라고 함 )이 제공되는 경우 값은

문자열, 문자 또는 정수 또는 부동 소수점 유형의 값이 될 수 있습니다.

 

또는 열거 형 케이스는 공용체 또는 변형이 다른 언어에서 수행하는 것처럼 각기

다른 케이스 값과 함께 저장 될 모든 유형 의 관련 값을 지정할 수 있습니다. 

 

공통된 관련 사례 집합을 하나의 열거의 일부로 정의 할 수 있으며, 각각에는 적절한 유형의 서로 다른 값 집합이 연결되어 있습니다.

 

Swift의 열거 형은 그 자체로 일류 유형입니다. 열거 형의 현재 값에 대한 추가 정보를 제공하는 계산 된 속성과 열거 형이

나타내는 값과 관련된 기능을 제공하는 인스턴스 메서드와 같이 전통적으로 클래스에서만 지원되는 많은 기능을 채택

 

열거 형은 초기 케이스 값을 제공하는 이니셜 라이저를 정의 할 수도 있습니다. 

원래 구현 이상으로 기능을 확장하도록 확장 할 수 있습니다. 표준 기능을 제공하기 위해 프로토콜을 준수 할 수 있습니다.

 

 

 

기본적으로 Optional  2 개의 케이스 가있는 Enum ( none, some )

var x : Int? = 10   <Some (10)>

var x : Int? = nil   <None>

 

Optional 이라는 타입으로 nil 을 처리

 

옵션은 단지 값의 래퍼입니다. 

 

nil  다른 값을 할당 하면 기본 이니셜 라이저가 호출

.Some 상태로 Enum  만들고 할당 된 값이 관련 값으로 설정

 

OptionalType  NilLiterableConvertible 프로토콜을 따르기 때문에 가능

 프로토콜은 준수 유형에 nil 을 인수로 취하는 이니셜 라이저가 필요함을 정의

 

Nil Coalescing Operator

c의 값이 nil 경우 우측의 값을 반환

 

let c: Int? = 10

let d: Int = 0

let e = c ?? d

 

표현식 d  c 안에 저장된 유형과 일치해야합니다 . 경우 d는 문자열 것, 그것은 컴파일되지 않습니다.

 

let c: Int? = 10

let d: String = “Hello World”

let e = c ?? d  // 컴파일되지 않음

 

 

Forced Unwrapping

무조건 변수가 있는 상황이 보장된 경우 느낌표(!)를 쓰면 우리가 원하는 Hello을 출력

var optionalString: String? = “Hello”
print(optionalString!)
// 출력 결과: Hello

 

Enum, Optionals