SwiftUI

SwiftUI ) Mojave에서 써보기 / UIHostingController, UIViewControllerRepresentable, UIViewRepresentable

Zedd0202 2019. 6. 10. 09:56
반응형


안녕하세요 :) Zedd입니다.

역시 저는 집에있으면 안돼요..나와야ㅕ해...........

방금 SwiftUI Essentials을 봤는데, 정말 흥미로운 사실들이 끊임없이 나오네요..!!!

근데 이거 보는거 너무 뭐랄까..지루함..

내용은 재밌는데 이게 보는게 너무 힘드네요zzz

그래두 하루에 하나씩...이렇게 보면....보고싶은거 다 볼 수 있겠지..

WWDC때문에 빔프로젝터를 사고싶은 마음이 굴뚝같ㅎ습니다..


회사의 모든 iOS개발자들이 모여서 다같이 감상하면 얼마나..재밌을까여ㅛ...

한 50명정도 모여서..박수치면 우리도 박수치고...막 기립박수 하면서..허허 참 저친구들 대단해 하면서..

이야기 꽃을 피우며...커피 마시면서 아주 건설적인 토론을 하면서...어떻게 적용할지 이야기하면서ㅏ..


회사에 대한 그런 로망 있잖아요!? 하하



자 암튼 제가 어제 Catalyst도 써보고..SwiftUI도 써봤는데, 이거 2015년 맥북으로는..거의 비행기 수준.


그래서 모하비 && Xcode 11 베타 플레이그라운드에서 SwiftUI를 사용해보도록 할게요.

사실 SwiftUI프로젝트 하나 만들고 그냥..빌드하는거랑 똑같습니다. 

근데 굳이..굳이.........오른쪽에 마치 Canvas가 있는 듯한..그런 느낌을..받고싶다면....Playground로 해보는 것도 나쁘지 않겠죠.



플레이그라운드를 하나 만들어줍니다.



Single View를 선택해줍시다.



그럼 이런 화면이 나올텐데



일단 위에거 다 주석처리하고 SwiftUI를 import해줍시다.



그리고..SwiftUI프로젝트에 기본적으로 있는 View를 일단 가져와볼게요?



자, 뭔가 코드가 늘어났는데, 위 ContentView는 제외하고 맨 아래에..코드를 봅시다. 

PlaygoundPage~ 얘네를 쓸려면 PlaygroundSupport를 import해야합니다. 

그래서 위에 PlaygroundSupport가 import되었죠?


UIHostingController라는게 있죠? 

UIHostingController가 뭔지 알아봅시다.




아니 저기요.

정의는 있어야지


뭐 SwiftUI 튜토리얼에 잠깐 있는 설명을 하자면..


UIHostingController는 UIKit컨텍스트 내에 SwiftUI view를 나타내는 UIVIewController의 하위클래스입니다.

위 그림을 잘 보시면, SwiftUI프레임워크 안에 있는 칭구입니다.




짠?


자 

UIHostingController는 UIKit컨텍스트 내에 SwiftUI view를 나타내는 UIVIewController의 하위클래스입니다.

이 말이 모냐

지금 기존에 우리가 만든 프로젝트들은 SwiftUI프로젝트가 아니잖아요????
근데 거기에 SwiftUI로 만든 View넣어보고싶음..그럼 어카냐 이거죠
그럴떄 UIHostingController를 사용하면 된다₩~ 이거같은데..
그럼 진짠지 함 보자
 
non-SwiftUI 프로젝트를 열어줍니다.


어제 썼던 칭


일단 이 프로젝트는 SwiftUI프로젝트가 아니기 때문에 그 SwiftUI프로젝트에 기본적으로 있는..ContentView인가 그거 없음..

암튼 우리가 SwiftUI view를 하나 만들어줘야겠죠!?!?




SwiftUI View를 추가해줍시다.


 

예에ㅔㅔ~~


