iOS 개발자/iOS Stanford Univ

[iOS 스탠포드] Chapter2

FDEE 2021. 6. 22. 21:23

Chapter 2

- StoryBoard : View

- ViewController : Controller

- Concentration : Model

- Card : Struct

 

✔︎ MVC 구조

- M : Model - UI와 관련없는(import Foundation) 코드, 즉 Controller가 명령을 내리면 무엇을 보일지 여부

- V : View - UI만으로 존재 (StoryBoard)

- C : Controller - View와 Model 사이의 소통담당(import UIKit), 어떻게 화면에 표시할지 여부

 

- C -> M, V : 직접적으로 접근 가능

- V -> C

  - delegate : 행위에 대한 요청

  - data source : 데이터에 대한 요청

- M -> C : Notification & KVO

 

✔︎ 목표

- ViewController 에서 UI와 관련없는 코드를 Model로 분리하자

- Struct를 사용하여 Card만의 속성을 설정하자

- Card를 사용하며 UI와 관련없는 게임관련 동작 메소드를 Concentration에 분리하자

- View를 수정하여도 영향없이 동작가능한 Model를 통해 게임을 구현하자

 

✔︎ 구현 내용

- struct Card : isFaceUp(앞면 여부), isMatched(쌍이 찾아졌는지 여부), identifier(카드 구별값) 속성들을 설정하자

- struct Card : static 변수, 메소드를 통해 Card 타입자체의 identifier 값을 설정하자

 

- class Concentration : cards: [Card]를 통해 Controller 에서 접근하도록 만들자

- class Concentration : init(카드수: Int)를 통해 cards를 설정하도록 하자

- class Concentration : chooseCard(index: Int) 메소드를 통해 카드가 선택되었을 때 Card의 상태를 설정하는 메소드를 만들자

  - isMatched = true 인 카드가 선택되었을 경우 모든 메소드 무시

  - 선택된 카드의 공동 행동 : isFaceUp = true 설정

  - 두장째 뒤집어진 경우

    - 1. 매칭이 된 경우 -> 두 카드 모두 isMatched = true 설정, 확인카드값 nil 설정

    - 2. 매칭이 안된 경우 -> 확인카드값 nil 설정

  - 카드 한장만 뒤집어진 경우 -> 모든 카드 isFaceUp = false 설정, 해당 index 카드만 true 설정, 확인카드값 index 설정

 

- ViewController : Model 접근하기 위한 변수 game 설정 (Concentration의 init 설정)

  - (전체카드수+1)/2 가지수의 카드종류 설정 

  - 사용될 때 초기화가 진행되는 lazy 특징 사용

- ViewController : touchCard 메소드 수정

  - game.chooseCard 메소드 사용

  - Model이 수정됨에 따른 View 수정을 위한 메소드인 updateViewFromModel() 실행

- ViewController : updateViewFromModel() 메소드 추가

  - game.cards의 각 isFaceUp 값에 따라 해당 button의 앞, 뒷면 여부 설정

  - isMatched 값에 따라 숨기기 설정

- ViewController : emoji 메소드 추가

  - 기존 emojiChoices 배열에서 랜덤으로 하나씩 추출하여 Dictiorary 형태인 emoji에 데이터 추가

  - Dictionary의 key 값인 클릭된 Button의 identifier 값을 통해 String 형태인 emoji값 반환

 

✔︎ 새롭게 알게된 기능들

- static var, func : 정적 변수, 메소드라 부르며 struct 타입에 관한 변수, 메소드의 특징을 지닌다

  이를 통해 동일 struct 간의 구별과 같은 기능에 사용이 가능하다!

static var identifierFactory = 0
static func getUniqueIdentifier() -> Int {
    identifierFactory += 1
    return identifierFactory
}
    
init() {
    self.identifier = CP2_Card.getUniqueIdentifier()
}

- 배열.indices를 통핸 for문 형식 : for i in 0..<Array.count   ->   for i in Array.indices 형식으로 사용이 가능

for flipDownIndex in cards.indices {
    cards[flipDownIndex].isFaceUp = false
}

- 배열.append(값1), 배열.append(값2)  ->  배열 += [값1, 값2] 형식으로 한번에 추가 가능

cards += [card, card]

- lazy var 변수 : 초기화에 사용되는 변수의 초기화가 먼저 필요한 경우에 사용 가능 (초기화 순서 미루기)

