Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- 리펙토링
- map
- 클린 코드
- combine
- Clean Code
- UITextView
- ios
- 리펙터링
- HIG
- MVVM
- RxCocoa
- swift documentation
- tableView
- Xcode
- 애니메이션
- collectionview
- UICollectionView
- rxswift
- Protocol
- uitableview
- swiftUI
- 리팩토링
- SWIFT
- Refactoring
- Human interface guide
- ribs
- Observable
- clean architecture
- 스위프트
- uiscrollview
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] 스위즐링 (swizzling) 사용 방법 (class_getInstanceMethod, method_exchangeImplementations) 본문
iOS 응용 (swift)
[iOS - swift] 스위즐링 (swizzling) 사용 방법 (class_getInstanceMethod, method_exchangeImplementations)
jake-kim 2023. 5. 26. 23:14사전지식) Objective-C 런타임 라이브러리
- class_getInstanceMethod, method_exchangeImplementations 관련 내용 이해를 위해서 이전 포스팅 글 먼저 참고
class_getInstanceMethod, method_exchangeImplementations 개념
- class_getInstanceMethod
- 지정한 클래스의 특정 메소드를 검색하여 이 메소드를 원하는 시점에 실행시킬 수 있는 방법
- 원래 메소드를 실행 시키려면 인스턴스를 생성하고나서 실행시켜야하지만, 타입으로 접근하여 일괄적으로 모든 인스턴스에 적용시키고 싶을 때 사용
- method_exchangeImplementations
- 위에서 얻은 Method 타입을 파라미터로 받아서, 첫 번째 인자에 삽입한 메소드가 실행될 때 두 번째 인자의 메소드가 실행되게끔 하는 방법
- 주의사항 - 두 메소드를 교체하는게 아니라, 두 메소드 모두 실행되는 방법임
Swizzling 방법
* swizzle: 뒤섞다
- 스위즐링
- Objective-C에 의해 만들어진 swift언어도 역시 Objective-C의 성격을 가지고 있으므로 메소드의 실행은 런타임에 결정
- 메소드의 실행은 런타임때 결정되므로, 런타임에서 메소드가 실행되기전에 원하는 내용으로 뒤섞기가 가능
- = 런타임 시점에 내가 원하는 코드가 실행되게끔 가능
- 기존 SDk의 메소드를 수정할 수 없을 때 유용
- Swizzling 방법
- #selector로 Selector를 참조한 후, class_getInstanceMethod로 실행시킬 수 있는 Method를 참조
- Method를 method_exchangeImplementations(_:_:)에 넣어주면 메소드 변환 성공
import UIKit
fileprivate var swizzleEnabled = false
extension UIViewController {
static let methodSwizzled: Void = {
guard !swizzleEnabled else { return }
swizzleEnabled = true
// #selector: swift의 메소드나 함수를 참조하는 방법 (Selector 타입)
let originalSelector = #selector(viewWillAppear(_:))
// class_getInstanceMethod: Objecitve-C 런타임 라이브러리에서 제공하며, 메소드를 검색하는데 사용
let originalMethod = class_getInstanceMethod(UIViewController.self, originalSelector)
let swizzledSelector = #selector(swizzledViewWillAppear(_:))
let swizzledMethod = class_getInstanceMethod(UIViewController.self, swizzledSelector)
guard let originalMethod, let swizzledMethod else { return }
method_exchangeImplementations(originalMethod, swizzledMethod)
}()
@objc private func swizzledViewWillAppear(_ animated: Bool) {
// Swizzling된 메서드에서 추가적인 동작 수행
print("Swizzled viewWillAppear called for \(self)")
}
}
- App Delegate에서 아래처럼 methodSwizzled를 한 번만 호출해주면 앞으로 모든 UIViewController 인스턴스들이 viewWillAppear가 동작할 때 위에서 정의한 swizzledViewWillAppear(_:)가 동작
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// enable swizzling
UIViewController.methodSwizzled
return true
}
- 결과
- 가로챈 swizzle 메소드가 먼저 호출되고, 가로챔 당한 메소드가 이어서 실행
- 주의할점 - 스위즐링은 한 메소드만 실행되는게 아니라 두 메소드 모두 실행되게 하는 방법
import UIKit
class BaseViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("viewWillAppear in BaseViewController")
}
}
class ViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("called?")
}
}
/*
Swizzled viewWillAppear called for <ExSwizzling.ViewController: 0x152505d50>
viewWillAppear in BaseViewController
called?
*/
* 전체 코드: https://github.com/JK0369/ExSwizzle
* 참고
https://developer.apple.com/documentation/objectivec/1418530-class_getinstancemethod
https://developer.apple.com/documentation/swift/using-objective-c-runtime-features-in-swift
'iOS 응용 (swift)' 카테고리의 다른 글
Comments