一、DEBUG 宏区分调试模式和发布模式进行特殊处理
① 利用 Configuration 配置不同的编译环境
- 一个应用往往对应多个域名的情况,测试地址、生产地址、后台接口开发者的个人主机地址:
1.开发人员环境(Other)连接写服务人的电脑,与服务器联调使用
2.开发环境(Debug)完成需求,代码上传,在外网开发服务器调试
3.测试环境(Testing)测试人员使用
4.预发布(PreRelease)测试人员使用,copy 的正式数据
5.正式环境(Release)上传 AppStore 使用
- 新建不同的编译环境:
文章图片
- 在 Build Setting 中搜索 preprocessor macro:
文章图片
- 定义预编译宏 Preprocessor Macros:
k_BUILD_VERSION = 0 -> 开发人员环境(Other)
k_BUILD_VERSION = 1 -> 开发环境(Debug)
k_BUILD_VERSION = 2 -> 测试环境(Testing)
k_BUILD_VERSION = 3 -> 预发布环境(PreRelease)
k_BUILD_VERSION = 4 -> 正式环境(Release)
文章图片
- 用预编译命令 Define 不同的 URL:
#if(k_BUILD_VERSION == 0)
// 开发人员环境(Other)
your code
#elif(k_BUILD_VERSION == 1)
// 开发环境(Debug)
your code
#elif(k_BUILD_VERSION == 2)
// 测试环境(Testing)
your code
#elif(k_BUILD_VERSION == 3)
// 预发布(PreRelease)
your code
#elif(k_BUILD_VERSION == 4)
// 正式环境(Release)
your code
#endif
- 切换 build Configuration:
文章图片
- 配置不同环境,如果手机装了多个环境的项目,不好区分,可以在 Xcode 配置脚本,在编译时根据不同环境制作不同的 icon 图标。
// 调试模式
#ifdef DEBUG
#define NSLog(...)NSLog(__VA_ARGS__)
#define KisDebug 1//#define NSLog(fmt, ...) NSLog((@"[文件名:%s]\n" "[函数名:%s]\n" "[行号:%d] \n" fmt), __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__);
#else // 发布模式
#define NSLog(...)
#define KisDebug 0
#endif
二、Objective-C’s boxing capability(“装箱”快速构造数字对象) ① NSLog 的输出
- NSLog 将消息输出到 Apple System Log 工具或 Console 应用程序:
② 改进 Objective-C 中的日志记录
宏 | 格式说明符 | 描述 |
---|---|---|
func | %s | 当前函数签名 |
LINE | %d | 在源代码文件的当前行号 |
FILE | %s | 源代码文件的完整路径 |
PRETTY_FUNCTION | %s | print the name of the function being called |
NSLog( @"calling: %s", __PRETTY_FUNCTION__ );
表达 | 格式说明符 | 描述 |
---|---|---|
NSStringFromSelector(_cmd) | %@ | Name of the current selector |
NSStringFromClass([self class]) | %@ | Name of the current object’s class |
[[NSString stringWithUTF8String:FILE] lastPathComponent] | %@ | Name of the source code file(源代码文件的名称) |
[NSThread callStackSymbols] | %@ | NSArray of the current stack trace as programmer |
NSLog(@"%@", [NSThread callStackSymbols]);
- 数据类型的格式说明符:
Type | Format specifier | Considerations |
---|---|---|
NSInteger | %ld or %lx | Cast the value to long |
NSUInteger | %lu or %lx | Cast the value to unsigned long |
CGFloat | %f or %g | %f works for floats and doubles when formatting; but note the technique described below for scanning |
CFIndex | %ld or %lx | The same as NSInteger |
pointer | %p or %zx | %p adds 0x to the beginning of the output. If you don’t want that, use %zx and no typecast |
- NSLog 函数提供许多用于打印数字的替代标记(例如 %d,%ld,%f,%d 等),为了方便起见,可以使用 Objective-C 的装箱功能来节省时间并避免编译器警告:
double myNumber = 8.80;
NSLog(@"number : %@", @(myNumber));
NSLog(@"number class: %@", @(myNumber).class);
// 调试结果
number : 8.8
number class: __NSCFNumber
- 平常也可以使用 @ 来快速包装数字类型以对象的形式进行存储和传参:
[discountArray addObject:[[self class] mj_objectWithKeyValues:@{@"placeholder":QCTLocal(@"please_input_card_num"),@"btnContent":QCTLocal(@"member_see"),@"EnterModelType":@2,@"isEnabled":@1,@"isLast":@1,@"block":block}]];
④ 打印调试(强化 NSLog)
// A better version of NSLog
#define NSLog(format, ...) do { \
fprintf(stderr, "<%s : %d> %s\n", \
[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], \
__LINE__, __func__);
\
(NSLog)((format), ##__VA_ARGS__);
\
fprintf(stderr, "-------\n");
\
} while (0)
- 输出结果:
-[ViewController viewDidLoad]
2022-06-26 17:33:31.022 DEUBG[12852:1238167] Hello World!
-------
三、benchmarking 的时间测量 ① benchmarking
- benchmark 是程序明确地要测量并比较硬件以及软件上的运行效率。benchmarking 表示的则是测量效率的一段代码,可结合 Instruments 进行性能分析。
- benchmark 代码不应该被加到终极提交的产品中,Benchmarking 应该被分离到单独的项目分支或独立的测试用例中,或者使用 DEBUG 宏的区分调试模式和发布模式进行特殊处理。
- 推荐使用包装 mach_absolute_time 的 CACurrentMediaTime() 方法来以秒为单位测量时间:
/* Returns the current CoreAnimation absolute time. This is the result of
* calling mach_absolute_time () and converting the units to seconds. */CA_EXTERN CFTimeInterval CACurrentMediaTime (void)
API_AVAILABLE (macos(10.5), ios(2.0));
// uint64_tmach_absolute_time(void);
// long timestamp = CFAbsoluteTimeGetCurrent()
- 和 NSDate 或 CFAbsoluteTimeGetCurrent()偏移量不同的是,mach_absolute_time() 和 CACurrentMediaTime() 是基于内建时钟的,能够更精确更原子化地测量,并且不会因为外部时间变化而变化(例如时区变化、夏时制、秒突变)。
static size_t const count = 1000;
// 有多少个元素需要添加到数组
static size_t const iterations = 10000;
// 测试运行的次数CFTimeInterval startTime = CACurrentMediaTime();
{
for (size_t i = 0;
i < iterations;
i++) {
@autoreleasepool {// 循环体都被 @autoreleasepool 包裹,用来降低内存占用
NSMutableArray *mutableArray = [NSMutableArray array];
for (size_t j = 0;
j < count;
j++) {
[mutableArray addObject:object];
}
}
}
}
CFTimeInterval endTime = CACurrentMediaTime();
NSLog(@"Total Runtime: %g s", endTime - startTime);
③ dispatch_benchmark
- dispatch_benchmark 函数返回给定块执行所需的平均纳秒数:
// 该方法并没有被公开声明,所以你必须要自己声明
extern uint64_t dispatch_benchmark(size_t count, void (^block)(void));
// 不要在 app 的提交代码中加入 benchmarking。dispatch_benchmark 可能会导致 app 被 App Store 拒绝
static size_t const count = 1000;
// 有多少个元素需要添加到数组uint64_t t = dispatch_benchmark(iterations, ^{
@autoreleasepool {
NSMutableArray *mutableArray = [NSMutableArray array];
for (size_t i = 0;
i < count;
i++) { // 循环体都被 @autoreleasepool 包裹,用来降低内存占用
[mutableArray addObject:object];
}
}
});
NSLog(@"[[NSMutableArray array] addObject:] Avg. Runtime: %llu ns", t);