blog

ClangでOCオブジェクトの性質を見る

1.Clangコンパイル macOSプロジェクトを作成し、中のmain.mファイルをコンパイルします。 コンパイルコマンド: clang -rewrite-objc main.m -o main.cp...

Aug 10, 2020 · 4 min. read
シェア

Clang

macOSプロジェクトを作成し、中のmain.mファイルをコンパイルします。clang -rewrite-objc main.m -o main.cppCompileコマンド: このコマンドでmain.mをcppファイルにコンパイルできます。

// macosコマンドライン項目
clang -rewrite-objc main.m -o main.cpp 
clang -rewrite-objc 
// UIKitライブラリへの参照
clang -rewrite-objc -fobjc-arc -fobjc-runtime=ios- -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.5.sdk main.m
// xcrun xcode  
xcrun -sdk iphonesimulator clang -arch -arm64 -rewrite-objc main.m -o main.m-arm64.cpp //  
xcrun -sdk iphoneos clang -arch -arm64 -rewrite-objc main.m -o main.m-arm64.cpp //  

コンパイル結果

main.mの内容は以下の通り:

#import <Foundation/Foundation.h>
@interface Person : NSObject {
 NSString *nickname;
}
@property (weak, nonatomic) NSString * name;
@end
@implementation Person
@end
int main(int argc, const char * argv[]) {
 @autoreleasepool {
 
 }
 return 0;
}

検索結果:124件

これらの結果を比較すると、LGPersonは次のようなcppファイルをコンパイルすることがわかります。

  • Person クラスは objc_object 構造体にコンパイルされます:
  • メンバー変数 nickname または nickname
  • 属性名は_name
  • name属性のゲッター・メソッドとセッター・メソッドの両方が生成されます。
#ifndef _REWRITER_typedef_Person
#define _REWRITER_typedef_Person
typedef struct objc_object Person;
typedef struct {} _objc_exc_Person;
#endif
extern "C" unsigned long OBJC_IVAR_$_Person$_name;
struct Person_IMPL {
	struct NSObject_IMPL NSObject_IVARS;
	NSString *nickname;
	NSString *_name;
};
// @property (copy, nonatomic) NSString * name;
/* @end */
// @implementation Person
static NSString * _I_Person_name(Person * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_Person$_name)); }
extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);
static void _I_Person_setName_(Person * self, SEL _cmd, NSString *name) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct Person, _name), (id)name, 0, 1); }
// @end

typedef struct objc_objectもう一度グローバル検索をかけると、843件の検索結果が得られますので、この構造が多くのものを定義していることがわかります。

では、一番下のobjc_objectとは一体何なのかというと、objc_object {で検索すればその定義を見つけることができます。objc_objectの定義は、objc_objectで検索すれば見つかります。クラスとidとSELもその上下に見つかりました。

typedef struct objc_class *Class;
struct objc_object {
 Class _Nonnull isa __attribute__((deprecated));
};
typedef struct objc_object *id;
typedef struct objc_selector *SEL;

上記のコードから以下の結論が得られます:

  • objc_objectは一番下の構造体です。
  • idはobjc_object型の構造体へのポインタです。
  • SELはobjc_selector型構造体へのポインタです。
  • Classはobjc_class型の構造体へのポインタです。

メソッドとシグネチャの一覧

注:Xcode 11.5

static struct /*_method_list_t*/ {
	unsigned int entsize; // sizeof(struct _objc_method)
	unsigned int method_count;
	struct _objc_method method_list[4];
} _OBJC_$_INSTANCE_METHODS_Person __attribute__ ((used, section ("__DATA,__objc_const"))) = {
	sizeof(_objc_method),
	4,
	{{(struct objc_selector *)"name", "@", (void *)_I_Person_name},
	{(struct objc_selector *)"setName:", "v@16", (void *)_I_Person_setName_},
	{(struct objc_selector *)"name", "@", (void *)_I_Person_name},
	{(struct objc_selector *)"setName:", "v@16", (void *)_I_Person_setName_}}
};

"@16@0:8 "はメソッドのシグネチャです。

  • @ は戻り値の型です。
  • 16は全パラメータが占めるメモリの長さ
  • は最初のパラメータタイプ
  • 0は最初のパラメータの開始位置
  • は2番目のパラメータの型です。
  • 8は第2パラメータの開始位置

対応する記号の種類

  • 印刷する
void types(){
 NSLog(@"char --> %s",@encode(char));
 NSLog(@"int --> %s",@encode(int));
 NSLog(@"short --> %s",@encode(short));
 NSLog(@"long --> %s",@encode(long));
 NSLog(@"long long --> %s",@encode(long long));
 NSLog(@"unsigned char --> %s",@encode(unsigned char));
 NSLog(@"unsigned int --> %s",@encode(unsigned int));
 NSLog(@"unsigned short --> %s",@encode(unsigned short));
 NSLog(@"unsigned long --> %s",@encode(unsigned long long));
 NSLog(@"float --> %s",@encode(float));
 NSLog(@"bool --> %s",@encode(bool));
 NSLog(@"void --> %s",@encode(void));
 NSLog(@"char * --> %s",@encode(char *));
 NSLog(@"id --> %s",@encode(id));
 NSLog(@"Class --> %s",@encode(Class));
 NSLog(@"SEL --> %s",@encode(SEL));
 int array[] = {1,2,3};
 NSLog(@"int[] --> %s",@encode(typeof(array)));
 typedef struct person{
 char *name;
 int age;
 }Person;
 NSLog(@"struct --> %s",@encode(Person));
 
 typedef union union_type{
 char *name;
 int a;
 }Union;
 NSLog(@"union --> %s",@encode(Union));
 int a = 2;
 int *b = {&a};
 NSLog(@"int[] --> %s",@encode(typeof(b)));
}
Read next

EventBusソースコード解析

4.5 ASYNC : 非同期スレッドで実行されます。どのような場合でも、サブスクリプションメソッドを実行するスレッドは、ポスト送信者のスレッドとは異なり、メインスレッドではない別のスレッドですが、非同期は常に別のスレッドで実行されます。 6.1 通常のイベント: 通常のイベントを送信する場合、正常に登録された同じイベントタイプのサブスクライバのみが通常のイベントを受信できます。...

Aug 10, 2020 · 17 min read