여기 있는 controller에 대해 이야기해보자
Model이 필요한데 여기에 만들어둔 작은 Class를 생성할거야
FacialExpression(얼굴 표정)라는 이름의 클래스인데
여기로 드래그해서 여기 copy에 체크할거야
어떤 것을 드래그해 올 때 거의 항상 체크해야 할거야
copy를 원하고, link되는 것을 원하지 않는다면 집중해서 들어야 해
대부분 이렇게 해줄거야
미리만들어 둔 FacialExpression을 복사해 가져왔고
이제 FacialExpression 안을 살펴보자
여기 FacialExpression을 보면
이건 UI 같은 것이 아니라 Model이야
Foundation만 import 해왔고 UI와는 완전히 독립적이야
이 모델에서 얼굴에 대한 개념은 FaceView와는 달라
FaceView는 입의 곡률, 눈썹의 기울기 같은 것이지
여기에 그런건 없어
eyeBrows(눈썹)를 가지고 있긴하지만
Relaxed(편안한), Normal(일반), Furrowed(주름진) 만 있어
3가지 상태에 대해서만 알고 있지
Mouth(입)도 똑같아
Frown(찌푸린), Smirk(실실웃는), Neutral(평상시), Grin(활짝웃는), Smile(미소짓는)이 다야
입의 곡률을 가지고 있진 않지
그게 뭔지 몰라
하나 멋진 것은 여기 보이는 enum이야
enum안에 함수가 있는 걸 잘 봐
이 함수들을 실행하는 것에 대해선 이야기 하지 않을거야
읽기 과제를 본다면 알게 될거야
어쨌든 enum안에 함수가 몇 개 있어
FacialExpression은 enum으로 명시돼 있는 입, 눈, 눈썹인거야
여기 Eyes같은 enum은 상태를 가지고 있더라도
FaceView는 이것을 표현할 수가 없어
FaceView에는 Squinting(가늘게 눈을 뜬)은 없고
눈을 뜨고 감게 하는 법만 알뿐이야
그래서 중요한 것은 이 Model은 Controller에 의해서
View를 위해 해석되어야만 한다는 거야
Controller는 알아내야만 할거야
Model에 있는 EyeBrows에서 Relaxed가 무얼 뜻하는지 말야
FaceView 입장에선 눈썹의 곡률 같은 것을 의미하겠지
Controller는 이게 뭔지 알아내서 View에게 말해줄거야
이런게 MVC에서 Controller의 주요 역할이야
View를 위해 Model을 해석해주는 일이지
반대로 Model을 위해 View에 들어간 것들을 해석하기도 하지
그건 제스처(Gesture) 부분을 이야기할 때 보게 될거야
이게 Controller가 존재하는 제일 중요한 목적이야
그럼 Controller가 그런 일을 할 수 있도록 만들어보자
FacialExpression을 FaceView의 무언가로 바꿔 보는거지
Controller로 가서 제일 먼저 여기에 var를 만들거야
Model을 위한 포인터(pointer)이지
타입은 FacialExpression이 될거고
시작하려면 FacialExpression으로 설정을 할건데
FacialExpression은 구조체였던 것 기억하지
그럼 자동으로 만들어지는 초기화구조를 가져올 수 있는데
그건 그렇고 타입은 알아서 추론되도록 놔둘게
자동 생성되는 초기화구조를 가져와서
눈은 뜬 상태로 두고 (eyes: .Open)
눈썹은 그냥 일반으로 둘거고 (eyeBrows: .Normal)
입은 웃도록 해볼게 (mouth: .Smile)
이게 FacialExpression의 기본값이 될거야
이것이 우리 MVC의 Model이지
이 Model에서 재미있는건 만약 값이 바뀐다면
나의 View를 새롭게 업데이트 해야 하지
웃고 있던 입을 찡그리도록 바꾸면
FaceView에서 곡률 값을 바꿔야만 할거야
그렇게 하기 위해 전에도 썼었던 마법인 didSet을 사용할거야
FacialExpression이 바뀔 때마다 UI를 업데이트 하기 위해서지
그리고 이 FacialExpression은 값 타입이니까
이 변수 중 하나라도 값이 바뀌면 didSet이 불릴거야
이게 Class였다면 그렇지 않았겠지
다행히도 이건 값 타입이니까
이 부분이 호출될거야
이렇게 updateUI( ) 함수가 필요한데
여긴 다른 함수가 들어가도 좋아
난 updateUI( )를 해주는 걸 선호하긴 하는데
너희가 원하는 걸 해도 좋아
private func updateUI로 함수를 선언할건데
여기 안에는 FaceView를 업데이트하는 내용이 들어가야겠지
FaceView를 업데이트한다면 그것에 대한 포인터도 필요해
어떻게 view안에 포인터를 만들수 있을까?
control키를 누른 채 드래그 했었지
outlet을 만들었는데 그렇게 해보자
스토리보드로 가보면 여기 FaceView가 있지
이쪽엔 FaceViewController가 있고
FaceView로부터 여기로 ctrl + 드래그하고
faceView라는 이름의 outlet을 만들거야
계산기 앱에서는 display라고 했고 여기선 faceView지
이렇게 해주면
이제 이 outlet이 만들어졌어
이 얼굴에 대한 포인터가 생긴거야
이제 이 얼굴에 곡률이나 모든 것들을 설정하라고 말할 수 있어
이제 이것을 가르키는 포인터를 생겼고
updateUI( )안에서 포인터에게 말해서
얼굴 표정에 따라 설정해 줄 수 있어
그럼 어떻게 할 수 있을까?
첫번째로 눈부터 해볼거야
만약 FacialExpression의 눈이 떠 있는 상태라면
FaceView에 메시지를 보낼 거야
faceView.eyeOpen = true 라고 말이야
이건 간단한 편이야
faceView인데 모델에서 하는 방식과 매우 비슷하지
눈이 감겨있을 때도 마찬가지야
faceView.eyeOpen = false
하지만 가늘게 눈을 뜨는(Squinting) 경우는 어떻게 할까?
faceView에는 squint가 없어서 이전처럼 할 수 없지
그럼 일단 faceView.eyeOpen = false으로 해둘게
눈을 가늘게 뜬 건 눈을 감은 것에 더 가까울테니까
내가 할 수 있는 최선의 방법이야
가끔은 컨트롤러는 이렇게 할 수 밖에 없을 때도 있어
뷰는 모델을 표현할 때 완벽히 들어맞지 않을 수도 있지
대신 할 수 있는 한 최선을 다 해보는 거야
FaceView에게 우리의 요청을 보낼지도 모르지
이렇게 말하면서 말이지
"이봐, 우리는 FaceView에 눈을 가늘게 뜨는 항목을 넣고 싶어"
"왜냐하면 모델에는 그 항목이 있으니까"
그럼 그들은 "너희 제안을 받아들여서 고려해 볼게"라고 할거야
하지만 우린 지금 꼼짝 못하고 있는 상태야
지금은 가늘게 눈을 뜨는 상태를 눈을 감은 것으로 둘거야
나머지 두가지는 어떨까?
그걸 처리하기 위해 곡률(curvatrure)이 있는거야
이렇게 하면 될거야
faceView.mouthCurvature = expression.mouth 라고
하지만 expression.mouth는 웃음 또는 찡그림 같은 거였어
도대체 우리가 뭘 해야할까?
저걸 어떻게 곡률을 바꿀 수 있는걸까?
private 딕셔너리를 하나 만들거야
이름은 mouthCurvatures(입 곡률들)이라고 복수형으로 할게
등호('=')를 사용해서 바로 딕셔너리를 만들거야
대괄호 [ ]로 딕셔너리를 만들 수 있었던 것 기억하지
딕셔너리의 키(key)는 모델의 mouthCurvatures로 할거야
딕셔너리의 값(value)는 뷰에 대한 mouthCurvatures 이지
Double 타입이 될거고
예를 들어, FacialExpression.Mouth.Frown이라고 해보자
이게 키이고 값은 -1.0가 될거야
이 곡률 값에 따라 입이 그려질거야
무슨 말하는지 이해가 되니?
딕셔너리 이렇게 하나 만들었어
이렇게 해서 모델과 뷰 사이의 맵핑을 만든거야
*맵핑(mapping): 데이터간의 대응관계를 설정
그럼 'Grin'은 어떤 값과 대응시킬까
그건 그렇고 'Grin'을 적을 때 한가지 주목할게 있어
이미 FacialExpression.Mouth까지 접근하는게 추론됐으니까
매번 이 부분을 반복할 필요는 없어
그냥 .Grin이라고만 하면 돼
Grin에 해당하는 값은 0.5 로 할거야
활짝 웃는게 아니고 살짝 웃는 표정이니까
활짝 웃는건(.Smile) 1.0 가 되겠지
.Smirk(히죽거리며 웃음)는 찡그림(Frown)이 약간 들어가지만
많이 찡그리게 하진 않고 -0.5 정도로 둘게
마지막으로 Neutral(무표정) 입은 0.0 이 될거야
이렇게해서 mouthCurvatures 테이블을 만들었어
아래로 내려와서
mouthCurvature = mouthCuravtures[expression.mouth]
라고 해줄게
여기 에러가 하나 생기는데 무슨 문제인지 아는 사람?
이 부분은 딕셔너리를 검색(lookup)하는 부분이야
딕셔너리 look up이 뭘까?
어떤 타입을 반환할까?
옵셔널이야
근데 이건 Double이지 옵셔널이 아니지
그럼 이걸 어떻게 처리해야 할까?
만약에 FacialExpression이 추후에 업그레이드가 되었는데
찾고자 하는 expression이 없다면?
그럴 땐 기본값을 0을로 둘거야
이렇게 기본값을 설정하는 것 기억하니?
Double 타입의 어떤 값을 가져오려고 시도했는데
nil을 반환하면 nil 대신 이 기본값을 반환하는거야
이해되니?
여기 var가 빠졌네
지금까지 한 것 모두 알겠니?
계산기 앱이랑 비슷하니까 도움이 되길 바라
딕셔너리를 검색해서 값을 가져오는 부분 말이지
눈썹 기울임(eyeBrowTilt)에도 같은 방식을 쓸거야
eyeBrowTilt = eyeBrowTilts
eyeBrowTilts는 딕셔너리가 되겠지
[ ]안에는 expression.eyeBrows를 넣을거야
여기도 기본값으로 0을 넣어줄거야
찾지 못했을 때를 위해서지
여기에 private 변수를 만들고
eyeBrowTilts라고 부르자
이건 FacialExpression.Eyebrows.Relaxed가 될거야
Relaxed의 값은 CGFloat(0.5)이 될거야
이건 릴랙스한 눈썹모양이지
이런, CGFloat이 아니고 0.5이지
이건 Double 타입이야
eyeBrowTilts의 타입은 Double이니까
저기엔 CGFloat이 아니지
.Furrowed(찡그린)는 -0.5 만큼 기울일거야
.Normal(일반)은 0.0 로 만들거야
이해되지?
이렇게 해서 눈썹도 입처럼 딕셔너리 검색이 가능해졌어
이제 모델을 뷰와 대응시켰어
뷰를 위해 모델을 해석해주었지
일단 실행해보고 어떻게 보이나 확인해보자
흠...별로 좋아보이지 않는군
왜냐하면 모델을 확인해보면
눈은 뜬 상태가 되어야하는데 그렇게 보이고 있지
눈썹은 Normal인데 여기선 Normal이 아니지
찡그린 상태야
입은 웃고 있어야 하는데 그게 아니라 찌푸리고 있군
여기 보이는 모든 것들은 모델에서 설정한 UI가 아니라
여전히 스토리보드에 설정한 상태로 보이고 있어
그럼 왜 여기서 updateUI( ) 메소드가 불리지 않는걸까?
우리가 FacialExpression을 초기화할 때 말이지
그건 초기화 중에 값을 설정하면 didSet이 불리지 않기 때문이야
설정한 이후에만 불리지
왜 그럴까?
Swift에서 어떤 것이 초기화가 되고 있을 때
그걸로 무엇이든 하기 전에 완전히 초기화 되어 있어야 해
물론 여기서도 이걸로 뭔가를 하기 전에 초기화되어야 하는거지
이 초기화는 이뤄졌지만 이 updateUI( )는 불리지 않았어
FaceViewController를 초기화하는 단계서 발생했기 때문이야
이 expression을 나중에 설정했으면 updateUI( )가 불리고
UI가 바뀌었겠지
그럼 어떻게 처리해야할까?
어쨌든 해야만 했던 일이긴 하지
시스템에 의해 faceView outlet이 설정되었을 때
여기에서 didSet를 하고 updateUI를 호출할거야
이 didSet이 불리는 건
MVC가 생성된 직후에 iOS가 나타나고
이 outlet이 연결될 때 불릴거야
outlet에 연결되어서 실질적으로 faceView를 가리킬 때야
그래서 그렇게 되자마자 faceView를 지배할 수 있게 되고
그 땐 업데이트 할 수 있는거야
모델이 바뀔 때와 처음 뷰와 연결이 될 때 모두 업데이트 될거야
보통 이렇게 짧을 때는 한 줄로 정리해
여기도 그렇게 할 수 있지만
우리가 하고 있는 걸 강조하기 위해 이건 그냥 이렇게 둘거야
저렇게 넣는 방식이 흔하긴 해
이제 실행해보자
iOS가 나타나고 FaceView가 연결될거야
짠! 모델 설정대로 얼굴이 업데이트 됐네
여기에 있는 모델을 바꿔보면, 눈썹은 편안하게 하고
입은 히죽거리게 하고 눈은 감도록 만들어보자
모델에 있는 얼굴 표정을 바꾸었으니
뷰는 모델을 반영해야 할거야
이렇게 말이지
모두들 모델로 여기까지 만들어 본 것 이해하니?
'연습 > swift개발' 카테고리의 다른 글
4.11 얼굴에 제스처를 적용해보자 (0) | 2022.01.20 |
---|---|
4.10 제스처는 어떻게 만들까 (0) | 2022.01.20 |
4.8 다양한 얼굴 표정 (0) | 2022.01.20 |
4.7 얼굴앱 - 눈 넣기 (0) | 2022.01.20 |
4.6 얼굴앱 - 스토리보드 연결 (0) | 2022.01.20 |