1、以下可变字典设置值的方式有什么区别?(新人很容易犯的错误)

1
2
3
4
5
6
7
8

NSMutableDictionary *dicT = [NSMutableDictionary dictionary];

方式一:
[dicT setObject:value forKey:@"test"];

方式二:
dicT[@"test"] = value;

(1)使用setObject:forKey:方法时,object不能为nil,否则会直接crash,抛出NSInvalidArgumentException异常

(2)使用可变字典的语法糖方式会直接调用setObject:forKeyedSubscript:方法,object为nil时,会导致可变字典中对应key的value被移除。key不能为nil,否则会直接crash,抛出NSInvalidArgumentException异常

结论:在日常开发的过程中,可变字典的赋值建议使用语法糖的方式,避免不必要的线上crash。

2、开启xcode编译时间显示(编译优化)

1
2
3
在终端执行以下命令:

defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES

测量每个构建任务所花费的时间:Xcode -> Product -> Perform Action-> Build With Timing Summary

3、Objective-C源码重写成C++

1
clang -rewrite-objc main.m

应用场景:简述Objective-C中block的实现

4、将Swift代码转换为SIL(中间码)

1
swiftc -emit-silgen -O main.swift

应用场景:查看函数派发方式

5、Objective-C项目中宏定义和常量使用方式

(1)宏定义:(过多会降低编译速度)

1
#define kScreenWidth   [UIScreen mainScreen].bounds.size.width

(2)全局静态变量(文件内可见)

1
static NSString *const kCellIdentity = @"CellIdentity";

(3)extern全局变量(所有文件可见,跨组件建议使用,多用FOUNDATION_EXTERN)

1
2
3
4
5
在.h文件中声明:
extern NSString *const kCellIdentity;

在.m文件中实现:
NSString *const kCellIdentity = @"CellIdentity";

FOUNDATION_EXTERN这个宏有用过.mm文件的人会深有体会,C++需要 extern “C”

6、LLDB常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
po:打印对象
示例:
po [[self view] recursiveDescription] 输出视图层级关系
po [self _shortMethodDescription] 输出对象所有实例方法和类方法
po [self _methodDescription] 输出对象所有实例方法和类方法(更详细)
po [self _ivarDescription] 输出对象所有变量、结构体和值

p: 打印基础数据类型

call:执行一段代码
示例:call NSLog(@"%@", @"xixue")

expr:执行表达式
示例:expr i = 101

bt:打印当前线程堆栈回溯

image:镜像相关操作
示例:
image list 列出主要的可执行文件和所有依赖的共享库
image lookup --address 0x0000000104c25550
在可执行文件或共享库中查找原始地址信息
br:断点相关操作(逆向动态调试常见)
示例:
br s -a 0x01e25008 设置断点到指定的地址
br l 显示所有断点
br del 1 删除指定断点(序号)

register:寄存器操作
示例:
register read 显示当前线程通用寄存器
register write r0 1 修改寄存器值

7、消除Xcode警告(建议在开发的过程中就把警告解决掉)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

// 单个文件代码块消除指定类型的警告,如:-Wdeprecated-declarations
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
...包裹的代码块
#pragma clang diagnostic pop


// 单个文件:忽略未使用变量警告
Build Phases -> Compile Sources:双击对应文件添加-Wno-unused-variable



// 整个工程:忽略未实现代理方法警告(可区分环境)
Build Settings -> Apple Clang - Custom Compiler Flags -> Other Warning Flags里面添加一项:-Wno-protocol

8、NS_ASSUME_NONNULL_BEGINNS_ASSUME_NONNULL_END

它表示将两个宏包裹的区域块标记为nonnull。

如果需要某个参数单独声明成可为空,只需要在参数前面加上nullable修饰即可(OC和Swift混编项目中,建议在OC代码指定nonnull或nullable)。

1
2
3
4
5
6
7
8
9
NS_ASSUME_NONNULL_BEGIN

@interface TestClass : NSObject
- (nullable TestItem *)itemWithTestName:(NSString *)name;
- (nullable NSString *)nameForTestItem:(TestItem *)item;
@property (copy) NSArray<TestItem *> *someItems;
@end

NS_ASSUME_NONNULL_END

9、iOS开发中如何查看预处理后的代码(展开宏定义或条件编译)

场景1:常见的三方开源库中有很多宏把一大串代码给包了起来,这个时候查看预处理后的代码更方便我们进行源码分析

场景2:查看宏定义替换后代码是否满足预期

1
2
3
4
5
6
7
8
方法一:
Xcode -> Product -> Perform Action -> Preprocess “xx.m”

方法二:
Xcode -> Editor -> 勾选“Assistant” -> Preprocess

方法三:
clang -E xx/xx.m

10、iOS中宏的#和##用法(OC的三方库中常见)

1
2
3
4
5
6
7
// 定义版本号
#define STR_V(v) #v //# 表示将宏参数v转换为字符串
#define STR(a) STR_V(a)
#define ADD(a,v) STR(a##.##v) //## 表示连接参数a和v
#define VER_STR(a,v) ADD(a,v)

@VER_STR(6,0) // 展开是字符串6.0

11、OC中CGFLOAT_MAX、CGFLOAT_MIN宏在Swift用什么替代?
12、NSDateFormatter中yyyy和YYYY的区别(曾经出过线上bug)
13、静态库真机和模拟器架构合并
14、查看包大小
15、CocoaPods 管理,当开启 use_frameworks!区分framework中是静态库还是动态库?
16、如何查看framework是否是静态库和动态库:
17、OC与Swift混编项目中指定OC方法在Swift中的调用函数名
18、OC中的方法屏蔽Swift的调用(针对Swift隐藏API,只在OC中可调用对应方法)
19、iOS开发中常见的__attributes__(clang attributes)使用
20、非越狱手机如何下载App Store上的IPA包
21、低版本Xcode调试高版本iOS系统(Could not locate device support files)
22、查看Mac系统架构
23、@property(class)属性的使用
24、iOS App 防止抓包,网络层配置请求不走全局设置代理(只能提高防抓包门槛,自己衡量得失)
25、Objective-C中可变参数的用法(相关知识点见文末【Argument-Macros】)
26、Swift中可变参数的用法
27、OC中复合语句的使用(常见于UI控件的初始化)
28、iOS 系统中的“设置->辅助功能”(Accessibility)造成的各种显示异常问题

参考资料

完整优秀版请移步小专栏:
iOS 开发必备tips

更多好文推荐,扫描下方的二维码,关注《iOS开发秘籍》公众号,点关注不迷路!
在这里插入图片描述

本文内容中部分来自网络,后续会持续更新完善。欢迎一起学习交流!

如需转载,请注明出处

iOS 开发必备tips