define
和const
常量有什么区别
define
在预处理阶段进行替换, const
常量在编译阶段使用;
宏不做类型检测,仅仅进行替换, const
常量有数据类型,会执行类型检测;
define
不能调试,const
常量可以调试;
define
定义的常量在替换后运行过程中会不断的占用内存, 而const
定义的常量存储在数据段只有一分copy
,效率更高
define
可以进行定义一些简单的函数, const
不可以;
atomic
一定是线程安全吗? nonatomic
一定线程不安全吗?
这个问题, 看怎么理解, atomic
修饰的属性, 保证它的setter
和getter
方法一定是线程安全, 但是这个属性的相关操作不是线程安全的;其本质是在getter
和setter
中添加@synchronized()
保证安全;
nonatomic
则一定是不安全的;
例子:一个atomic
修饰的NSMutableArray *muArr
; 则muArr
的getter
和setter
一定是线程安全的, 但是对这个数组的相关操作例如[muArr addObject]
之类的都不是线程安全的;atomic
能保证getter
时取到一个完整点值;
结构体和类的区别:
结构体 | 类 |
---|---|
只能封装属性 | 能封装属性和方法 |
分配在栈区,空间小,但是效率高;如果在结构体中赋值很多属性,会降低程序运行的效率 | 分配在堆区,空间较大但是读取效率低 |
结构体直接赋值 | 赋值的是对象的指针 |
@dynamic
和@synthesize
比较
@dynamic
关键字: 表示必须要自己实现getter
和setter
方法;
@synthesize
关键字: 表示系统会自动生成getter
和setter
方法, 如果自己实现了就会替换掉系统的;
NSCache
对NSDictionary
的优点:
-
NSCache
采用LRU
规则, 会对超出限制的数据进行清除; -
NSCache
会在系统内存很低时自动释放一些对象; -
NSCache
是线程安全的;不需要对cache
加锁; -
NSCache
的key
只是做强引用, 不需要实现NSCoping
协议;
编译和链接的过程:
像C++
, OC
都是编译类型语言,在执行时需要先通过编译器生成机器码,机器码可以直接在CPU
上执行,所以效率比较高;
像Python
, JS
都是直译式语言, 不需要经过编译的过程, 而是在执行的时候通过一个中间的解释器将代码解释为CPU
可以执行的代码;所以直译型语言的效率低一些, 但是编写效率高;
以下以OC
为例:
1.编译器前端的任务:语法分析, 语义分析, 生成中间代码, 在这个过程中会进行类型检查, 如果发现错误和警告会标注出哪行;
2.编译器后端的任务:进行机器无关的代码优化, 生成机器语言, 并进行机器相关的代码优化;
以打印一行”hello world”
为例需要四个步骤:预处理, 编译, 汇编, 链接;
去掉导航条下方的线
[self.navigationController.navigationBar setBackgroundImage:[[UIImage alloc] init] forBarMetrics:UIBarMetricsDefault]; self.navigationController.navigationBar.shadowImage = [[UIImage alloc] init];
@property
的本质:
在编译阶段由编译器自动帮我们生成ivar
成员变量,getter
方法, setter
方法
@property = ivar + getter + setter
; “属性” (property
)有两大概念:ivar
(实例变量)、getter
+setter
(存取方法)
“属性” (property
)作为 Objective-C
的一项特性,主要的作用就在于封装对象中的数据。
Objective-C
对象通常会把其所需要的数据保存为各种实例变量。
实例变量一般通过“存取方法”(access method
)来访问。
其中,“获取方法” (getter
)用于读取变量值,而“设置方法” (setter
)用于写入变量值。
NSDictionary的实现原理?
通过方法- (void)setObject:(id)anObject forKey:(id)aKey;
进行存储, 底层是基于哈希表(又称为散列表)的key-value
映射存储; 本质上是一个数组在存储, 每一个元素存储着键值对的信息;
hash的存储过程
- 通过
key
进行hash
运算出哈希值h;- 假设散列表长度为n, 则这个键值对应该存储的位置是h%n
- 如果这个位置已经被存储了, 则用开放寻址法或者拉链法进行解决冲突;
如果对散列表的原理完全不懂的, 建议看下入门课程陆军工程大学的公开课第四周
哈希表的负载因子
它被用来衡量哈希表的满/空程度;
负载因子=键值对总数/散列表长度; 当值大于某个值后哈希表再次扩展空间, 一般是双倍空间, 因此即使原先的键值对的hash不会变由于散列表的长度变化, 也会导致其所在链表存储位置发生变化, 这个过程成为重哈希
;
如果用拉链法(上文中所说存储时所用的数组, 数组元素中存储链表, 将取模冲突的键值对依次排列在链表中)解决冲突时; 哈希表扩容后,其实并不能有效提高查找效率;因为每个键值对仍然存储在链表中, 链表的长度也没变化, 只是位置改变了;
各个APP之间有什么通信的方式?
- URLScheme
- KeyChain
- UIPasteboard
- 隔空投送
- UIActivityViewController分享