Week 1: Assignment

sun·2021년 12월 18일

# 테마 추가

  • 필수 요구 사항의 테마의 의미를 좀 더 확장해서 테마가 카드에 사용할 이모지들, 카드 뒷면 색, UI 배경화면 색을 모두 포괄하는 의미로 정의해서 사용했다.

  • 별도의 구조체를 선언할까 싶기도 했는데 귀찮아서 그냥 (emojis: [String], cardBackColor: UIColor, backgroundColor: UIColor) 형태의 튜플을 사용했다.

  • 사실상 이 과제에 소요한 시간의 2/3 가 테마 구현에 소요됐는데 처음에는 init 이랑 static 을 사용했고, 여기에 쓸데없는 변수도 많이 선언하고, 또 init 자체가 좀 복잡해서 코드가 깔끔하지 않은 느낌이었다(이후에 3강을 들었는데 교수님이 ViewController 에서의 init은 복잡해서 지양한다고 하셨다). 다시 보니까 그냥 lazy 키워드로도 충분한 해결이 가능할 것 같아서 바꿔줬고, 덕분에 코드도 훨씬 깔끔해졌다. 다양한 해결 방법이 있겠지만 이번 주차에 lazy 를 사용하는 방법을 배운만큼 이를 활용해봤다.

  • themes 변수에 사용가능한 모든 테마들을 배열로 관리하고, randomElement() 메서드로 하나를 이 중 하나를 랜덤으로 선택해서 theme 변수에 저장했다. 그냥 그대로 컴파일하면 themes 와 theme 모두 ViewController 의 프로퍼티라서 빌드에 실패하기 때문에 theme 프로퍼티를 lazy 하게 만들어줬다.

class ViewController: UIViewController {
    @IBAction func touchNewGame() {
        game = Concentration(numberOfPairsOfCards: (cardButtons.count + 1) / 2)
        emoji = [:]
        theme = themes.randomElement() ?? defaultTheme
        updateViewFromModel()
        updateViewByTheme()
    }
    
    // MARK: - Theme
    lazy private var theme = themes.randomElement() ?? defaultTheme
    
    private func updateViewByTheme() {
        for index in cardButtons.indices {
            cardButtons[index].backgroundColor = theme.cardBackColor
        }
        background.backgroundColor = theme.backgroundColor
    }
    
    private var themes: [(emojis: [String], cardBackColor: UIColor, backgroundColor: UIColor)] = [
        (["🦇", "😱", "🙀", "😈", "🎃", "👻", "🍭", "🍬", "🍎"], cardBackColor: .systemOrange, backgroundColor: .black),
        (["🎅", "🧣", "☃️", "🥶", "❄️", "🛷", "⛸", "🏂", "🌨"], cardBackColor: .white, backgroundColor: .systemBlue),
        ("👷🧱🛠🦺🧰🚧🚜🪚".map { String($0) }, cardBackColor: .systemYellow, backgroundColor: .black),
        ("🌱🌷🌸🌹🌲🌵🍁🌴🌺🌼🌿🍃".map { String($0) }, cardBackColor: .systemGreen, backgroundColor: .systemBrown),
        ("💙💚💜❤️💛🤎💖🧡".map { String($0) }, cardBackColor: .systemBrown, backgroundColor: .systemPink),
        ("🌭🍑🥑🍝🥞🍦🍖".map { String($0) }, cardBackColor: .systemMint, backgroundColor: .systemPurple)

    ]
    
    private let defaultTheme = (emojis: ["🦇", "😱", "🙀", "😈", "🎃", "👻", "🍭", "🍬", "🍎"], cardBackColor: UIColor.orange, backgroundColor: UIColor.black)
}

  • 문제는 랜덤으로 선택한 테마를 적용하려면 수동으로 미니언들을 부려야 하는 데 말 그대로 명령을 내릴 시점이 없었다. cardButtons 는 UIButton 의 Collection 으로 ViewController 에서 초기화하는 친구들이 아니라서 init 에서는 업데이트할 수가 없었기 때문...이것 때문에 별의 별 생각을 다 하다가 우연히 과제 지시 사항의 Things to Learn 부분에서 viewDidLoad 를 봤는데 보는 순간 알 수 있었다...이 친구가 나를 구해줄 거라는 걸...

  • 공식 문서를 보면 viewDidLoad() 메서드는 view controller 가 자신의 view 체계를 메모리에 올린 직후에 호출되며, 이 메서드를 오버라이딩함으로써 view 가 초기화 될 때 추가적인 작업을 수행할 수 있다. 딱 내가 필요한 함수 그 자체...랜덤으로 선택된 테마에 따라서 배경화면과 카드 뒷면 색깔(즉, 버튼 색깔)이 로딩 시점에 업데이트 되도록 선언해줬더니 해결됐다.

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        updateViewByTheme()
    }

    private func updateViewByTheme() {
        for index in cardButtons.indices {
            cardButtons[index].backgroundColor = theme.cardBackColor
        }
        background.backgroundColor = theme.backgroundColor
    }
}

# flipCount 를 Model 로 옮기기

  • 이미 매칭된 카드를 누르는 경우 선택되지 않아야 하므로 이제 flipCount 을 Model 로 옮겨줘야 한다. Concentration 의 chooseCard(at:) 메서드에서 현재 누른 카드가 매칭되지 않은 경우에만 flipCount 가 증가하도록 했다.

  • 문제는 이제 이걸 어디서 view controller 의 flipCountLabel 과 연동해주느냐였다. 연산프로퍼티나 lazy 를 생각하긴 했는데 이러면 didset 을 쓸 수 없었다. 최종적으로는 결국 flipCount 또한 model 의 데이터에 따라 view 를 업데이트하는 것이므로, view controller 의 updateViewFromModel() 메서드에 flipCountLabel.text = "Flips : \(game.flipCount) 를 추가해서 해결했다


# "New Game" 버튼 추가

  • 스토리보드에 "New Game" 버튼이 될 새로운 UIButton 을 추가하고 눌렀을 때 호출할 touchNewGame() 이라는 메서드를 선언했다.
  • 메서드가 호출되면 초기화해야할 것들, 그러니까 비우거나 아니면 새로운 인스턴스를 대입하거나 해줘야 하는 친구들을 다 교체해주고 빌드했는데 새로운 버튼을 눌러도 뷰가 업데이트 되지 않았다. 이전 게임에서 뒤집힌 카드가 그대로 남아있고 테마도 그대로였다...
  • 이제는 SwiftUI의 세계가 아니라 UIKit의 세계이므로 내가 Controller 에서 직접 미니언들을 부려야하기 때문...updatViewFromModel() 메서드와 updateViewByTheme() 메서드를 호출해서 해결했다.
class ViewController: UIViewController {
    @IBAction func touchNewGame() {
        game = Concentration(numberOfPairsOfCards: (cardButtons.count + 1) / 2)
        emoji = [:]
        theme = themes.randomElement() ?? defaultTheme
        updateViewFromModel()
        updateViewByTheme()
    }
}

profile
☀️

0개의 댓글