lazy var game = CP2_Concentration(numberOfPairsOfCards: (cardButtons.count+1)/2)

- 랜덤숫자 추출 메소드 : arc4random_uniform

let randomIndex = Int(arc4random_uniform(UInt32(emojiChoices.count)))

 

✔︎ 동작 화면

 

✔︎ 전체 코드

- Card

import Foundation

struct CP2_Card
{
    var isFaceUp = false
    var isMatched = false
    var identifier: Int
    
    static var identifierFactory = 0
    static func getUniqueIdentifier() -> Int {
        identifierFactory += 1
        return identifierFactory
    }
    
    init() {
        self.identifier = CP2_Card.getUniqueIdentifier()
    }
}

- Concentration

import Foundation

class CP2_Concentration
{
    var cards: [CP2_Card] = []
    
    var indexOfOneAndOnlyFaceUpCard: Int?
    
    func chooseCard(at index: Int) {
        if !cards[index].isMatched {
            if let matchIndex = indexOfOneAndOnlyFaceUpCard, matchIndex != index {
                // check if cards match
                if cards[matchIndex].identifier == cards[index].identifier {
                    cards[matchIndex].isMatched = true
                    cards[index].isMatched = true
                }
                cards[index].isFaceUp = true
                indexOfOneAndOnlyFaceUpCard = nil
            } else {
                // either no cards or 2 cards are face up
                for flipDownIndex in cards.indices {
                    cards[flipDownIndex].isFaceUp = false
                }
                cards[index].isFaceUp = true
                indexOfOneAndOnlyFaceUpCard = index
            }
            
        }
    }
    
    init(numberOfPairsOfCards: Int) {
        for _ in 1...numberOfPairsOfCards {
            let card = CP2_Card()
            cards += [card, card]
        }
        // TODO: Shuffle the cards
    }
}

- ViewController

import UIKit

class CP2_ViewController: UIViewController {
    
    lazy var game = CP2_Concentration(numberOfPairsOfCards: (cardButtons.count+1)/2) //사용될 때 초기화가 진행, didSet은 사용 불가
    
    var flipCount = 0 {
        didSet { flipCountLabel.text = "Flips: \(flipCount)" }
    }
    var emojiChoices: [String] = ["👻", "🎃", "😈", "👽", "💀", "🤢", "🤡", "💩"]
    
    @IBOutlet var cardButtons: [UIButton]!
    @IBOutlet var flipCountLabel: UILabel!
    
    @IBAction func touchCard(_ sender: UIButton) {
        flipCount += 1
        if let cardNumber = cardButtons.firstIndex(of: sender) {
            game.chooseCard(at: cardNumber)
            updateViewFromModel()
        } else {
            print("chosen card was not in cardButtons")
        }
    }
    
    func updateViewFromModel() {
        for index in cardButtons.indices { //배열 -> 셀수있는 구간
            let button = cardButtons[index]
            let card = game.cards[index]
            
            if card.isFaceUp {
                button.setTitle(emoji(for: card), for: .normal)
                button.backgroundColor = UIColor.white
            } else {
                button.setTitle("", for: .normal)
                button.backgroundColor = card.isMatched ? UIColor.clear : UIColor.orange
            }
        }
    }
    
    var emoji : [Int:String] = [:]
    func emoji(for card: CP2_Card) -> String {
        if(emoji[card.identifier] == nil), emojiChoices.count > 0 {
            let randomIndex = Int(arc4random_uniform(UInt32(emojiChoices.count)))
            emoji[card.identifier] = emojiChoices.remove(at: randomIndex)
        }
        
        return emoji[card.identifier] ?? "?"
    }
    
}

 

✔︎ 깃허브 : https://github.com/FreeDeveloper97/iOS_Stanford_Univ

 

FreeDeveloper97/iOS_Stanford_Univ

Contribute to FreeDeveloper97/iOS_Stanford_Univ development by creating an account on GitHub.

github.com

 

✔︎ 과제내용

- 카드를 랜덤으로 섞는 작업

- 게임이 종료되었을 때 작업

'iOS 개발자 > iOS Stanford Univ' 카테고리의 다른 글

[iOS 스탠포드] Chapter3  (0) 2021.07.07
[iOS 스탠포드] Assignment 1 : Concentration  (0) 2021.07.05
[iOS 스탠포드] Chapter1  (0) 2021.06.18