iOS/Swift

Swift - Method Swizzling

ios-hans 2023. 12. 1. 12:51

Method Swizzling

이번에는 Method Swizzling이라는 개념에 대해서 알아보자. Swizzle이라는 단어를 번역하면 '뒤섞다'라는 뜻입니다. 말 그대로 'Method' 특정 함수를 특정 시점에 'Swizzle' 뒤섞는다는 개념인거죠.

 

그렇다면 해당 메서드를 언제 뒤섞는 작업들이 필요할까요? 예를 들어 Firebase를 사용할 때 해당 ViewController에서 ViewWillAppear 같은 메서드가 몇 번 실행되는지와 같은 분석 기능을 추가할 때 사용하게 됩니다. 

Firebase Console Document를 살펴보면 Method Swizzling에 대한 설명이 나오는 것을 볼 수 있습니다. 

 

Method Swizzling은 Objective-C의 런타임 기능 중 하나이므로 어떤 식으로 구현할 수 있는지 한번 살펴보겠습니다.

프로젝트 예시

ViewController.swift

import UIKit

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        print(#function)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        print(#function)
    }
}

/*
 - Method Swizzling
 - '런타임 시점'에 특정 함수를 교체해서 특정 기능을 실행하게됨.
 */
extension UIViewController {
    class func methodSwizzling() {
        
        let origin = #selector(viewWillAppear)
        let change = #selector(changeViewWillApper)
        
        guard let originMethod = class_getInstanceMethod(UIViewController.self, origin),
              let changeMethod = class_getInstanceMethod(UIViewController.self, change)
        else {
            print("함수를 찾을 수 없음.")
            return
        }
        
        method_exchangeImplementations(originMethod, changeMethod)
    }
    
    @objc func changeViewWillApper() {
        // 앱 분석 특정 기능..
        print(#function)
    }
}

// viewDidLoad()
// changeViewWillApper()
// viewWillAppear(_:)

#selector를 이용해서 Swizzle할 메서드를 상수에 담아두고 인스턴스 메서드를 반환해줄 '메서드' (class_getInstanceMethod)를 이용해 guard let 바인딩해주면 해당 swizzle할 메서드가 각각의 상수에 담기게 되고 마지막으로

method_exchangeImplementations 메서드를 통해 기존 메서드와 바꿔줄 메서드를 파라미터로 전달하면 런타임 시점에 Method Swizzling이 실행됩니다.

AppDelegate.swift

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        UIViewController.methodSwizzling()
        return true
    }
}

이후 App이 실행되는 시점에 AppDelegate에서 구현해둔 'methodSwizzling()' 메서드를 호출하면 모든 ViewController의 인스턴스가 생성되고 파라미터로 전달했던 기존의 메서드가 실행될때 마다 바꿔줄 메서드가 실행되는 것을 볼 수 있습니다.

장점

- 이렇게 Method Swizzling을 사용하게 되면 모든 viewWillAppear 메서드에서 분석 기능이 구현된 함수를 호출하지 않아도 된다는 장점이 생깁니다.

단점

- 그러나 잘 생각해보면 Method Swizzling 기법은 런타임 시점에 호출되게 하고 싶은 함수를 찾아 실행시킨다고 했는데 이렇게 되면 런타임 시점에 크래시가 날 가능성도 있기 때문에 유의하여 사용해야할 것입니다. 

- 또한 iOS 버전이 올라가 Swizzling한 메서드가 변경되면 문제가 발생할 수도 있습니다.

 

결론적으로 Method Swizzling은 장점이 명확한 기능임은 확실하나 남발할 경우 많은 문제가 발생할 수 있기 때문에 신중하게 사용해야할 것 같습니다.