12/08/2018, 15:26

Method swizzling

Method swizzling là quá trình hoán đổi implement của những selector có sẵn. Giả sử bạn có lớp A có 2 function là hello và goodbye. Bạn muốn hoán đổi như sau: Gọi vào function hello thì funtion goodbye được thực hiện và ngược lại. Đó là mục đích của medthod swizzling. Ở đây tôi sẽ thực hiện method ...

Method swizzling là quá trình hoán đổi implement của những selector có sẵn. Giả sử bạn có lớp A có 2 function là hello và goodbye. Bạn muốn hoán đổi như sau: Gọi vào function hello thì funtion goodbye được thực hiện và ngược lại. Đó là mục đích của medthod swizzling.

Ở đây tôi sẽ thực hiện method swizzling tự động gọi hàm trong lớp con.

  • Tạo lớp BaseStoryboard kế thừa UIStoryboard.
  • Khai báo method "swizzling_storyboardWithName: bundle :"
  • Override hàm load ở class BaseStoryboard(Hàm load là function class được gọi khi class được load, lúc này tôi sẽ hoán đổi method "storyboardWithName: bundle : :" và "swizzling_instantiateViewControllerWithIdentifier :"
//
//  BaseStoryboard.h
//  Demo
//
//  Created by Thanh Vu on 6/7/17.
//  Copyright © 2017 Thanh Vu. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface BaseStoryboard : UIStoryboard
+(BaseStoryboard *)swizzling_storyboardWithName:(NSString *)name bundle:(NSBundle *)storyboardBundleOrNil;
@end

//
//  BaseStoryboard.m
//  Demo
//
//  Created by Thanh Vu on 6/7/17.
//  Copyright © 2017 Thanh Vu. All rights reserved.
//

#import "BaseStoryboard.h"
#import <objc/runtime.h> // 1
@implementation BaseStoryboard

+(void)load
{
    Method origin = class_getClassMethod(self, @selector(storyboardWithName:bundle:)); // 2
    Method swizzling = class_getClassMethod(self, @selector(swizzling_storyboardWithName:bundle:)); // 3
    
    method_exchangeImplementations(origin, swizzling); //4
}

+(UIStoryboard *)swizzling_storyboardWithName:(NSString *)name bundle:(NSBundle *)storyboardBundleOrNil
{
    BaseStoryboard *st = [BaseStoryboard swizzling_storyboardWithName:name bundle:storyboardBundleOrNil];
    // Custom more code
    return st;
}

-(UIViewController *)instantiateViewControllerWithIdentifier:(NSString *)identifier
{
    UIStoryboard *st = [super instantiateViewControllerWithIdentifier:identifier];
    // Custom code inject
    return st;
}
@end

// 1: Import objective c runtime để thực hiện method swizzling. // 2 - 3: Lấy method "storyboardWithName:bundle:" và "swizzling_storyboardWithName:bundle:". // 4: Thực hiện chuyển đổi method.

Sau đó thì khi gọi vào function "storyboardWithName:bundle:" thì "swizzling_storyboardWithName:bundle:" sẽ được thực hiện và ngược lại. Như vậy khi app(có sử dụng storyboard) được chạy thì khi các bạn gọi

UIStoryboard *st = [UIStoryboard storyboardWithName:@"Name" bundle:nil];

thì st sẽ được mang type là BaseStoryboard như vậy chúng ta không cần chỉ định lớp con mà nó sẽ tự động được trả lại thông qua method swizzling. Chúng ta có thể áp dụng cơ chế này để tạo ra DIContainer cho Dependencty Injection.

0