iOS

2,988 阅读4分钟
原文链接: www.jianshu.com

定义一个类不能够被继

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 单例。

如果你看到了这里,请给个👍么么哒
参考文档
参考链接