定义一个类不能够被继
objc_subclassing_restricted
__attribute__((objc_subclassing_restricted)) //这样定义,该类不可以继承
@interface Eunuch : NSObject
+(void)show;
@end
强行继承就会出现该情况

110.png
定义一个方法,子类调用该方法的时候需要用 super
__attribute__((objc_requires_super))
父类具体代码如下:
.h
@interface FalseEunuch : NSObject
+(void)show __attribute__((objc_requires_super));;
@end
.m
#import "FalseEunuch.h"
@implementation FalseEunuch
+(void)show
{
//内容
}
@end
子类代码如下
.h
#import "FalseEunuch.h"
@interface Child : FalseEunuch
@end
.m
#import "Child.h"
@implementation Child
+(void)show
{
[super show]; //调用super
}
@end
定义的的结构体也可以使用语法糖
__attribute__((objc_boxable))
###例如:
这样写:
CGRect rect1 = {1, 2, 3, 4};
NSValue *value1 = @(rect1); //编译器报错
###但是:
这样写:
typedef struct __attribute__((objc_boxable)) {
CGFloat x, y, width, height;
} YYGRect;
YYGRect rect2 = {1, 2, 3, 4};
NSValue *value2 = @(rect2); //编译通过
在程序的主函数之前运行,跟UIWindow能放在视图之上并设置优先级类似概念
__attribute__((constructor))__attribute__((destructor))
这样定义之后程序最先执行在main函数之前执行
__attribute__((constructor)) #### 之前
static void beforeMain(void)
{
NSLog(@"在Main前");
}
//如果在之前执行的比较多的话可以设置之前优先级,类似UIwindow显示的优先级
__attribute__((constructor(101))) //里面的数字越小优先级越高,1 ~ 100 为系统保留,类似win系统的系统使用的端口号概念。
#### 之后
如果main函数return 0; 那么会执行:
__attribute__((destructor))
static void afterMain(void)
{
NSLog(@"在Main的return 0 后执行");
}
设置程序调用时传参的筛选性
enable_if__attribute__((enable_if(age > 0 && age < 120,"这里没有搞明白")))
定义函数:
static void printValidAge(int age)
__attribute__((enable_if(age > 0 && age < 120,"这里没有搞明白")))
{
printf("%d", age);
}
//调用该函数:
printValidAge(20); //通过
printValidAge(150); //不通过
//如果里面传参的数据不满足 :age > 0 && age < 120 编译器不通过
修饰一个变量在该变量作用域结束后,自动调用一个指定的方法 Cleanup
所谓作用域结束,包括大括号结束、return、goto、break、exception等各种情况。
可以修饰的变量不止NSString,包括自定义Class或基本类型都是可以的:以压栈的方式调用,在函数调用dealloc之前执行:
__attribute__((cleanup))
在方法中
// 指定一个cleanup方法,注意入参是所修饰变量的地址,类型要一样
// 对于指向objc对象的指针(id *),如果不强制声明__strong默认是__autoreleasing,造成类型不匹配
__strong NSString *string __attribute__((cleanup(Show))) = @"Yin Yu 思密达";
...//这里写N多代码,都是最后执行下面的函数
在外面
static void Show(__strong NSString **string)
{
NSLog(@"代码以为我为标志结束!%@",*string);
}
例子如下:
函数里面:
// 加了个`unused`的attribute用来消除`unused variable`的warning
__strong void(^block)(void) __attribute__((cleanup(blockCleanUp), unused)) = ^{
NSLog(@"代码以为我标志结束!");
};
//所调用的函数
// void(^block)(void)的指针是void(^*block)(void)
static void blockCleanUp(__strong void(^*block)(void))
{
(*block)();
}
看明白上面了,为了开发方便使用宏定义
//定义宏
#define onExit __strong void(^block)(void) __attribute__((cleanup(blockCleanUp), unused)) = ^
//使用的地方
onExit {
NSLog(@"代码以为为结束");
};
//下面~~~~~~~~N多代码
# 所调用的函数
// void(^block)(void)的指针是void(^*block)(void)
static void blockCleanUp(__strong void(^*block)(void))
{
(*block)();
}
#行家一出手便知有没有
定义若干函数,函数名字相同但是方法不同,编译器能够自动识别调用的函数
__attribute__((overloadable))
#定义三个名字相同的函数
__attribute__((overloadable)) void logAnything(id arr)
{
NSLog(@"%@", arr);
}
__attribute__((overloadable)) void logAnything(int num)
{
NSLog(@"%@", @(num));
}
__attribute__((overloadable)) void logAnything(CGRect rect)
{
NSLog(@"%@", NSStringFromCGRect(rect));
}
#调用
//传递数值
logAnything(@[@"hello",@"world"]);
//int 数值
logAnything(66);
//Rect
logAnything(CGRectMake(0, 0, 0, 0));
结果打印如下:
2016-08-03 14:06:20.672 0803-黑魔法[24302:1914372] (
hello,
world
)
2016-08-03 14:06:20.672 0803-黑魔法[24302:1914372] 66
2016-08-03 14:06:20.672 0803-黑魔法[24302:1914372] {{0, 0}, {0, 0}}
告诉编译器编译的时候不要编译我本来的名字,可以定义一个学名,在App上架以后防止有些心机叵测的人反汇编
objc_runtime_name用于 @interface 或 @protocol
__attribute__((objc_runtime_name("FalseEunuch"))) //相当于给Eunuch起个学名
@interface Eunuch : NSObject
+(void)show;
@end
#示例:
NSLog(@"%@",[Eunuch class]);
#得到的打印消息
2016-08-03 14:16:46.882 0803-黑魔法[24329:1921649] FalseEunuch
类名混淆:
__attribute__((objc_runtime_name("40ea43d7629d01e4b8d6289a132482d0dd5df4fa"))) @interface Eunuch : NSObject @end
拷贝别人的一段话
通过编码类名可以在编译时注入一些信息,被带到运行时之后,再反解出来,这就相当于开设了一条秘密通道,打通了写码时和运行时。脑洞一下,假如把这个 attribute 定义成宏,以 annotation 的形式完成某些功能,比如:
// @singleton 包裹了 __attribute__((objc_runtime_name(...)))
// 将类名改名成 "SINGLETON_Sark_sharedInstance"
@singleton(Sark, sharedInstance)
@interface Sark : NSObject
+ (instancetype)sharedInstance;
@end
在运行时用 __attribute__((constructor)) 获取入口时机,用 runtime 找到这个类,反解出 “sharedInstance” 这个 selector 信息,动态将 + alloc,- init 等方法替换,返回 + sharedInstance 单例。