그럼 SwiftUI view는 만들어졌고.......이 SwiftUI view를 띄워볼까요? 

자;;;;암튼 뭐 저 버튼을 누르면 우리의 ZeddView가 나왔으면 좋겠읍니다..


버튼에 action을 줘볼까욘??!!?



자 줘따 그쵸.

자 위그림의 코드를 보면 우리가 늘 일반적으로 보는 코드잖아요?

UIKit이 import되어있고......암튼 그렇잖아요?


이 UIKit 컨텍스트 내에 SwiftUI view를 나타내고 싶으면 뭐가 필요하다!?!?!?!?!

UIHostingController ㅇㅇ

근데 아까 제가 잠깐 언급했는데.. UIHostingController이 친구는

SwiftUI프레임워크 안에 있는 아이라서 SwiftUI를  import해줘야합니다.



자, import 해줬어요!!


리구 이제 UIHostingController를 불러봅시다. 그냥 똑같에요. 

우리 뭐..storyboard선언하고..viewController선언하고..그걸 present하거나 push해줬잖아요?

똑같습니다..



UIHostingController는 UIViewController의 하위클래스라고 그랬죠?

그러니까 당연히 present메소드의 viewControllerToPresent파라미터에 들어갈 수 있는건..당연하죠!!!??


어차피 SwiftUI는 스토리보드 이런 개념이 아니잖아요? 그래서 storyboard에서 viewController를 가져올 필요도 없고..그냥 UIHostingController만 있음 댐

앗 근데 이렇게 제가 너무 단정지어서 말하는군요..

아닐수도 있습니다,,,,,,,,


그럼..실행해봅시다.





넘 쉽다 그쵸

ㅎㅎㅎㅎㅎㅎㅎ


헐..

아 이게..UIHostingController..아 음..

그니까 SwiftUI와 UIKit을 intergrate하기 위해 UIHostingController말고도 다른 개념들이 몇개 더 있네요???

아 흠...


ㅇ ㅏ~~~~~헐....그렇군...


자 후하후ㅏ하후ㅏ 자 여러분..

자 그럼 간단하게 생각합시다.


지금 우리는 UIKit에 SwiftUI를 연결한거에요. 

그 view Controller hierarchy에 SwiftUI viewController를 추가한거죠!!!!

그럴때 쓰는게 UIHostingController고, 


반대의 상황이 있을 수 있겠죠. 지금처럼 UIKit베이스(?) 아니 이걸 뭐라해...암튼 지금!!! UIKit쪽에서 SwiftUI를 부른 상황이라면

SwiftUI쪽에서 UIKit controller(?) 를 부를 수 있잖아요??? 

아니 이걸 이렇게 표현해도 맞는지;; 잘 모르겠네요. 그냥 느낌만..알아채시면 될 것 같습니다.


그니까 SwiftUI도 navigation있고 뭐 다 있잖아요? 걔네도  view Controller hierarchy가 있을텐데, 

거기에!!! UIKit View controller를 추가 하는 상황도 있을거 아니에요????? 


그럼 그때는 어떡하냐 이거죠.

그럴때는 그럼 SwiftUI코드에서..스토리보드 선언하고..viewController얻어와서...걔를 또 어떻게 띄워주는것이며....


그 상황을 한번 해볼게요!?


그럼 우리가 지금 만든 앱에서 더 나아가 봅시다.

우리가 지금 첫 화면은 UIKit(?) viewController에요. 그리고 Button을 누르면 SwiftUI ViewController가 뜨게했죠.

그럼 이 SwiftUI ViewController에서 UIKit ViewController를 띄워줘봅시다!!!!!!!! 하하



뭐 이렇게 UIViewController를 선언해줬습니다. 늘 보던거잖아요?? 그쵸??

그럼 아까 우리 UIHostingController가 있었듯이..SwiftUI에서 UIKit viewController를 부를 수 있도록 뭔가 또 있겠죠? 



그것이 바로 UIViewControllerRepresentable입니다. 

