프로토콜을 이용해보자
이전 글에 이어서 프로토콜을 통해 VC2 -> VC1으로 데이터를 전달해보겠습니다!
이전글 Summary
VC2의 코드중 핵심은 위 이미지 중 아래 코드와 같습니다.
var delegate: VC1
타입이 VC1클래스 였고, 여기서 꼭! 해줘야하는건 아래 그림처럼 특정 클래스와 연결을 시켜줘야 했습니다.
연결 방법은 간단했죠
vc2.delegate = self
이런식으로 “그 delegate는 나야”를 정해주면 데이터 전달이 가능하다는것이 저번 내용이었습니다.
하지만, 이 방법도 좋지만 단점도 있습니다.
이전 방식의 단점
결론부터 말하자면, **VC1 타입만 이전 방식이 가능하다 ** 입니다.
이게 무슨말인지 감이 안오신다면! 이렇게 생각해보세요.
VC2 -> VC1에 이름 값을 전달 해주는 화면이었죠, 그런데
이름을 전달받는게 저화면뿐만 아니라면 어떻게 될까요?
다르게 표현 해볼까요? 이번엔 멋진 그림으로
우선 기존 방식입니다.
VC2가 VC1의 내부 함수를 호출하는 방식이었죠,
그렇담 아래 같이 새로운 VC3라는 클래스가 나타난다면 문제가 생깁니다.
그렇담 여기서 VC2의 아래 코드는 어떻게 변경되어야할까요?
var delegate: VC1
// 추가
var delegate2: VC3
이름을 delegate2라곤 안하겠지만! 개념상 그건 중요치 않으니 패스,
중요한건 VC3 클래스 타입을 가진 변수가 추가된다는 점입니다.
크게 문제 될건 없지만,,,, 프로토콜을 이용한다면 장점이 더 많습니다!
프로토콜
그렇담 프로토콜은 무엇일까요?
넷플릭스에 나오던 미국 드라마중 ‘지정생존자’란 드라마에서
무슨 위급한 상황이 생기자,
“OOO 프로토콜을 발동하지”
이런 표현을 쓰는게 나오더군요!!
그러자, 정해진 역할들을 수행해 나가더라구요
네, 그래도 감이 안오는 경우가 많을거라 생각합니다, 저도 그랬거든요.
그렇담, 또 다른 표현!
이번엔 책에서 주로 나오는 내용을 좀더 쉽게 설명해볼게요.
‘이동 수단’에 대해 얘기해볼까요?
이동 수단은 좀 상위 개념이죠, 하위 개념엔 자동차, 자전거, 버스, 택시, 기차 등등이 있을겁니다.
근데, 이것들이 공통적으로 가져야할 개념이 있죠,
빵빵이 기능입니다, 클락션이라고도 하죠?
이동 수단이라 하면, 타인에게 자신의 의사를 표현할 방법이 필요하죠! 위험해라던가 뭐라 표현을 해야하니깐요!
이 빵빵이 기능을 탑재 해야하는 시스템을 빵빵이 프로토콜 이라고 합시다, 클락션 프로토콜이라 하면 이름 생각하다 중요한걸 잊을테니,,
그럼, 이제 자동차를 만들어 봅시다,
윗사람이 지시를 내립니다, “자동차를 만들땐 빵빵이 프로토콜을 적용해.”라고
그렇담, 윗사람의 지시 -> 무조건 넣어라 겠죠?
대신 빵빵 소리는 상황에 따라 바꿉니다, 지하철, 버스, 자전거 등등 서로 다르게요.
이러면 좀 감이 오시나요? 위의 드라마 얘기도 이해 되실겁니다!
프로토콜을 실행하자 각자 해야할 일들을 수행해나간다
=
프로토콜을 실행하면 각자 할일들도 있지만 무조건 해야할 것들이 생긴다.
그럼 좀더 프로그래밍틱하게 설명을 해볼게요.
프로토콜 선언
protocol Bbang {
func warning(name:String)
}
위의 코드가 프로토콜을 선언하는 것입니다.
Bbang(빵-빵빵이의 빵)이라는 이름을 가지고 있고
함수를 하나 가지고 있습니다.
그런데 뭔가좀 허젼하죠?
함수명, 인자값등이 있지만 함수 내용이 없습니다.
반환값도 있다고 보시면 됩니다! 지금은 상황상 표현을 안했지만 Void로 리턴하고있을테고
다른 리턴값이 필요하시면 리턴형을 일반 함수때처럼 적어주시면 됩니다.
자세한 내용은 프로토콜 사용되는곳에서 기술 해주면 됩니다.
마치 이런거죠,
빵빵이 프로토콜을 택시, 자전거에 적용해!
했을때, 자전거 만들땐 경적소리를 “띵띵” 할거야, 택시는 “빠앙” 할거야 등은 자기가 맘대로지만
중요한건 “경적소리 울리는 함수가 들어가야한다는 점입니다.”
함수만 선언 가능한것은 아닙니다! 변수도 선언 가능해요
하지만, 마찬가지 값을 넣어주지 않습니다만
get,set 은 기입해줘야합니다. 아래처럼요!
var text: String {get}
var text: String {get set}
자 그럼 어떻게 사용하는지 볼까요?
변경된 라인은 42,54 쪽입니다. 프로토콜은 33번에 선언 되어있구요
기존에 43번 라인의 변경점은 타입이 VC1에서 Bbang으로 바뀌었단 점입니다.
이건 무슨의미일까요?
단순하게 타입이 바뀌었다고 볼수 있지만,
좀더 좋은점을 위의 VC3애기로 들자면, VC1이든 VC3이든, 저 delegate 변수 하나로 사용이 가능하단점이죠!
var delegate: VC1
// 추가
var delegate2: VC3
이런건 안해도 됩니다!
var delegate: Bbang
이것으로 다 해결 했거든요.
그리고 변경점2(line:54)의 경우엔
VC1의 함수를 호출은 이제 못하고(당연하죠?), Bbang안에 있던 waring(name:)을 호출해주었습니다!
그럼 VC1쪽에 바뀐점은 무엇일까요?
바꾸기전에 아무것도 안하고 나오는 오류를 봅시다.
“Cannot assign value of type ‘VC1’ to type ‘Bbang?’“
“(VC1)은 Bbang 타입이 없음 / Bbang에 VC1 넣을 수 없음” 이런 의미의 경고가 뜹니다
그럼 저 빨간점을 누르고 싶겠죠? 하시면 안돼요.
프로토콜 추가
빨간점눌러서 자동 해결 기능을 쓰면
vc.delegate = self as! Bbang
이런식으로 타입을 맞춰서 얼렁뚱땅 넘어가려합니다.
된다하더라도 우리에게 중요한건 아직 빵빵이의 상세 기능을 추가안했죠.
택시일땐 무슨빵빵, 자전거는 무슨빵빵 할지 정해줄겁니다.
그렇담, 프로토콜 추가는 어떻게 해줄까요?
클래스 상속 받듯이 하면됩니다.
class VC!: UIVIewController, BBang {
// 내용 생략
}
이런식으로요!
여기서, 특이한점이 하나 있습니다.
다른 언어 중 일부에선 다중상속이 가능하죠, 그렇지만 Swift에선 하나만 상속이 가능합니다, 그래서 UIVIewController를 상속 받았으면 이젠 다른건 못받습니다. 이유가 있어서 애플에서 막았겠죠? 그렇지만 일부 기능은 아쉬운 기능입니다.
따라서 애플에선 프로토콜을 이용해 이를 어느정도 해결했다고 합니다!! (좀더 찾아봐야겠어요)
프로토콜의 경우 클래스 상속과는 다르게 제한이 없습니다, 그래서 한개든 두개든 가능하죠
그럼 코드를 봐볼까요
오류가 납니다.
“Type ‘VC1’ does not conform to protocol ‘Bbang’“
“VC1 타입은 Bbang 프로토콜을 따르지 않았다”
“VC1 타입은 Bbang 프로토콜을 준수하지않았다
이런 의미가 나옵니다.
즉, 위의 예시에서 **빵빵이 프로토콜 적용하라는 윗사람 말을 듣지않았다!!**가 됩니다.
프로토콜에 있던 warning 함수를 적용해줘야합니다. 내용까지 채워서요(line:17)
(여기선 빨간점 눌러서 자동 해결해도됩니다. 좋은 기능)
여기서 함수 내부 내용은 insert(name:_)과 같은 것을 사용했습니다.
그리고 동작도 똑같이 될것이구요! 이렇게하면 해당 내용은 모두 끝나게 됩니다.
마무리
사실 다른 장점들도 있습니다.
var delegate: VC1
// 추가
var delegate2: VC3
위의 코드같은 문제가
var delegate: Bbang
이렇게 사용하여 여러 VC들에서 사용 가능하단점들 말고도 좋은점은
협업 하는사람들이 알아보기 쉽다.
추가 해야할 것이 명확하다.
같은 것들이 있습니다, 물론 더 있습니다! 이런 방식 말고도 다른 방식으로도 사용가능합니다.
그리고, 윗사람이 시켰으니깐 무조건 따라야한다 « 라고 표현 하긴했지만,
필수가 아닌 함수, 변수들도 선언이 가능해요.
1의 경우 무슨말이냐, 다른 사람이 내 코드를 볼때 프로토콜 사용하기전에
insert(name:_) 이 함수를 봤다면 무슨 생각을 할까요?
“이건 이 클래스내에서 호출이 안되는데 왜있어?” 라고 생각 할 수 있겠죠,
검색해도 안나오니깐요, (헉 이때, privite을 쓰면 알 수 있겠네요!!! 구분용으로 써줄수도 있겠네요 ㅜㅜ
글쓰다 깨닳음,,, 도대체 언제 왜 써야했는데,,, 이게 전부는 아니겠지만 용도 하나는 찾았습니다. 블로그 소재써야지 )
위에 깨닳음을 통해 말하자면, private인데 검색해서 안나오면 지워도 되겠네요,
그렇지만 전 안썼고 누가 제 코드를 보고 저 함수를 봤다면, “뭐야 이건 왜안지웠어?” 했을겁니다.
하지만 프로토콜을 썼다면 다른 사람이 보고, 아 여기엔 이런 함수들이 들어가있겠구만
그렇다면 다른 화면에서 데이터를 받아오겠네, 라고 생각을 할 것 입니다!
프로토콜은 swift에서 많이 사용되고있습니다.
테이블뷰를 써보셨다면, cellForRow와 numberOfSection 등등 함수를 적용 안하면 오류 난다고 경고를 뿜죠
그래서 해당 함수들을 자동완성 기능으로 넣어보면, 내부는 깔끔하게 비어있죠!
이것도 마찬가지로 해야할 것들을 알려줬을뿐 내용은 자기맘대로 하란것입니다. 리턴 규격도 지켜야하구요!
위에 보시는 바와 같이, 프로토콜입니다! 이외에도 UIScrollViewDelegate, UITableViewDelegate등등
프로토콜로 이루어져있습니다!
더 코드를 좋게 하려면 프로토콜 추가 별로 Extension 쓰는게 좋더라구요~
그래서 다음 주제는 Extension 입니다.
수고하세요~!