Coordinator
낯선 언어를 매일 학습하며 몰입과 성장을 기록하는 일지
· 2 min read
구현 기능 사항 #
- QR 코드 View 파일 생성
문제 상황 #
- View에서 카메라를 사용하기 위해서는
UIViewcontrollerRepresentable의 필요 발생 - UIKit의 Context를 매개변수로 받아 이용하는데 Context의 학습
- SwiftUI에서 카메라 기능을 넣기 위해 살펴보니 UIKit 델리게이트 패턴에 대한 내용 발견
- struct에서 class인 deligator를 쓰기 위해 Coordinator 패턴을 적용할 필요가 발생
- Gemini, Claude를 통해 일단 템플릿 코드들을 보면서 대화식 학습 진행
개념 학습 #
UIViewControllerRepresentable #
- 일종의 어댑터 패턴
- SwiftUI와 UIKit(Camera) 사이의 어댑터 역할
- 해당 프로토콜을 통해 Class를 Struct처럼 사용 가능
참고 #
- SwiftUI는 무엇을 그릴지 선언하는 방식
- 카메라는 어떻게 하드웨어를 단계벌로 제어할지의 명령형 방식 UIViewControllerRepresentable이 두 패러다임의 불일치를 해결해주는 가교 역할
Context #
Context는 SwiftUI 시스템이 UIKit(카메라)에게 전달하는 전체 정보
- Context안에는 Coordinator와 Environment 들어있음
- Context안의 Coordinator를 카메라의 Delegate로 임명
- Context가 없다면 Coordinator에 접근할 방법이 없음
- Environment는 시스템정보(다크 모드, 폰트 사이즈)와 같이 UIKit뷰가 SwiftUI 환경 설정을 읽어야 할 때 해당 정보를 사용
NSObject #
- Swift는
struct기반, AVFoundation은class기반 - AVFoundation의 뿌리는 Objective-C(NSObject)
- struct는 가볍지만 생성 후 사라지기를 반복
- 카메라는 QR코드 촬영 후 해당 신호를 누구에게 전달해야 될지를 모르는 상황
- SwiftUI 뷰는 계속 주소값이 바뀌거나 사라지므로 신호를 받을 수 없음
- 따라서 SwiftUI안에 Coordinator(통역사)가 필요
- Coordinator 클래스를 생성하며 이 클래스는 NSObject를 상속받아 안정적으로 카메라 신호를 수신
AVCaptureMetadataOutputObjectsDelegat #
- AVCapture: 카메라와 상호작용
- MetadataOutput: 영상 안에 숨겨진 정보 (QR 바코드) 결과
- 카메라가 영상을 찍으면서 QR을 발견할 때마다 Delegate에게 알림
weak #
- 약한 참조를 만드는데 사용
- Swift는 ARC(Automatic Reference Counting)로 메모리 관리
- 객체 참조할 때마다 참조 카운트 증가, 카운트가 0이 되면 메모리에서 해제
- 강한 순환 참조를 방지하기 위해 사용
- weak 참조는 항상 Optional이어야 함
- 참조하던 객체가 해제되면 자동으로 nil 할당
- delegate패턴이나 클로저에서 주로 사용됨
- Java의 GC와 달리 개발자가 직접 명시적으로 관리해야 하는 부분이 낯섦
개발 과정 #
문제 상황 #
- QR코드 스캔 시 3 게임인 경우 2 게임은 [0,0,0,0,0,0]으로 출력되는 문제 발견
원인 #
- 유효한 게임 데이터 뒤에 000으로 이루어진 더미 데이터나 체크섬이 붙어있는 경우 존재
- 단순히 숫자만 추출하여 12자리씩 끊는 로직으로는 더미 데이터까지 모두 숫자 공으로 만드는 문제
- 구분자가 q, n 그리고 m이 혼용되어 사용됨


해결 과정 #
- 유효성 검사 도입
- 숫자가 정확히 6개인지 확인
- 모든 숫자가 범위 내에 있는지 확인
- 중복된 숫자가 없는 지 확인
- 구분자 삭제 후 게임 데이터에 맞는 숫자들만 사용
- 0으로만 이루어진 숫자 제거
- 5게임 이후들의 숫자는 모두 무시
- 한 게임당 12자리의 숫자(2자리씩 6개)만 사용
부가적 문제들 #
- 테스트 시 와이파이 연결은 디버깅이 유실되는 문제 발생
- QR코드를 촬영할 때는 후면 카메라가 필수이므로 시뮬레이터 사용 불가
- 항상 유선 연결로 전환하여 사용해야 될 필요 느낌
배운 점과 인사이트 #
- SwiftUI의 Context가 UIKit의 Delegate 패턴을 어떻게 연결해주는지 구조적으로 이해
- 클라이언트는 언제나 더미가 섞인 데이터를 받을 수 있으므로 파싱 로직은 최대한 방어적으로 구현해야됨
- 테스트는 항상 유선 연결을 통해 로그를 관찰