0

メソッドの入れ替えがどのように機能するかをよりよく理解するために、この記事に従っています。次のようなメイン ビュー コントローラー (これは新しいプロジェクトです) があります。

#import "GLViewController.h"
#import <objc/runtime.h>

@implementation UIViewController (Tracking)

+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    Class class = [UIViewController class];

    SEL originalSelector = @selector(viewWillAppear:);
    SEL swizzledSelector = @selector(xxx_viewWillAppear:);

    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

    BOOL didAddMethod =
    class_addMethod(class,
                    originalSelector,
                    method_getImplementation(swizzledMethod),
                    method_getTypeEncoding(swizzledMethod));

    if (didAddMethod) {
        class_replaceMethod(class,
                            swizzledSelector,
                            method_getImplementation(originalMethod),
                            method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
});
}

#pragma mark - Method Swizzling

- (void)xxx_viewWillAppear:(BOOL)animated {
[self xxx_viewWillAppear:animated];
NSLog(@"viewWillAppear: %@", self);
}

@end


@implementation GLViewController

-(void)viewWillAppear:(BOOL)animated
{
  NSLog(@"glviewappear");
}

 - (void)viewDidLoad
{
    [super viewDidLoad];

}
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

これを実行すると、glviewappear が出力され、削除すると

-(void)viewWillAppear:(BOOL)animated
{
  NSLog(@"glviewappear");
}

次に、それは印刷され viewWillAppear: <GLViewController: 0x9d11a90>ます。私のプロジェクトは、これらの両方の方法で起動できる必要があります。これを行う方法はありますか?

4

1 に答える 1

5

簡単な理由があります。を呼び出していないため、UIViewController 実装を呼び出していません[super viewWillAppear:animated]

ただ行う:

-(void)viewWillAppear:(BOOL)animated
{
  [super viewWillAppear:animated];
  NSLog(@"glviewappear");
}

詳しい説明はこちら

Objective C クラスの各メソッドは単純な関数に過ぎず、ディスパッチ テーブルに保存されたポインターを介して参照されます。キーはセレクターであり、関連する値は各メソッドの実装 ( IMP) へのポインターです。

スウィズルでは、ディスパッチ テーブル内の 2 つのポインターを交換するだけで、参照される関数を交換できます。ディスパッチ テーブルはクラスに関連付けられているため、スウィズリングは実行するクラスでのみ発生し、サブクラスでは発生しません。

あなたの場合、3 つの異なる関数が使用されています。 UIViewController には、ディスパッチ テーブル内の次の関数へのポインタがあります。これらの関数は、スウィズリングによって実行時にスワップされます。

  • viewWillAppear:(現在は実装を指していxxx_viewWillAppear:ます)
  • xxx_viewWillAppear:(現在は実装を指していviewWillAppear:ます)

GLViewController には、 の独自の実装への別のポインターがありviewWillAppear:ます。

を呼び出さない場合super、クラスのディスパッチ テーブルにアクセスしていないためUIViewController、実装をまったく呼び出していません。

viewWillAppear: メソッドを削除すると、スーパー実装が自動的に呼び出されるため、明らかに機能します。

于 2014-05-19T23:39:58.023 に答える