Clang Атрибуты Clang предназначены для предоставления аннотаций источника. Позволяет разработчикам легко выразить запрос компилятору. Вовлечение статического анализатора, изменение имени, генерация кода и другие процессы. Обычно __attribute__(xxx) входит в код формы. для простоты использования номер общего атрибута Cocoa также определяется как макрос. например, часто встречается в системных заголовочных файлах NS_CLASS_AVAILABLE_IOS(9_0)это __attribute__(availability(...)) простая формулировка этого свойства.

Для ознакомления с общими атрибутами см. вводную статью NSHipster и вводную статью Twitter. В этой статье также будут представлены несколько интересных атрибутов "черной магии", которые могут иметь неожиданные эффекты в некоторых сценариях.

Objc_subclassing_restricted

Используйте это свойство, чтобы определить Final Class, скажем, класс не может быть унаследован, допустим, у нас есть имя foo класса, но мы не хотим, чтобы кто-то мог наследовать от него:

@interface foo : NSObject
@end
//child class
@interface Child : foo // Eunuch cannot be a child 
@end

Пока передний @interface добавляет objc_subclassing_restricted это свойство:

__attribute__((objc_subclassing_restricted)) 
@interface foo : NSObject
@end
//child class 
@interface Child : foo // ←- Compile Error
 @end

Objc_requires_super

Также: NS_REQUIRES_SUPER, при наследовании этого метода super необходимо вызывать подкласс флага, иначе выдается предупреждение компиляции:

@interface Father : the NSObject
 — ( void ) hailHydra __attribute __ ((objc_requires_super));
@end 
@implementation Father
 — ( void ) hailHydra {
     NSLog ( @ “Hail Hydra!” );
} @end 

@interface Son : Father 
@end 
@implementation Son 
— ( void )hailHydra {
} // ←- Warning missing [super hailHydra] @end

Objc_boxable

Коробка сахара синтаксиса Objective-C @(...) может быть базовыми типами данных в NSNumber объекте, если вы хотите тип коробки struct или union в NSValue объекте, это свойство можно использовать:

Typedef struct __attribute__((objc_boxable)) 
{ 
  CGFloat x, y, width, height; 
} XXRect;

Таким образом, XXRect у вас есть возможность быть в боксе:

CGRect rect1 = { 1 , 2 , 3 , 4 }; 
NSValue *value1 = @(rect1); // ←- Compile Error
 XXRect rect2 = { 1 , 2 , 3 , 4 }; 
NSValue *value2 = @(rect2 ); // ✔︎

Конструктор/деструктор

Как следует из названия, конструкторы и деструкторы. Функция этих двух свойств будет вызываться в исполняемом файле (или общей библиотеке) соответственно load и unload. main() выполняется перед вызовом функции и возвратом:

__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 ; 
}

Вывод:

beforeMain
main
afterMain

конструктор и +load выполняются до вызова основной функции, но +load еще раньше, чем конструктор, потому что dyld (начальная начальная точка для динамического компоновщика, программы) загрузки изображения (можно понимать как файл Mach-O) будет сначала уведомлен, когда objc runtime чтобы загрузить в котором все классы, каждый загружает класс, он +load будет вызывать, после того как все загружено, dyld будет вызывать все методы конструктора в этом образе.

Итак, конструктор — отличное время, чтобы сделать что-то плохое:

  1. Все классы загружены
  2. Основная функция еще не выполнена
  3. Нет необходимости монтировать как + load в классе

FDStackViewМетод FDStackViewPatchEntry заключается в использовании этой возможности для реализации трюка украсть день.

PS: Если есть несколько конструкторов и вы хотите управлять приоритетом, вы можете написать __attribute__((constructor(101)))что чем меньше число, тем выше приоритет, 1 ~ 100 зарезервировано для системы.

Enable_if

Это свойство может использоваться только в функциях C и может использоваться для реализации статической проверки параметров:

