大刘的 iOS 自学笔记

OC中一些预定义宏

2022-06-26  本文已影响0人  大刘

Created by 大刘 liuxing8807@126.com

看一些内置的宏(C/C++, OC可用),比如:

__LINE__     是整数类型;
__FILE__     宏是字符串类型;
__TIME__     宏是字符串类型;
__FUNCTION__ 宏是字符串类型;
__DATE__     宏是字符串类型;

采用#define定义宏,宏的优劣很明显,但使用宏在某些场景下确实可以起到一些作用;

举其中的一些示例:

__FUNCTION__

C语言中获取函数名,一般是__func__,GCC还支持FUNCTION.同时,PRETTY_FUNCTION`对函数的打印会带上参数

#include <stdio.h>

void sayHello(char *str) {
    printf("%s: hello %s\n", __PRETTY_FUNCTION__, str); // void sayHello(char *): hello daliu
}

int main(int argc, const char * argv[]) {
    printf("%s %s %s\r\n",__func__,__FUNCTION__,__PRETTY_FUNCTION__); // main main int main(int, const char **)
    sayHello("daliu");
    return 0;
}

__COUNTER__

__COUNTER__也是C的一个宏,它的值从0开始,每次调用就会加1,因为一般可以用来做为UniqueId的一部分.

From Doc:

COUNTER
This macro expands to sequential integral values starting from 0. In conjunction with the ## operator, this provides a convenient means to generate unique identifiers. Care must be taken to ensure that COUNTER is not expanded prior to inclusion of precompiled headers which use it. Otherwise, the precompiled headers will not be used.

上面讲通常搭配连接符##使用,示例:

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

#define ZZ_CONCAT(A, B) ZZ_CONCAT2(A, B)
#define ZZ_CONCAT2(A, B) A##B

#define SKILL \
+ (void)ZZ_CONCAT(skill_, __COUNTER__) { \
    NSLog(@"%@", NSStringFromSelector(_cmd)); \
}

@interface Person : NSObject

@end

NS_ASSUME_NONNULL_END
#import "Person.h"
#import <objc/runtime.h>

@implementation Person

+ (void)load {
    [self printClassMethod:self];
}

// 打印类方法
+ (void)printClassMethod:(Class)cls {
    unsigned int methodCount = 0;
    // object_getClass(cls) 获取元类对象,类方法存储在元类对象中
    Method *methods = class_copyMethodList(object_getClass(cls), &methodCount);

    for (unsigned int i = 0; i < methodCount; i++) {
        Method method = methods[i];
        NSString *methodName = NSStringFromSelector(method_getName(method));
        NSLog(@"方法名: %@", methodName);
    }

    free(methods);
}

SKILL
SKILL
SKILL
SKILL
SKILL
SKILL

@end

程序打印:

方法名: printClassMethod:
方法名: skill_0
方法名: skill_1
方法名: skill_2
方法名: skill_3
方法名: skill_4
方法名: skill_5
方法名: load

__LINE__

__LINE__表示当前行,是整数类型,示例:

line.png

可以在很多场景下使用__LINE__做一些事情,比如自定义Log并打印出代码的哪一行出现了问题,就可以使用这种方式:

#ifdef DEBUG
#define ZZLog(fmt, ...) NSLog((@"🙍♂️ ZZ log method: %s line: %d " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#define ZZLog(fmt, ...)
#endif

需要注意的是,这里的__LINE__所代指的行号是宏展开的地方,而不是宏定义的地方;而且宏有个特点是它实际上是一行,宏定义中使用了\只是代码显示的分隔,但实际上仍是一行,因此__LINE__仍是当前宏展开的那一行,示例:

#import <Foundation/Foundation.h>
#import "Test.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        [Test test];
    }
    return 0;
}
1   //
2   //  Test.h
3   //  TestLine
4   //
5   //  Created by daliu.
6   //
7   
8   #import <Foundation/Foundation.h>
9   
10  NS_ASSUME_NONNULL_BEGIN
11  
12  #define PRINT_LINE_METHOD \
13  + (void)printCurrentLine { \
14      NSLog(@"current line is: %d", __LINE__); \
15  }
16  
17  @interface Test : NSObject
18  
19  + (void)test;
20  
21  @end
22  
23  NS_ASSUME_NONNULL_END
1   //
2   //  Test.m
3   //  TestLine
4   //
5   //  Created by daliu on 2020/12/5.
6   //
7   
8   #import "Test.h"
9   
10  @implementation Test
11  
12  PRINT_LINE_METHOD
13  // 因为宏展开所在的行是第12行,即在第12行相当于: + (void)printCurrentLine { NSLog(@"current line is: %d", __LINE__); }
14  // 所以打印结果是 current line is: 12
15  
16  + (void)test {
17      [self printCurrentLine];
18  }
19  
20  @end
上一篇下一篇

猜你喜欢

热点阅读