Do.

Swift - 지금 보는 뷰 이름 알기 본문

iOS

Swift - 지금 보는 뷰 이름 알기

Hey_Hen 2022. 9. 4. 02:04

Introduce

회사 업무로 코딩하다 보면 정말 많이 화가날 때가 있는데, 뷰가 너무너무너무 많아서 도대체 내가 지금 보고 있는 뷰의 이름이 뭔지 모를때가 있다. 비슷하게 생긴 뷰도 워낙 많고 하니, 단순히 피그마 디자인만 보고 뷰의 이름이 추측이 안될때가 있다. 기록이나 정의해 둔 문서가 따로 있다면 좋겠지만, 아마 대부분의 회사는 없을 것 같다.

그래서 보통 쓰는 방법이, 뷰 계층 디버거를 이용해서 이름을 알아 내는 방법인데, 이게 또 프로젝트가 너무 커서 그런가, 켜지는 데 시간도 오래 걸리고, 심지어 어떨 때는 계층 디버거가 켜지지도 않는다. 이럴때 진짜 매우 섬뜩하게 화가난다. 코딩할 시간도 부족한데, 뷰 이름이나 찾고 있어야 한다는게...

그래서 어떤 방법을 이용하면 좀더 쉽고 빠르게 찾을 수 있을까 하다가, 배운적은 있지만 한번도 실용적으로 사용해본 적은 없는 Method Swizzling이 생각났다. 개념을 모르시는 분들께 간단히 설명하자면, 런타임 중에 실행되는 메서드를 바꿔치기 하는 기능이다.

예를들어 모든 UIViewController는 로드될 때 필연적으로 viewDidLoad() 를 호출하게 되는데, 이걸 내가 만든 별도의 메서드가 호출되도록 할 수 있는 것이다.

놀라워라!!!

딱기다려

그래서 어떻게 하느냐?

extension UIViewController {

  @objc func whatTheThisView() {
    print("What The This View: \(self)")
  }

}

우선 @objc 딱지가 붙은 메서드를 하나 만들 건데, UIViewController에서 이용할 예정이므로 extension으로 추가한다.

이 메서드는 지금 viewDidLoad와 교체할 메서드 이므로, 내용은 취향껏 채우자

그 다음 메서드를 스위즐링을 수행할 메서드를 만들 건데, 이 기능을 AppDelegate 시점에 DEBUG 일 때만 수행되도록 하고 싶다. 그래서 UIViewController의 타입 메서드로 만들꺼다.

static func startWhatTheThisView(mirror: Bool = false) {
    let target = #selector(viewDidLoad)
    let source = mirror ? #selector(whatTheThisViewMirrir) : #selector(whatTheThisView)

    guard
      let targetMethod = class_getInstanceMethod(UIViewController.self, target),
      let sourceMethod = class_getInstanceMethod(UIViewController.self, source)
    else { fatalError("What The This View Start Failure, Can't Find Method") }

    method_exchangeImplementations(targetMethod, sourceMethod)
}

addTarget 할때처럼 selector를 이용해 메서드를 가리켜 주면 된다.

그런 다음 class_getInstanceMetohd 를 통해 뭔갈 가져오면 되는데 신기하게도 Method 라는 타입이다. 신기해서 문서를 보니 OpaquePointer 라는 구조체의 별칭이었다. OpaquePointer는 C Pointer의 래핑이라고 문서에 써져있더라.

아무튼 그렇단 말은 Method의 참조 포인터를 가져온 다는 뜻! 즉 런타임 중에 viewDidLoad 가 올라가 있는 주소가 있고, 내가 만든 메서드 주소가 있는데, viewDidLoad로 향하게 안하고 내가 만든 주소로 향하게 해서 메서드 스위즐링 이란 것을 수행하는 것으로 추측된다.

그런 다음 수행 하는 코드는

method_exchangeImplementations(targetMethod, sourceMethod)

이름만 봐도 메서드 바꿔줄 것 같다. 

 

이제 AppDelegate에서 방금 만든 타입 메서드를 호출한다.

#if DEBUG
    UIViewController.startWhatTheThisView(mirror: true)
#endif

그러면 이제 앱을 실행시켜서 화면을 돌아다니면 내가 만든 메서드가 호출된다.

 

나 같은 경우는 ViewController가 가지고 있는 (가증스러운) 멤버 까지 모두 호출 시키도록 했다. 가끔 화면에 매치된 뷰 들이랑, 뷰의 이름이 뭔지 모를 경우가 많기 때문이다,

니네 이제 다 뒤졌다?

...

물론 회사에 오래 근무하신 분들은 이미 코드들을 속속 알고 계셔서 금방 찾으시겠지만, 회사를 옮길 때 마다 이 뷰가 무슨 뷰인가 찾는 시간이 너무 아깝다고 생각했다. 그렇다고 뭘 특별히 하기에는 좀 그렇고, 간단한 코드 한 페이지 작성해서 실행 시킬 수 있으니 훨씬 작업시간이 빨라지는 것 같다.

(로그 창이 지옥으로 변하는 건 어쩔 수 없다)

 

Comments