
| Connect Daily Quiz View |
|---|
![]() |
오늘은 기존 작성한 프로젝트의 디테일 업 작업을 하고, 팀원이 만든 DailyQuizView와 내 프로젝트를 합치는 작업을 진행하였다.
이 과정에서 GitHub를 통한 협업, 그리고 SwiftUI와 UIKit을 함께 사용하는 방법에 대해 학습하였다.
함께 프로젝트를 진행하는 다른 멤버가 UIKit을 사용하여 만든 뷰로, 랜덤하게 문제를 출제하고 정답을 맞추면 다음 문제로 넘어갈 수 있고 오답일 경우 다시 문제를 풀어야 하는 방식으로 구현되어 있다.
내가 작성한 코드는 SwiftUI기반이고, 팀원이 작성한 코드는 UIKit기반이었기 때문에 서로를 연결하려면 특별한 코드가 필요했다.
이번 프로젝트의 경우 메인을 SwiftUI로 하고 UIKit을 서브로 하였기 때문에 멤버가 만든DailyQuizView를 내가 만든 코드에 접합할 필요가 있었다. SwiftUI에 UIKit을 넣는 것이기 때문에UIViewControllerRepresentable프로토콜을 준수하는 새로운 구조체의 선언이 필요했다.핵심코드
// SwiftUI에서 UIKit의 UIViewController를 사용하기 위해 UIViewControllerRepresentable 사용 struct DailyQuizViewControllerWrapper: UIViewControllerRepresentable { // UIViewController 업데이트 확인 func updateUIViewController(_ uiViewController: DailyQuizViewController, context: Context) { } // UIViewController 만들기 func makeUIViewController(context: Context) -> DailyQuizViewController { return DailyQuizViewController() } }
먼저 멤버가 만든 UIKit파일을 내 프로젝트 파일에 추가해 주었다.

추가한 DailyQuizView를 NavigationLink를 통해 이동하도록 만들기 위해 MainView에 해당 뷰를 할당한다.
NavigationLink(destination: DailyQuizViewController()) {
ZStack {
RoundedRectangle(cornerRadius: 10)
.frame(width: 350, height: 40)
.foregroundStyle(Color.parsta)
RoundedRectangle(cornerRadius: 10)
.frame(width: 347, height: 37)
.foregroundStyle(Color.white)
Text("Daily Quiz")
.font(.system(size: 20))
.fontWeight(.medium)
.foregroundStyle(Color.parsta)
.lineLimit(1)
}
}
그러나 단순히 NavigationLink에 destination값으로 퀴즈뷰의 값을 넣으면 에러가 발생한다.
Generic struct 'NavigationLink' requires that 'DailyQuizViewController' conform to 'View'라는 에러로 즉, UIKit으로 작성된 퀴즈뷰가 View타입이 아니기 때문에 NavigationLink에 destination값으로 사용할 수 없다는 에러이다.
위에서 발생한 에러를 해결하기 위해서는 SwiftUI에서 UIViewController를 사용할 수 있도록 해야한다.
이를 위해서는 UIViewControllerRepresentable프토토콜을 준수하는 구조체를 선언하고 해당 구조체 내에 UIViewController타입의 뷰를 선언해주면 된다.
UIViewControllerRepresentable이란 UIKit의 UIViewController를 SwiftUI에서 사용하기 위해 SwiftUI의 뷰로 변환하는 인터페이스이다.
import SwiftUI
import UIKit
// 필수구현 메서드
// makeUIViewController(context:) - UIKit의 UIViewController를 생성하고 초기화 시킨다.
// updateUIViewController(_:context:) - SwiftUI 뷰의 상태가 변경될 때 UIViewController를 업데이트 한다.
// SwiftUI에서 UIKit의 UIViewController를 사용하기 위해 UIViewControllerRepresentable 사용
struct DailyQuizViewControllerWrapper: UIViewControllerRepresentable {
func updateUIViewController(_ uiViewController: DailyQuizViewController, context: Context) {
// SwiftUI의 @State 혹은 @Binding 값이 변경될 때 변경사항을 UIViewController에 수동으로 반영
// SwiftUI와 UIKit의 상태를 동기화 하는 역할
}
// UIViewController 만들기
func makeUIViewController(context: Context) -> DailyQuizViewController {
return DailyQuizViewController()
}
}
위의 코드를 작성한 후 구현한 구조체인 DailyQuizViewControllerWrapper를 NavigationLink의 destination값으로 입력한다.
이렇게 하면 에러가 사라지고 정상적으로 구현이 되는 모습을 볼 수 있다.
NavigationLink(destination: DailyQuizViewControllerWrapper()) {
ZStack {
RoundedRectangle(cornerRadius: 10)
.frame(width: 350, height: 40)
.foregroundStyle(Color.parsta)
RoundedRectangle(cornerRadius: 10)
.frame(width: 347, height: 37)
.foregroundStyle(Color.white)
Text("Daily Quiz")
.font(.system(size: 20))
.fontWeight(.medium)
.foregroundStyle(Color.parsta)
.lineLimit(1)
}
}

프로젝트 멤버와
GitHub를 통해 프로젝트 파일을 merge하는 과정에서 push 오류가 발생했다. 자꾸만 인터넷 연결 상태를 확인하라는 메세지에 새로 commit을 하기로 하고 reset을 진행하였는데, 그 과정에서 무엇이 문제였는지 프로젝트 파일이 날아가버렸다...
백업된 파일도 없고, 맥북의 TimeMachine도 활성화가 안 되어있는 상태에서 인터넷에 복구 방법을 검색하며 복구를 시도하였는데, 모두 잘 되지 않았다. 파일 복구 앱을 사용하려고도 해보았지만 대부분 유료인데다가 스캔을 해보아도 프로젝트 파일을 찾을 수 없어서 포기하고 있던 상황에 터미널의 Log에 commit hash가 남아있는 것을 확인하고 이를 사용하여 무사히 복구를 할 수 있었다.
터미널 로그에서 reset을 진행하기 전 커밋해쉬를 찾아 복사해 주었다. 그 뒤 checkout을 통해 파일 복구를 진행하였다.
// git checkout (커밋해쉬) (파일명)
$ git checkout 9141e28dc5066f5f56eee88f6a0e7dd925000183 parSta_App_SwiftData_DetailView
checkout을 통해 복구된 파일을 repository에 저장하기 위해 push를 진행한다.
$ git add parSta_App_SwiftData_DetailView
$ git commit -m "복구파일 추가"
$ git push
복구된 파일의 커밋은 성공했으나 여전히 push에서 에러가 발생했다.
어쩌면 원격저장소와 로컬저장소의 값이 달라서 발생하는 문제일 수도 있기 때문에 추후 pull을 통해 업데이트 후 다시 Push를 해 볼 예정이다.

오늘은 지금까지 진행한 프로젝트를 다른 팀원과 GitHub를 통해 merge하고,
그 과정에서 SwiftUI와 UIKit의 호환을 위한 코드에 대해 학습하였다.
git을 오랜만에 사용하는 탓에 파일이 날아가는 등 문제가 있었지만... 다행히 파일을 복구하고 프로젝트를 완수할 수 있었다.
이번 일을 계기로 백업의 중요성과 reset을 할 때는 더욱 신중해야 한다는 것을 다시금 깨닫게 되었다.