안녕하세요 코찐 입니다.
요즘 학습할 거리들이 넘쳐나고 있는데요.
SwiftUI, 새로 추가된 WWDC 21 세션들, 개인앱 작업, 모듈 관리 등 많은 열정적인 개발자 분들이 자료를 공유해주고 계십니다.
저는 자료가 넘쳐나는 시즌에는 열등감이 넘쳐났다가 다음 WWDC 직전때에 자만심이 넘치는 주기를 반복하는 것 같아요ㅋㅋ
열등감이 커지면 학습 열정을 자극하기 보다는 집중력이 흩어지고 오히려 학습을 방해하는 느낌을 받습니다.
다음에 이것 관련해서 글을 좀 정리해보려고 합니다.
무튼!!!! 분위기를 다시 전환해서 오늘의 문제를 정리해볼게요.
제가 해결한 것은 아니지만 앞으로 디버깅 할 때 참고하고자 기록합니다.
저희팀에서 만난 문제입니다.
아이패드에서 키보드를 floating으로 전환할 수 있는데요.
이상하게 카페앱에서 floating으로 전환하면 앱이 동작을 멈추는 것입니다.
더 이상한 건 샘플앱을 만들어서 동일하게 해보면 앱이 동작을 멈추지 않았습니다.
특히 inputAccessoryView가 있을 때 발생하고 있어서 일단은 이것을 의심했습니다.
아이패드일 때 inputAccessoryView를 빼면 된다는 접근인데요.
accessoryView 대신 addSubview를 해서 키보드 영역 만큼 들어주는 방안입니다.
이렇게 하면 앱 안에 퍼져있는 이슈를 모두 잡는 것이 쉽지 않게 됩니다...
원인 분석
그런데 이 루프가 발생하는 원인이 무엇일까?
Main Thread에서 무한 루프가 돌고 있다는 것은 추측할 수 있었지만 어떻게 디버깅 해야할지 몰랐습니다.
먼저는 Time Profiler로 앱의 콜스택을 실시간으로 확인할 수 있습니다.
정확하게는 어떤 역할인지 더 알아봐야겠지만 함수 호출회수가 기록되는 것을 볼 수 있었습니다.
하지만 이것이 어느 부분 떄문에 크래시가 발생하는지 알려주기는 쉽지 않았습니다.
ViewLayout 때문에 루프가 도는 횟수를 지정해서 디버깅 해볼 수 있는 장치가 있습니다. https://www.hackingwithswift.com/articles/59/debugging-auto-layout-feedback-loops
Option키를 누른채로 Run 버튼을 누르면 앱 실행시에 전달할 Argument를 세팅할 수 있는 공간이 있습니다.
-UIViewLayoutFeedbackLoopDebuggingThreshold 100
이렇게 지정하고 문제 화면에 접근하면 아래와 같이 크래시가 발생합니다.
아쉽게도 이것만으로 직접적인 원인을 파악할 수는 없었습니다.
그렇게 헤매고 있는 와중에 저희팀 시니어님께서 원인을 파악하셨는데요!
문제의 원인
스위즐링 되어 있는 코드가 무한루프를 발생시키고 있었습니다.
스위즐링!! 의심은 했었지만 정확한 발생 지정을 찾지 못했는데, 다시 돌아보면 가장 높은 우선순위로 생각했어야 했습니다.
왜냐하면 저희앱에서는 이슈가 발생하고, 샘플앱에서는 이슈가 발생하지 않았기 때문입니다.
그리고 앱 안에서 전반적으로 발생하고 있었기 때문에 핵심 메소드가 스위즐 되었다고 의심할 수 있습니다.
엉뚱하게도 키보드 관련 코드가 문제가 아니었습니다.
저희 앱에서는 cornerRadius를 디자인 의도대로 표현하기 위해서 https://github.com/lapfelix/UIView-SmoothCorners 를 사용하고 있는데요. 이곳에서 layoutSubviews를 스위즐링 하고 있었습니다.
제가 이 코드를 검색하지 못했던 것은 단순히 swizzle 이라는 단어로 검색했기 때문입니다.
스위즐을 수행하는 함수들 class_getInstanceMethod, method_exchangeImplementations, class_replaceMethod 등... 을 중점으로 검색했다면 찾을 수 있었을 것 입니다.
이곳으로 가서 breakpoint를 걸어보니 무한 루프가 있다는 것을 알 수 있었습니다.
정리
- 작업하는 앱에서만 발생하고 다른 앱에서는 발생하지 않는다
- 앱 안에 범용적으로 발생하고 있고 특정 클래스가 관여하지 않는다
=> swizzling 코드가 있다는 것을 강하게 의심해보자
=> swizzling 을 수행하고 있는 함수를 검색해보자
=> 이슈 전반을 제대로 해결 할 수 있는 방법을 찾아보자
엄청 복잡한 문제는 아니었지만 디버깅을 하는게 어려웠습니다.
디버깅 실력에 암묵지가 있다는 것을 또 한번 느꼈습니다.
생각을 정리하는 습관을 가지고 문제를 차근차근 접근하는 연습을 해야겠다는 생각이 들었습니다.
그리고 코드를 애매하게 추측하지 말고 정확히 해당 기능을 수행하는 코드로 검색하는 것이 좋다는 것을 알게되었습니다.
읽어주셔서 감사합니다!
'iOS' 카테고리의 다른 글
[WWDC21] Ultimate application performance survival guide (0) | 2021.07.08 |
---|---|
iPad Slide-over 키보드 높이 계산 이슈 해결 (0) | 2021.06.15 |
커스텀 UIInputView height에 SafeArea 반영하기 (0) | 2021.04.28 |
Swift 객체 외부에서 객체가 해제되는 것 감지하기 (0) | 2021.04.20 |
@testable import로 연결한 모듈에서 Undefined symbol이 발생하는 이슈 대응 (0) | 2021.04.17 |