애플이 설명하는 UIViewControllerRepresentable를 보면,




Create a structure that conforms to UIViewControllerRepresentable and implement the protocol requirements to include a UIViewController in your SwiftUI view hierarchy.


UIViewControllerRepresentable를 준수하는 struct를 만들고, 

SwiftUI view hierarchy에 UIViewController를 포함하도록 프로토콜 요구사항을 구현하세요.





ㅇㅋ.,.........


아니 이것때매 한 30분 헤맨듯Zzzz

아니 자 우리가 늘 보던 UIKit ViewController는 일단 class잖아요? 

일단 UIViewController를 상속받아야 하는데..

class여야 하잖아??? 근데 struct를 만들래


zzzz그래서 뭐 어케어케 했습니다..



자. 하나씩 볼게요? 



일단 struct를 만들래서 만들었습니다. 그리고 UIViewControllerRepresentable를 채택했죠.

그럼 에러가 날텐데요. UIViewControllerRepresentable은 프로토콜이니 뭔가 요구하는 메소드나 그런게 있겠죠? 



ㅇㅇㅋ



그럼 이런 typealias가 생깁니다. 여기에!!!!! ㄴ우리가 아까 만든 그 UIKit ViewController를 넣어주면 됩니다. 



이렇게요.


또 뭔가 준수안하는 메소드나 그런게 있나봐요, 에러가 사라지지않네..

fix눌러주면



이런 메소드들이 생깁니다. 


이름.

직관적.


make / UIViewController네요. 근데 리턴타입이 ZeddDetailViewController네? 



응 리턴이야



update / UIViewController.

리턴은 안하는군요. 

아 근데 파라미터에..uiViewController너무...거슬려...항상 UIViewController만 보다가..uiView를 보니.....

아니 소문자로 시작 해야하는거 맞긴한데...


자 암튼 이건 



지금 모르겠으니까 안한다..



ㅈ ㅏ~~ 그럼 우리의 SwiftUI코드로 가봅시댜

그럼 뭔가 이동해야하니까 Navigation으로 감싸줄게요. 



NavigationButton을 넣어줘봅시다.



자..이렇게 destination에 아까 우리가 만든  UIViewControllerRepresentable를 준수하는 그 struct를 넘겨줍니다.




 ta da



아까 제가 background를 gray로 줬으니...

잘 뜨는 것 같죠!?!?


허허 SwiftUI에서 띄워줄려면 이런 작업이 필요하군요...

zzz근데 여러분 이게..맞는지 잘 모르겠어요..


아~~~~여러분



typealias없어두 된당!!!!! 

만약 쓸거면



저걸 저렇게 바꿔주면 된당. 

make, update ViewController메소드를 불러오기 위한 힌트..인가??? 


암튼 그렇다는거??

작동은 똑같이 하니까 알아서 하세욘


아, 그리고

위 그림 보면..make, update메소드에 UIViewControllerRepresentableContext~~라고 복잡하게 있잖아요? 그걸 생략하고



Context로 해도 되네요???

참고하세요!

훨씬 깔끔해져서 좋음 ㅎㅎ



하나 더 남았는데......지금 넘 힘드네요zzz

일단, 제가 작성한 코드가...동작은 되지만, 이게 맞다!!하는 자신이 없네요. 

항상 제 글을 보실때..항상..의심해주시고..틀린점이 있다면 바로바로 지적 부탁드립니다.


사실 저렇게 struct로 만든게 apple이 권장(?) 하는거잖아요? 



사실 extension도 됩니다. 

UIViewController를 만들고, 해당 UIViewController를 

extension해서 UIViewControllerRepresentable를 채택해도 됩니다. 

SwiftUI쪽에서 부를때는 ZeddDetailViewController()로 불러도zzzz동작은 같습니다.

다만 주의할 점은 반드시 UIViewController를 정의할때 final로 만들것.

final로 안하면 에러남ㅎ


