LoginSignup
21
21

More than 5 years have passed since last update.

objcのクラスメソッドとインスタンスメソッドの違い

Posted at

は、ありません。

でも述べたんですが。もう少し踏み込んで。

objcのクラスにはクラスメソッドがあります。
あまり知られていませんがクラスメソッドとインスタンスメソッドの違いは実はあんまりないのです。

例えば、NSObject ClassにはconformsToProtocol:というセレクタのメソッドが、クラスメソッドとインスタンスメソッドと両方ありますが、セレクタだけではその判別は出来ません。なのでこんなこともできます。

ObjcTests.m

+ (BOOL)conformsToProtocol:(Protocol *)protocol
{
    NSObject *obj = [NSObject new];
    return (BOOL)objc_msgSend(obj,_cmd,protocol);
}

- (void)testExample
{
    Class class = [self class];
    XCTAssert([class conformsToProtocol:@protocol(NSObject)], @"???");
}

クラスメソッド+conformsToProtocol:の呼び出しを動的に生成したNSObjectにプロクシーしても、"unrecognized selecter was send to ~"というエラーにはなりません。ちなみに_cmdはSEL型のオブジェクトで、objcのメソッド内での隠し引数(selfもそう)で、すべてのメソッドに第二引数として渡されています。(selfは第一引数)

つまり、こういうことです。


// 以下の二行は同じことをしている
[obj respondsToSelector:@selector(count)];
objc_msgSend(obj,@selector(respondsToSelector:),@selector(count));

クラス、インスタンスを問わずメソッドの中でselfが参照できるのは、objc_msgSendの引数でターゲットが送られているからなんですね。

クラスメソッドの中では以下のようなメソッド呼び出しが可能ですが、それはselfがクラスオブジェクトになっているからです。


+ (void)staticMethod1
{
    [self staticMethod2]; //呼び出せる 
}

+ (void)staticMethod2
{
    ...
}

ということはどういうことかというと、こういうことです。


+ (void)staticMethod1
{
    // 同じ
    [self staticMethod2];
    objc_msgSend(self,@selector(staticMethod2)); // 呼び出せる 
}

+ (void)staticMethod2
{
    ...
}

つまり、objcではクラスに対してもインスタンスと全く同じ方法でメッセージ送信が可能なんですね。

なので、NSSelectorFromString, NSClassFromStringを使うと、単なる文字列からクラスメソッドも呼び出せます。

メタメタですね。

21
21
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
21
21