Static void printValidAge( int age) 
__attribute__((enable_if(age > 0 && age < 120 , “You 丫 Martian?” ))) 
{ 
 printf( “%d” , age); 
}

Выраженная необходимость удовлетворения этой функции называется age > 0 && age < 120разрешенной, а значит:

printValidAge( 26 );  // ✔︎
printValidAge( 150 ); // ←- Compile Error
printValidAge( -1 );  // ←- Compile Error

Очистка

Объявите переменную, когда область действия переменной закончится, вызовите указанную функцию, Reactive Cocoa использует эту функцию для достижения магии @onExit.

__attribute__((cleanup(...)))Используется для оформления переменной и автоматического выполнения указанного метода в конце его области действия, например:

// Specify a cleanup method, note 
// that the input parameter is the address of the modified variable, // the type should be the same 
// For the pointer to the objc object (id *), if it is not mandatory // to declare __strong the default is __autoreleasing, causing the // type does not match 
static void stringCleanUp(__ strong NSString **string) { 
   NSLog ( @”%@” , *string); 
} 
// In a method: 
-(void) someMethod { 
    __ strong NSString *string __attribute__((cleanup(stringCleanUp))) = @”sunnyxx “ ; 
} // automatically calls stringCleanUp when running to the end of
  //this scope

Область заканчивается, включая фигурные скобки, возврат, переход, разрыв, исключение и т. д.
Конечно, переменных, которые можно изменить, больше, чем NSString, настроить класс или базовый тип, все они возможны:

// Custom Class 
static void sarkCleanUp(__ strong Sark **sark) { 
   NSLog ( @”%@” , *sark); 
} 
__ strong Sark *sark __attribute__((cleanup(sarkCleanUp))) = [Sark new] ; 
// The basic type 
static void intCleanUp( NSInteger *integer) { 
   NSLog ( @”%d” , *integer); 
} 
NSInteger integer __attribute__((cleanup(intCleanUp))) = 1 ;

Если в области есть несколько переменных очистки, порядок их вызова
определяется после порядка стека; кроме того, перед этими объектами dealloc вызывается очистка.

Перегружаемый

Для функций 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 ));

Objc_runtime_name

Используется @interface или @protocol имени класса или протокола к другому, указанному во время компиляции:

__attribute__((objc_runtime_name( “SarkGay” ))) 
@interface Sark : NSObject
@end
NSLog ( @”%@” , NSStringFromClass ([Sark class])); // “SarkGay”

Все места, которые используют это имя класса напрямую, будут заменены (единственное, что следует отметить, это неправильно использовать отражение во время выполнения), самое простое и грубое использование — внести путаницу в имя класса:

__attribute__((objc_runtime_name( “40ea43d7629d01e4b8d6289a132482d0dd5df4fa” ))) 
@interface SecretClass : NSObject
@end

Это единственный известный мне атрибут, влияющий на структуру класса времени выполнения objc. Кодируя имя класса, вы можете ввести некоторую информацию во время компиляции, а затем вернуть ее в среду выполнения, а затем отменить ее. Это эквивалентно открытию секретного канала при написании кода и во время выполнения. Мозговой код, если этот атрибут определен как макрос для annotation формы, завершает определенные функции, такие как:

@singleton wrapped __attribute__((objc_runtime_name(…))) 
// renamed the class name to “SINGLETON_Sark_sharedInstance”
@singleton(Sark, sharedInstance) 
@interface Sark : NSObject
 + (instancetype)sharedInstance; 
@end

Во время выполнения с __attribute__((constructor))gain время входа, чтобы найти класс с Runtime, обратное решение 'sharedInstance' информация селектора будет динамическим +alloc, -init и другими альтернативными методами, возвращает +sharedInstance один вариант осуществления.

использованная литература

http://llvm.org/releases/3.8.0/tools/clang/docs/AttributeReference.html
http://clang-analyzer.llvm.org/annotations.html