Method Swizzling(메소드 재구성)이 뭘까?
기존 메소드의 기능을 런타임 때 원하는 메소드로 바꾸는 것
파베에서도 Method Swizzling으로
앱이 실행될 때 애플의 메소드를 살짝 탈취해서 APNs의 토큰과 파베의 토큰으로 매칭시켜서 구현하는 바이브로 처리한다고 한다.
또는 컨퍼런스에 들은 바로는 회사에서 사용되는 뷰컨과 스보가 너무 많아 지금 보고 있는 화면의 뷰컨의 이름을 알고 싶을 때
이 Method Swizzling을 통해서 뷰딛로드와 커스텀 메소드의 기능을 바꿔서 뷰컨의 이름을 찍는 방식으로 해결해줬다고 들었다.
구글링해보니까 메모리 누수를 체크하려고 뷰컨이 deinit 될 때 로그가 찍히도록 Method Swizzling을 사용해서 구현한 분도 계시네..
만약 이 기법을 안사용하면 모든 뷰컨의 deinit 부분에 로그를 찍어줘야 하니까..(근데 deinit에서 애초에 Method Swizzling이 적용이 안돼서 viewDidLoad에서 delocator를 통해 구현해줬다고 함..)
보통 이렇게 하려면 BaseViewController 하나 만들어가지고 했던 걸로 기억함..
BaseVC에서 viewWillAppear나 viewDidLoad에서 원하는 기능 구현해서 뷰컨에 BaseVC을 상속시키고
오버라이딩해주는 방식으로... 그 대신에 Method Swizzling이 있으니까 이 방식을 사용하면 될 것 같음
내가 잘 사용하기를...
그러면 어떻게 사용하냐면...
나는 여러 ViewController들의 viewWillAppear가 호출될 때 내가 만든 커스텀 메소드를 호출해주고 싶다고 한다면
아래처럼 코드를 작성해줄 수 있다.
extension UIViewController {
static func swizzleMethod() {
let origin = #selector(viewWillAppear) // 원래 메소드
let change = #selector(changeViewWillAppear) // 바꿔주려는 메소드
// UIViewController의 origin이라는 메소드를 가지고 오겠다.
// 너 UIViewController의 인스턴스를 만들었을 때 거기에 viewWillAppear/changeViewWillAppear가 있는지 확인하겠다.
guard let originMethod = class_getInstanceMethod(UIViewController.self, origin),
let changeMethod = class_getInstanceMethod(UIViewController.self, change) else {
print("함수를 찾을 수 없거나 오류 발생")
return
}
// 메소드를 바꿔주기
method_exchangeImplementations(originMethod, changeMethod)
}
// 바꿔주려는 메소드의 실제 작동되는 부분
@objc func changeViewWillAppear() {
print("Change ViewWillAppear SUCCEED🧡")
}
}
selector를 통해서 메소드의 참조를 가져와
class_getInstanceMethod를 이용해서 진짜 Method 타입을 가지고 온다.
method_exchangeImplementations를 통해 두 메소드를 바꿔준다.
그리고 AppDelegate에서 호출해줘야 한다.
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UIViewController.swizzleMethod()
return true
}
}
그러면 이제 어떤 뷰컨에 들어가도 커스텀 메소드가 불린다.
여기서 swizzleMethod가 타입메소드인 걸 알 수 있는데 수업에서 이걸 듣고 아리까리했다. 그래서 정리를 해본다.
인스턴스 메소드
인스턴스 메소드부터... 먼저 보자면.. 와 인스턴스 메소드라고 하니까 낯선데
평상시에 사용하던 게 인스턴스 메소드다.
final class HomeView: BaseView {
func setupMapDelegate(_ touchDelegate: NMFMapViewTouchDelegate,
_ cameraDelegate: NMFMapViewCameraDelegate) {
mapView.touchDelegate = touchDelegate
mapView.addCameraDelegate(delegate: cameraDelegate)
}
}
private let homeView = HomeView()
override func setupDelegate() {
homeView.setupMapDelegate(self, self)
}
HomeView라는 클래스를 만들어서 그 안에 setupMapDelegate라는 메소드를 만들었음
글구 HomeView 클래스의 인스턴스를 생성해서 인스턴스에서 setupMapDelegate에 접근할 수 있다.
만약 그냥 이렇게 클래스에서 바로 접근하려면 에러가 발생하는데 읽어보면
인스턴스 멤버인 setupMapDelegate는 HomeView 타입에서 사용할 수 없다. 대신 이 타입의 값을 사용하겠니? 라고 나옴
결론은 인스턴스 메소드는 평상시에 쓰던 그 메소드다.
그러면 타입 메소드는 뭘까?
swizzleMethod 앞에 static 키워드가 붙어 있으면 타입 메소드로 쓴다는 걸 알 수 있어서 구분하기는 쉽다.
아까 인스턴스 메소드랑 다르게 타입 메소드는 인스턴스를 생성하지 않아도 타입에 접근해서 쓸 수 있다.
그래서 위에서 swizzleMethod는 타입 메소드기 때문에 인스턴스 메소드처럼 접근이 불가능하다!
static 키워드 대신에 class를 붙여도 타입 메소드로 쓸 수 있는데 이 둘의 차이점은
class라는 키워드는 오버라이딩이 가능하고, static은 불가능하다는 거다.
단순 오버라이딩이 차이라면 그냥 final class == static과 같다고 보면 된다.
static을 언제 그럼 사용하냐? 그것도 궁금한데, 이제 또 다른 블로그에서 찾아가지구 여기다가 또 정리해보면,,,,
static을 사용하는 경우는 메소드나 프로퍼티가 인스턴스보다 type 자체와 연관될 때 사용한다.
static property의 경우
- 자주 변하지 않고, 전역 변수처럼 공통으로 관리하는 공용 자원의 경우 ex). 색상 / 폰트
- 자주 재사용되고 생성 비용이 많이 드는 object를 미리 만들어 놓고 계속 쓰면 효율을 높일 수 있을 때 ex). dateFormatter 등
(당장 첫 번째 예시는 이해가 가는데, 두 번째 예시는 감이 잘 오지 않는군!!!)
static method의 경우
- 오. 어려운데? 간단한 factory pattern의 경우 (오 팩토리 패턴이 몬데요? 모르겠는 걸~~?? 차차 공부해보도록 하쟈...^^)
별개로 싱글톤은 클래스와 사용이 가능하다.
싱글톤 자체가 하나의 인스턴스를 생성해서 공용으로 사용하는 디자인 패턴이기 때문에
구조체와 사용해버리면 애초에 사용하는 의미가 없다.
그리고 static 키워드가 싱글톤이랑 같이 쓰이는 이유는
싱글톤이 공용으로 사용하자는 디쟌패턴인데
타입 프로퍼티 자체가
- 처음 호출돼서 메모리에 한 번 올라가면 그 뒤로 생성되지 않고 언제 어디서든 이 타입 프로퍼티에 접근할 수 있기 때문이다. (전역변수)
- 타입 프로퍼티라서 타입에 접근해서 프로퍼티 값을 가져와야 하고
- 인스턴스 생성과 무관하기에 초기값을 반드시 가져야 한다.
'⭐️ 개발 > iOS & Swift' 카테고리의 다른 글
[iOS] 20221012 TIL (0) | 2022.10.13 |
---|---|
[iOS] Remote Notification (2) | 2022.10.11 |
[iOS] 다국어 지원 i18n, l10n (1) | 2022.09.06 |
[iOS] 안간단한 MVVM 안간단하게 톺아보기 (3) | 2022.08.31 |
[iOS] URLSession(1) (0) | 2022.08.30 |