
무엇 인지를 나타내는 부분으로 UI 와는 무관사용자에게 어떻게 보이는지 를 나타내는 부분으로 UI 로직Controller 는 Model 과도 직접적으로 소통할 수 있고, View 와도 (outlet 을 통해) 직접 소통 가능
Model 과 View 는 어떤 방법으로도 소통이 불가
View 는 Controller 와 소통할 수는 있으나 blind and structured 한 방식으로만 가능
blind : View 는 generic 이므로 Controller 에 대해서 아무것도 모름structured : Controller 와 어떻게 소통할 지를 미리 정해야 함View 와 Controller 간의 보다 복잡한 의사소통은 delegate 을 통해 이루어짐.
View 는 Controller 로부터 데이터를 받아서 디스플레이함
Controller 의 역할은 Model 의 데이터를 View 에 전달하고, View 에서 발생한 사용자 상호작용을 Model 에 전달하는 것
Model 은 Controller 와 직접적으로 소통은 불가능하지만 라디오와 유사한 방식(KVO: Key Value Observing)을 사용해 간접적으로 소통 가능. Model 이 방송을 시작하면 Controller 가 이를 듣고 적절히 반응
여러개의 MVC 가 함께 협동하는 경우 하나의 MVC 는 다른 MVC 들을 자신의 View 의 일부처럼 다루기 때문에 blind and structured way 로 소통
해당 클래스에 포함된 모든 메서드와 프로퍼티들의 목록
public API : 어떤 클래스의 API 중에서 다른 클래스들이 호출할 수 있는 모든 메서드와 프로퍼티. 즉, 이 클래스의 사용 방법
Concentration 게임을 하기 위해 필수적인 요소는 카드와 카드를 선택하는 것이므로 Model 은 cards, chooseCard(at:) 라는 2개의 public API 를 갖는다. 카드의 개수는 초기화 시 Controller 로부터 받아온다.
SwiftUI + MVVM 에서의 Model 과 사실상 같은데 여기서는 클래스로 선언한다는 차이가 있다.
Public API : flipCountLabel, cardButtons, touchCard(_:)
Private : emoji(for:), updateViewFromModel(), flipCount, game
MVVM 에서는 Model 과 View 간의 중개자 역할이 더 강했다면 이제 View 는 minion 에 불과하므로 Controller 의 역할이 확대됐다. 이제 Model 의 업데이트를 View 에 단순히 전달하는 게 아니라 그에 맞춰 View 가 어떻게 변화해야하는 지 까지 지정한다.
SwiftUI + MVVM 이었다면 updateViewFromModel() 이나 flipCount 는 View 에서 구현했을텐데 MVC 에서는 Controller 의 역할이 됐다. 전에 다른 글에서 확장성 문제 때문에 이제 MVC 는 지양되고, MVVM 이 선호된다는데 UIKit 를 사용할 때 MVVM 패턴으로 구성하면 어떤 모습일 지 아직 잘 모르겠다....뭔가 여기서의 View 는 할 수 있는게 너무 적어보인다 아직 스토리보드를 쓰고 있어서 그런가?
class Concentration {
init(numberOfPairsOfCards: Int) {
for _ in 1...numberOfPairsOfCards {
let card = Card()
cards += [card, card]
}
cards.shuffle()
}
}
Controller 와 Model 을 연결하기 위해 Controller 내부에서 Model 을 아래와 같이 선언하면 초기화 중에 다른 프로퍼티 cardButtons.count 을 사용하기 때문에 컴파일 에러가 발생한다.
이를 해결하기 위해 lazy 키워드를 사용할건데, 변수 앞에 lazy 를 덧붙이면 게을러지므로 누군가가 실제로 해당 변수를 호출하기 전까지는 초기화되지 않는다!
다만, didset 과 같은 property observer 를 사용할 수 없다는 단점이 있다.
class ViewController: UIViewController {
lazy private var game = Concentration(numberOfPairsOfCards: (cardButtons.count + 1) / 2) // to protect from odd number
}
Model 에서 변화가 발생하면 View 를 해당 변화에 맞춰 업데이트 해줘야 하는 데, 이는 미니언들을 부리는 Controller 가 할 일이다. SwiftUI 를 배울 때는 그냥 View 에 ViewModel 을 넘겨줘서 View 에서 변화를 감지하고 스스로 어떻게 변할 지 결정하게 했는데 좀 낯선 부분이었다.
사용자가 카드를 누를 때마다 Model 에서 변화가 발생할 것이므로 updatViewFromModel() 을 호출해서 View 도 변화시킨다.
class ViewController: UIViewController {
@IBAction func touchCard(_ sender: UIButton) {
flipCount += 1
if let cardNumber = cardButtons.firstIndex(of: sender) {
game.chooseCard(at: cardNumber)
updateViewFromModel()
} else {
print("choosen card was not in cardButtons")
}
}
private 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 = .white
} else {
button.setTitle("", for: .normal)
button.backgroundColor = card.isMatched ? .clear : .orange
}
}
}
}
class ViewController: UIViewController {
private var emojiChoices = ["🦇", "😱", "🙀", "😈", "🎃", "👻", "🍭", "🍬", "🍎"]
private var emoji = [Int: String]()
private func emoji(for card: Card) -> String {
if emoji[card.identifier] == nil, !emojiChoices.isEmpty {
let randomIndex = Int(arc4random_uniform(UInt32(emojiChoices.count)))
emoji[card.identifier] = emojiChoices.remove(at: randomIndex)
}
return emoji[card.identifier] ?? "?"
}
}


Controllers can always talk directly to their Model
Controllers can also talk directly to their View (eg. outlet)
The Model and View should never speak to each other
the View can speak to its Controller but it has to be blind and structured (e.g. target(method)-action)
- blind in that Views are generics and so they don't know anything about a concentration game controller, it doesn't even know that its a concentration game controller
sometimes the View needs to synchronize with the Controller(e.g ScrollView(view item) may ask controller can I scroll horizontal? verticle?). complicated communications are done with predfinded methods (that the scrollView) defines as part of its delegate. a delegate is just a var in ScrollView that, and this var will have some object in it, and all we know about this object is that it responds to a certain number of messages. Most of these messages start with the words nil, should, or did. and the Controller, using a mechanism called protocols, is able to tell the scroll View, I'm ur delegate, and all the scroll View will know is that it implements will, should, and did. It doesn't know anything about it, such as it class,
Views do not own the data they display. they r not gonna have the data they're displaying as part of their instance variables. instead they use the same kind of protocol mechanism to have another set of special messages to get the data from the data source and Controllers are always that data source not Model. it;s Controllers get the data from the Model.
Controller's job in MVC is to interpret and format the model's info for the View and it interprets user interaction in the View for the model
Model can't communicate directly with the Controller but, it can indirectly communicate when it has info to update or sth to inform. It uses a 'radio-staion'-like broadcast mechanism(i.e. notifications, KVO(Key Value Observing), in which the model starts broadcasting on a certain known radio station, and the controller up there, it's just gonna tune in and when it hears that sth has changed on the models radio station, then it's gonna use its big green arrow, to go to the model to get the data that has changed or whatever
when an MVC works with another MVC, it treats other MVC's as part of its View, so it has to talk to them in a blind, structured way