UIPageViewController 크래시 분석
UIPageViewController를 사용하는 앱에서 높은 비율로 크래시가 발생했습니다.
- The number of view controllers provided (0) doesn't match the number required (2) for the requested transition
- The number of view controllers provided (0) doesn't match the number required (1) for the requested transition
UIPageViewController에 제공하는 UIViewController의 개수를 제대로 컨트롤하고 있었기 때문에 원인을 파악하기 어려웠습니다.
UIPageViewController를 사용하는 기능 2개 중 1개에서만 발생하는 것을 확인했고,
하나는 자동으로 페이지를 넘기고, 크래시가 발생하는 다른 하나는 사용자가 페이지를 직접 넘긴다는 차이점이 있습니다.
빠르게 넘기고, 회전하면서 넘기고... 이런저런 케이스를 확인해 본 결과,
마지막 페이지에서 세로축을 포함하여 드래그를 하면 크래시가 발생한다는 것을 알 수 있었습니다.
예를 들어, 마지막 페이지에서 "오른쪽 위에서 왼쪽 아래" 방향으로 드래그를 하면, UIPageViewControllerDataSource의 viewControllerAfter 메서드가 무수히 많이 호출되면서 프레임워크 크래시가 발생하고 있었습니다.
그리고 충격적인건.. 이 크래시는 실기기에서만 발생합니다. 시뮬레이터에서도 메서드 이상 호출은 발생하지만 실기기에서만 크래시가 발생합니다. 그래서 찾기가 너무 힘들었네요.
영상 및 직접 확인하고 싶으신 분은 깃허브에 샘플 프로젝트를 올려두었으니 참고해 주시면 감사하겠습니다.
(https://github.com/jeongju9216/SamplePageViewController)
포럼에도 문의를 올렸었는데.. 거의 한 달 간 답변이 하나도 없다가 최근에 답변 하나가 생겼네요 ㅋㅋ (https://developer.apple.com/forums/thread/761662)
UIPageViewController 크래시 해결
해당 크래시의 원인은 특정 페이지의 제스처시 발생하는 잘못된 프레임워크 메서드 호출입니다.
잘못된 프레임워크 메서드 호출은 저희가 해결할 수 없습니다. 애플이 해결해 줘야죠 🥲
따라서 이 문제는 제스처에 집중해야 합니다.
특정 페이지에서 드래그 제스처 막아 해결할 수 있습니다.
UIPageViewController의 view에 PanGesture를 붙이고, UIPageViewController를 사용하는 ViewController에서 PanGesture의 Delegate를 구현합니다. 단, UIPageViewController에서 직접 Delegate를 구현하면 자체적인 Gesture와 겹쳐서 원하는 대로 처리가 안 되니 주의해야 합니다.
특정 페이지, 특정 조건일 땐 직접 추가한 PanGesture에서 제스처를 처리하고, 아니라면 UIPageViewController의 제스처를 수행해야 합니다. 이를 위해 UIGestureRecognizerDelegate의 gestureRecognizerShouldBegin(_:)를 활용할 수 있습니다.
각자 프로젝트에 맞게 마지막 페이지를 구하고, panGesture의 x축 이동을 구한 뒤 오른쪽에서 왼쪽 제스처를 막으면 크래시를 해결할 수 있습니다. (관련 커밋)
해결하면서 느낀 점
정말 고생 많이 한 크래시 해결이었습니다.
시뮬레이터에서는 발생하지 않고, 실기기에서만 크래시가 발생해서 두 배는 더 어려웠어요.
시나리오 상으로도 테스트 코드로 찾기가 힘들었습니다. 마지막 페이지에서 특정 제스처를 반복하는 것을 쉽게 예상할 수 없었어요.
그래도 재현 시나리오를 발견한 뒤로 해결은 어렵지 않았네요 ㅎㅎ
너무 좋은 경험이었던 거 같습니다.
감사합니다.
아직은 초보 개발자입니다.
더 효율적인 코드 훈수 환영합니다!
공감과 댓글 부탁드립니다.