Objective-Cではカテゴリを使って既存のクラスに新しいメソッドを追加したかのように振る舞わせることができる。
では、カテゴリで新しいメソッドではなく、既存の(というかオーバーライドして使うようなもの)を定義するとどういう挙動になるのか。気になって調べてみた。
例えばUIViewでタッチを検出して処理を行いたい場合はそのビューのサブクラスを作ってtouchesBegan
やtouchesEnded
を実装すればよいし、ViewControllerでも同じようなことができる。
このtouchesBegan
などのメソッドをカテゴリで実装してやる。実装は単にタッチ開始や終了を自身のアドレス付きでログに出すものとなっている。
// UIView+Touch.h
#import <UIKit/UIKit.h>
@interface UIView (Touch)
@end
// UIView+Touch.m
#import "UIView+Touch.h"
@implementation UIView (Touch)
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@"touchesBegan:[%p]", self);
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@"touchesEnded:[%p]", self);
}
@end
そして、こんな感じで適当にビューを作る。置いたのはすべてUIView。UILabelなんかでもいいんだけど、一部のUIコンポーネントはuserInteractionEnabled
をYESにしないといけないのが面倒なのでサンプルではUIVIewにした。
起動して次の順番でそれぞれのビューをタップする。
- UIView 1
- UIView 2
- UIView 3
- 背景部分のView
ログにはそれらのViewのtouchesBegan
やtouchesEnded
からの出力が出ている。
2014-05-30 21:17:36.592 OverrideInCategory[56354:60b] touchesBegan:[0x8f3b190]
2014-05-30 21:17:36.641 OverrideInCategory[56354:60b] touchesEnded:[0x8f3b190]
2014-05-30 21:17:37.585 OverrideInCategory[56354:60b] touchesBegan:[0x8f3aac0]
2014-05-30 21:17:37.675 OverrideInCategory[56354:60b] touchesEnded:[0x8f3aac0]
2014-05-30 21:17:38.639 OverrideInCategory[56354:60b] touchesBegan:[0x8f3b7e0]
2014-05-30 21:17:38.757 OverrideInCategory[56354:60b] touchesEnded:[0x8f3b7e0]
2014-05-30 21:17:39.953 OverrideInCategory[56354:60b] touchesBegan:[0x8f3b130]
2014-05-30 21:17:40.061 OverrideInCategory[56354:60b] touchesEnded:[0x8f3b130]
先ほど定義したUIView+Touch
のヘッダーはどこにも#import
はしていないが、全てのViewに対してtouchesBegan
などが有効になっている。こういう言語仕様になっているということを知らなかったので、へぇーという感じ。