LoginSignup
11
11

More than 5 years have passed since last update.

UIStoryboardをサブクラスで置き換える

Posted at

背景

UIStoryboardは下記のファクトリを使って生成します。

+ (UIStoryboard *)storyboardWithName:(NSString *)name bundle:(NSBundle *)storyboardBundleOrNil

今回はTyphoon FrameworkというDIコンテナを導入するにあたって、このファクトリで生成されるUIStoryboardをサブクラスで置き換える必要が出て来ました。

ClassメソッドのSwizzling

UIStoryboardのクラスメソッドの入れ替えは、Objective Cのランタイム機能を使うと簡単にできます。

- (void)swizzleSample
{
    Method original,swizzled;
    original = class_getClassMethod([UIStoryboard class], @selector(storyboardWithName:bundle:));
    swizzled = class_getClassMethod([UIStoryboard class], @selector(ppStoryboardWithName:bundle:));
    method_exchangeImplementations(original, swizzled);
}

ただ、ここで問題になるのがサブクラス側でのファクトリ実装です。
今回組み込みたいサブクラスは下記のようにスーパークラスのファクトリメソッドを使用しています。というか、UIStoryboardの場合にはこうせざるを得ないです。

TyphoonStoryboard.h
+ (TyphoonStoryboard *)storyboardWithName:(NSString *)name bundle:(NSBundle *)storyboardBundleOrNil
{
    return [super storyboardWithName:name bundle:storyboardBundleOrNil];
}

単純にファクトリメソッドを入れ替えると無限ループしてしまうため、下記のようにselfに格納されたクラスオブジェクトによって処理を分岐するようにします。

@implementation UIStoryboard (PPTyphoon)

+ (UIStoryboard *)ppStoryboardWithName:(NSString *)name bundle:(NSBundle *)storyboardBundleOrNil
{
    if(self != [UIStoryboard class]){
        // Called by subclass. Use original implementation
        return [self ppStoryboardWithName:name bundle:storyboardBundleOrNil];
    }
    return [TyphoonStoryboard storyboardWithName:name
                                         factory:[TyphoonComponentFactory defaultFactory]
                                          bundle:storyboardBundleOrNil];
}

@end

これにより、下記のような順序で処理が実行され、無事に生成されるクラスをサブクラスで置き換えることができました。

  1. UIStoryBoardのファクトリ呼び出し
  2. UIStoryboardの独自ファクトリ(swizzled)-> TyphoonStoryboard呼び出し
  3. TyphoonStoryboardのファクトリ -> super呼び出し
  4. UIStoryboardの独自ファクトリ(swizzled) -> 本来の実装呼び出し
  5. UIStoryboardの本来のファクトリ

Objective Cって 気持ち悪い 面白いですね。

Typhoonって何?

DIコンテナです。Typhoon Frameworkについてはまた別の機会に。

11
11
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
11