把最近面试中遇到的问题总结下
1.使用atomic一定是线程安全的吗?
不是,atomic 的本意是指属性的存取方法是线程安全的,并不保证整个对象是线程安全的。
声明一个 NSMutableArray 的原子属性 stuff,此时 self.stuff 和 self.stuff =othersulf 都是线程安全的。但是,使用[self.stuff objectAtIndex:index]就不是线程安全的,需要用互斥锁来保证线程安全性。
2.@synthesize 和 @dynamic 分别有什么作用?
@property 有两个对应的词,一个是@synthesize,一个是@dynamic。
如果@synthesize 和@dynamic 都没写,那么默认的就是
@syntheszie var = _var;
@synthesize 的语义是如果你没有手动实现 setter 方法和 getter 方法,那么编译器会自动为你加上这两个方法。
@dynamic 告诉编译器:属性的 setter 与 getter 方法由用户自己实现,不自动生成。(当然对于 readonly 的属性只需提供 getter 即可)
假如一个属性被声明为
@dynamic var;然后你没有提供@setter 方法和@getter 方法,编译的时候没问题,但是当程序运行到 instance.var = someVar,由于缺 setter方法会导致程序崩溃;
或者当运行到 someVar = instance.var 时,由于缺 getter 方法同样会导致崩溃。
编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定
3.浅拷贝和深拷贝在不同对象下的表现
总结:copy后的都是不可变对象,mutablecopy后的都是可变对象,NSString使用copy和strong都是浅拷贝,但是使用strong关键字后可能变成可变对象,因此要用copy关键字,同理NSMutableString使用copy关键字会变成不可变对象,所以建议使用strong
1 | // 深复制 |
- 容器中的元素实现深拷贝,也就是多层容器对象,可以使用归接档实现
1 | NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:array]]; |
- 自定义对象使用copy和mutableCopy需要遵守NSCopying和NSMutableCopying协议,实现
- (id)copyWithZone:(nullable NSZone *)zone
和- (id)mutableCopyWithZone:(nullable NSZone *)zone
方法。
1 | - (id)copyWithZone:(NSZone *)zone { |
4.这个写法会出什么问题: @property (copy) NSMutableArray *array;
两个问题:
1、添加,删除,修改数组内的元素的时候,程序会因为找不到对应的方法而崩溃.因为 copy 就是复制一个不可变 NSArray 的对象;
2、使用了 atomic 属性会严重影响性能 ;
5.如何给 Category 添加属性?关联对象以什么形式进行存储?
查看的是 关联对象 的知识点。
详细的说一下 关联对象。
关联对象 以哈希表的格式,存储在一个全局的单例中。
1 | @interface NSObject (Extension) |
6.说一下 Runtime 消息解析和转发
7.说一下 Runtime 的方法缓存?存储的形式、数据结构以及查找的过程?
cache_t增量扩展的哈希表结构。哈希表内部存储的 bucket_t。
bucket_t 中存储的是 SEL 和 IMP的键值对。
如果是有序方法列表,采用二分查找
如果是无序方法列表,直接遍历查找
7.Category 可不可以添加实例对象?为什么?
每个类的内存布局在编译时期就已经确定了,运行时才加载的category无法添加属性和实例变量
8.Bounds 和Frame的区别
Bounds:一般是相对于自身来说的,是控件的内部尺寸。如果你修改了 Bounds,那么子控件的相对位置也会发生改变。
Frame :是相对于父控件来说的,是控件的外部尺寸。
9.UIViewController 的生命周期
1 | -[ViewController initWithCoder:] |
10.iOS程序的启动流程
程序完成加载
1 | [AppDelegate application:didFinishLaunchingWithOptions:] |
点击Home键
1 | [AppDelegate applicationWillResignActive:]; //程序取消激活状态 |
点击APP
1 | [AppDelegate applicationWillEnterForeground:]// 程序进入前台 |
注意
applicationWillResignActive(非活动)与applicationDidEnterBackground(后台)的区别。
applicationWillResignActive:
比如当有电话进来或短信进来或锁屏等情况下,这时应用程序挂起进入非活动状态,也就是手机界面还是显示着你当前的应用程序的窗口,只不过被别的任务强制占用了,也可能是即将进入后台状态(因为要先进入非活动状态然后进入后台状态)
applicationDidEnterBackground:
指当前窗口不是你的App,大多数程序进入这个后台会在这个状态上停留一会,时间到之后会进入挂起状态(Suspended)。如果你程序特殊处理后可以长期处于后台状态也可以运行。
Suspended : 程序在后台不能执行代码。系统会自动把程序变成这个状态而且不会发出通知。当挂起时,程序还是停留在内存中的,当系统内存低时,系统就把挂起的程序清除掉,为前台程序提供更多的内存。
11.id 和instanceType有什么区别?
相同点
instancetype 和 id 都是万能指针,指向对象。
不同点:
1.id 在编译的适合不能判断对象的真实类型,instancetype 在编译的时候可以判断对象的真实类型
2.id 可以用来定义变量,可以作为返回值类型,可以作为形参类型;instancetype 只能作为返回值类型
12.__block vs __weak
- __block:使用__block修饰的变量在block代码快中会被retain(ARC下,MRC下不会retain)
- __weak:使用__weak修饰的变量不会在block代码块中被retain
同时,在ARC下,要避免block出现循环引用 __weak typedof(self)weakSelf = self;