Clang Attributes黒魔術小記
5377 ワード
孫源sunnyxxの技術ブログシリーズhttp://blog.sunnyxx.com/2016/05/14/clang-attributes/
2016年5月14日
Clang AttributesはClangで提供されたソースの注釈であり、開発者がコンパイラにある要求を表現するのに便利であり、Static Analyzer、Name Mangling、Code Generationなどの制御に参加し、一般的に
一般的な属性の紹介は、NSHisterの紹介文とtwitterの紹介文を見ることができます。いくつかの面白い「黒の魔法」を紹介します。いくつかの場面で思わぬ効果があるかもしれません。
以下のテストはXcode 7.3(Clang 3.8)を基準とします。
OBsubclassing_resticted
この属性を使用すると、
aka:
Objective-Cの
名前の通り、コンストラクタとデストラクタ、この2つの属性の関数は、それぞれ実行可能ファイル(またはshared library)loadとunloadで呼び出され、
だからconstructorは悪いことをする絶好のチャンスです。すべてのクラスはすでにロード済みです。 main関数はまだ実行されていません。 は+ロードのような必要がなくても、一つのクラスに をマウントしなければなりません。
PS:複数のconstructorがあって、優先度を制御したいなら、
enabale_if
この属性はC関数だけで使用できます。パラメータの静的検査を行うために使用できます。
変数に宣言します。この変数のスコープが終了すると、指定された関数を呼び出します。Reactive Cocoaはこの特性で不思議な
overloadable
C関数では、いくつかの関数名が同じであることが定義されますが、パラメータが異なる方法では、コンパイラを呼び出すと自動的にパラメータに従って関数のプロトタイプを選択します。
これは私が知っている唯一のobjcの運行時のクラス構造に影響があるatributeです。コードクラス名を通じて、コンパイル時にいくつかの情報を注入して、運行時に連れてこられた後、逆解凍します。これは秘密通路を開設して、コードを書く時と運送時に相当します。頭の穴を開けてみてください。このatributeをマクロとして定義したら、
References
http://llvm.org/releases/3.8.0/tools/clang/docs/AttributeReference.html http://clang-analyzer.llvm.org/annotations.html
2016年5月14日
Clang AttributesはClangで提供されたソースの注釈であり、開発者がコンパイラにある要求を表現するのに便利であり、Static Analyzer、Name Mangling、Code Generationなどの制御に参加し、一般的に
__attribute__(xxx)
の形でコードに現れる。使用を容易にするために、いくつかの一般的な属性はまた、Cocoaによってマクロとして定義されています。例えば、システムヘッダファイルによく登場するNS_CLASS_AVAILABLE_IOS(9_0)
は、__attribute__(availability(...))
という属性の簡単な書き方です。一般的な属性の紹介は、NSHisterの紹介文とtwitterの紹介文を見ることができます。いくつかの面白い「黒の魔法」を紹介します。いくつかの場面で思わぬ効果があるかもしれません。
以下のテストはXcode 7.3(Clang 3.8)を基準とします。
OBsubclassing_resticted
この属性を使用すると、
Final Class
という名前のクラスがあると仮定して、つまり引き継がれてはいけないクラスを定義することができます。@interface Eunuch : NSObject
@end
@interface Child : Eunuch //
@end
@interfaceの前にEunuch( )
という属性をつければいいです。__attribute__((objc_subclassing_restricted))
@interface Eunuch : NSObject
@end
@interface Child : Eunuch //
OBrequires_スーパーaka:
objc_subclassing_restricted
、フラグサブクラスはこの方法を継承する時にNS_REQUIRES_SUPER
を呼び出す必要があります。そうでなければ、コンパイルの警告が与えられます。@interface Father : NSObject
- (void)hailHydra __attribute__((objc_requires_super));
@end
@implementation Father
- (void)hailHydra {
NSLog(@"hail hydra!");
}
@end
@interface Son : Father
@end
@implementation Son
- (void)hailHydra {
} //
OBbox ableObjective-Cの
super
シンタックス飴は、基本データタイプボックスを@(...)
オブジェクトにすることができ、もしbox 1つのNSNumber
タイプまたはstruct
タイプがunion
オブジェクトになるなら、この属性を使用することができます。typedef struct __attribute__((objc_boxable)) {
CGFloat x, y, width, height;
} XXRect;
これにより、NSValue
は、boxによって能力を備えている:CGRect rect1 = {1, 2, 3, 4};
NSValue *value1 = @(rect1); //
constructor/destructor名前の通り、コンストラクタとデストラクタ、この2つの属性の関数は、それぞれ実行可能ファイル(またはshared library)loadとunloadで呼び出され、
XXRect
の関数が呼び出される前とreturn後に実行されると理解できる。__attribute__((constructor))
static void beforeMain(void) {
NSLog(@"beforeMain");
}
__attribute__((destructor))
static void afterMain(void) {
NSLog(@"afterMain");
}
int main(int argc, const char * argv[]) {
NSLog(@"main");
return 0;
}
// Console:
// "beforeMain" -> "main" -> "afterMain"
constructorとmain()
は全部メーン関数の実行前に呼び出されましたが、+load
はconstructorよりもっと前になくしました。dyld(動的リンク器、プログラムの最初の起点)はイメージをロードする時に、+load
にすべての種類をロードするように通知します。全部のロードが完了したら、dyldはこのイメージの中のすべてのconstructor方法を呼び出すことができます。だからconstructorは悪いことをする絶好のチャンスです。
objc runtime
のFDStockViewPatch Entry方法は、このタイミングで奇日を実現するための手段である。PS:複数のconstructorがあって、優先度を制御したいなら、
+load
と書いてもいいです。中の数字は小さいほど優先度が高く、1~100はシステムのために保留されます。enabale_if
この属性はC関数だけで使用できます。パラメータの静的検査を行うために使用できます。
static void printValidAge(int age)
__attribute__((enable_if(age > 0 && age < 120, " ?"))) {
printf("%d", age);
}
この関数の呼び出しはFDStackView
を満たす必要があるという意味で許可されます。printValidAge(26); // √
printValidAge(150); //
cleanup変数に宣言します。この変数のスコープが終了すると、指定された関数を呼び出します。Reactive Cocoaはこの特性で不思議な
__attribute__((constructor(101)))
を実現しました。これについてatributeは前の記事で紹介されています。overloadable
C関数では、いくつかの関数名が同じであることが定義されますが、パラメータが異なる方法では、コンパイラを呼び出すと自動的にパラメータに従って関数のプロトタイプを選択します。
__attribute__((overloadable)) void logAnything(id obj) {
NSLog(@"%@", obj);
}
__attribute__((overloadable)) void logAnything(int number) {
NSLog(@"%@", @(number));
}
__attribute__((overloadable)) void logAnything(CGRect rect) {
NSLog(@"%@", NSStringFromCGRect(rect));
}
// Tests
logAnything(@[@"1", @"2"]);
logAnything(233);
logAnything(CGRectMake(1, 2, 3, 4));
OBruntime_nameage > 0 && age < 120
または@onExit
のためにクラスまたはプロトコルの名前をコンパイルする時に別のものに指定します。__attribute__((objc_runtime_name("SarkGay")))
@interface Sark : NSObject
@end
NSLog(@"%@", NSStringFromClass([Sark class])); // "SarkGay"
このクラスの名前を直接使うところは全部入れ替えられます。一番簡単で乱暴な使い方はクラス名の混淆をすることです。__attribute__((objc_runtime_name("40ea43d7629d01e4b8d6289a132482d0dd5df4fa")))
@interface SecretClass : NSObject
@end
数字で始まることもできます。心配しないでください。もしスクリプトを書いたら、各クラスの前にランダムに生成された@interface
を入れて、一番簡単なコードを混同して完成します。これは私が知っている唯一のobjcの運行時のクラス構造に影響があるatributeです。コードクラス名を通じて、コンパイル時にいくつかの情報を注入して、運行時に連れてこられた後、逆解凍します。これは秘密通路を開設して、コードを書く時と運送時に相当します。頭の穴を開けてみてください。このatributeをマクロとして定義したら、
@protocol
という形でいくつかの機能を完成します。// @singleton __attribute__((objc_runtime_name(...)))
// "SINGLETON_Sark_sharedInstance"
@singleton(Sark, sharedInstance)
@interface Sark : NSObject
+ (instancetype)sharedInstance;
@end
運転時にobjc_runtime_name
で入口タイミングを取得し、このクラスをルンムで見つけ、「sharedInstance」というselector情報を逆解釈し、動的にannotation
、__attribute__((constructor))
などの方法で置き換え、+ alloc
の単例に戻る。References
http://llvm.org/releases/3.8.0/tools/clang/docs/AttributeReference.html http://clang-analyzer.llvm.org/annotations.html