아 근데 뭐 이게 애플이 의도한 동작인지는 잘 모르겠고..지금 SwiftUI의 view들이 struct잖아요? 

그러니까 저~~기 위에서한 struct로 하는게 좋을 듯 해용

위 extension코드가 맞는지도 모르겠고zzzzz 제가 깊게 안건들여서..에러가 안나는 것 처럼 보일 수 있잖아요? 

그냥 이렇다는거..




하나 더 있는데...이거...지금 할까 말까..

자 그럼 일단 해봅시다.


지금까지 ViewController를 이야기했다면 지금부터는 View를 이야기 해볼게요.

View도 똑같은 상황이 있을 수 있죠.


하지만 아마 이건..제 생각인데, UIKit에서 SwiftUI view를 addSubview를 할 수 있냐?

안되지않아? 왜냐면 SwiftUI의 view는 controller역할을 하기때문에????? (제생각)

아니 이게 확실하지가 않는데..아무튼 SwiftUI의 그 view 프로토콜을 채택한 view는 사실상 하나의 controller잖아요?

그래서 UIKit에 SwiftUI를 addSubview하려면..



UIHostingController로 viewController를 가져온다음..거기서 view를....................

강제언래핑은 일단 무시해주세요.

ZeddView 코드를 보면



그냥 이런코드에요.




zzzzzzz근데 이거 아닌것같아요.

이러지맙시다 우리

이거 아닌거같애요ㅕ...

아니 아닌건 없지만..

아니 딱히 잘못된거 없고 굉장히 있을법한 거긴한데



아까 그 navigationView로 감싸진거 띄우면



이러케 앞에 뭐가 ....


아무튼 이건 튜토리얼에도 없어요.

UIKit View를 SwiftUI에 가져오는건 있는데, SwiftUI를 UIKit으로 가져오는건 없어zzzzz

너무 당연해서 추가 안한건가...?


자 암튼..알아서 하시구요

UIKit View를 SwiftUI에 가져와봅시다.

이것도 UIHostingController, UIViewControllerRepresentable를 사용했던것 처럼 뭔가를 써야하는데, 그것이

UIViewRepresentable입니다. UIViewControllerRepresentable에서 Controller만 빠진거네요.


정의는 

Use the UIViewRepresentable protocol to bridge UIKit views into SwiftUI, not view controllers.


UIKit view를 SwiftUI로 연결해주는 프로토콜~~


그럼 하나 만들어볼까욘?!?




이렇게 하나 만들어주고..역시나 make, update친구들을 구현해줘야합니다. 



UIViewType에는 뭐 UIView든,..UILabel이든..뭐 그렇게하면 됩니다. 



 너무 코드가 복잡해서 좀 줄여봤어요. Context같은거.


자 그리고 SwiftUI코ㅓ드로 가서,


뭐 그냥 이렇게 해줄게요?

그럼


이렇게 view로 들어가긴 하는데....

왤케 크게 들어가지..?


크기조정은 모르겠다

지금 머리 터질것같애요zzz



음 제가 

각 예제들을 github에 올려놨습니다!


UIHostingController :  https://github.com/Zedd0202/UIHostingController_Example


UIViewControllerRepresentable : https://github.com/Zedd0202/UIViewControllerRepresentable_Example


UIViewRepresentable : https://github.com/Zedd0202/UIViewRepresentable_Example


한꺼번에 한 프로젝트 안에서 할려니까 좀 헷갈려서..그냥 3개로 나눴어요!


SwiftUI와 UIKit의 결합(?)은 반드시 일어날 일이구요..

공부를 꼭 해야겠죠?

모두모두..WWDC를 꼭..보도록 해요

저도 SwiftUI와 Combine관련 세션은 모두 보려구요!! XD



제 예상과는 다르게 글이 너무너무너무 길어졌는데요,

혹시 틀린점이나 그런게 있다면..지적은 정말 언제든지 환영입니다.





반응형