Có rất nhiều thứ mà chúng ta có thể làm với objc runtime, tuy nhiên trong bài này mình chỉ đề cập tới một số trường hợp thông dụng hay sử dụng. Các vấn đề khác các bạn có thể tìm hiểu thêm và sau đó comment ở bên dưới nhé.
Series này được chia thành nhiều phần.
- Phần 1: Khái niệm, ưu nhược điểm.
- Phẩn 2: Chúng ta có thể làm gì với objc runtime.
- Phần 3: Swift & Objc Runtime
- Phần 4: Inside Objc Class
- Phần 5: Message dispatch
Kiểm tra một object có thuộc class nào đó
Khi ta muốn biết 1 object có phải thuộc class nào đó không, ta có thể dùng hàm isKindOfClass
. Method này sẽ thực hiện lấy thông tin về class của object đó và so sánh với class chúng ta muốn kiểm tra. Việc đó được implement như sau trong Objc runtime:
Associate objects
Đây là một tính năng của objc runtime cho phép chúng ta liên kết một object khác vào object chúng ta đang xét. Để sử dụng tính năng này ta phải import header .
Tính năng này có 3 hàm, giải thích về 3 hàm này có lẽ để tiếng anh nghĩa sẽ chuẩn hơn:
objc_setAssociatedObject | Sets an associated value for a given object using a given key and association policy. |
objc_getAssociatedObject | Returns the value associated with a given object for a given key. |
objc_removeAssociatedObjects | Removes all associations for a given object. |
Tại sao mình phải dùng tính năng này.
Ví dụ mình muốn tạo thêm property là screenName
cho class UIViewController
để lưu trữ tên màn hình. Giả sử mình có mã nguồn của nó, thì điều đó rất đơn giản, chỉ việc mở nó ra và thêm vào thôi.
Nhưng không, mình không có mã nguồn của nó, mình phải làm sao.
Khi đó mình sẽ tạo category
cho UIViewController
và dùng tính năng này để liên kết property đó vào object của class đó.
AssociationPolicy
Khi thực hiện gọi objc_setAssociatedObject
để liên kết giá trị vào object, có một tham số gọi là
. Nó dùng để xác định thuộc tính của giá trị bạn liên kết vào. policy
Giống như các thuộc tính của property, khi dùng Associate Objects
bạn cũng phải xác định các thuộc tính giống như vậy.
Policy | Property tương ứng |
OBJC_ASSOCIATION_ASSIGN | @property (assign) |
OBJC_ASSOCIATION_COPY | @property (copy) |
OBJC_ASSOCIATION_COPY_NONATOMIC | @property (copy, nonatomic) |
OBJC_ASSOCIATION_RETAIN | @property (strong) hoặc @property (retain) |
OBJC_ASSOCIATION_RETAIN_NONATOMIC | @property (nonatomic, strong) hoặc @property (nonatomic, retain) |
Bật mí nhỏ một xíu mà khi dùng tính năng này, thì cờ has_assoc
trong isa sẽ được bật nhé ?
Method Swizzling
Như ở phần trước mình có trình bày, objc có thể bị hook vào đầu hoặc cuối hàm để thay đổi behavior của class đó. Thì đó chính là tính năng Method Swizzling ta sẽ tìm hiểu ngay sau đây.
Đây là một tính năng khá hay ho mà Objc runtime đem lại cho chúng ta, nó cho phép chúng hoán đổi phần implement của hai method.
Bài toán giả thuyết mình đặt ra là mình đang xây dựng một lib DI( Dependency Injection) mà mình cần inject dependency của nó sau khi nó được khởi tạo bằng storyboard. Mục tiêu của mình chèn code vào cuối hàm -[UIStoryboard instantiateViewControllerWithIdentifier:]
.
- Đầu tiên mình cần lấy ra 2 method mà mình cần hoán đổi. Ở đây là
instantiateViewControllerWithIdentifier
vàswizz_instantiateViewControllerWithIdentifier
- Dùng hàm
method_exchangeImplementations
để hoán đổi phần implement của 2 phương thức. - Sau khi exchange xong thì nếu gọi method
-[UIStoryboard instantiateViewControllerWithIdentifier:]
thì chương trình thực chất sẽ gọi phương thức-[UIStoryboard swizz_instantiateViewControllerWithIdentifier:]
và ngược lại ? - Chèn code vào method
swizz_instantiateViewControllerWithIdentifier
thôi ??
Cảm ơn các bạn đã đọc bài, có thắc hay mắc hay ý gì thì comment giúp mình xuống bên dưới nhé. ?