学计算机的那个

不是我觉到、悟到,你给不了我,给了也拿不住;只有我觉到、悟到,才有可能做到,能做到的才是我的.

0%

iOS面试题汇总

把最近面试中遇到的问题总结下

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
2
3
4
5
6
7
8
9
10
// 深复制
Person *xiaoMing = [[Person alloc] init];
NSMutableString * name = [[NSMutableString alloc] initWithString:@"xiaoming"];
//name.string = @"xiaoming";
xiaoMing.name = name;
NSLog(@"%@", xiaoMing.name);
[name appendString:@"hah"];

//此时名字这个属性被修改了
NSLog(@"%@", xiaoMing.name);
  1. 容器中的元素实现深拷贝,也就是多层容器对象,可以使用归接档实现
1
NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:array]];
  1. 自定义对象使用copy和mutableCopy需要遵守NSCopying和NSMutableCopying协议,实现
    - (id)copyWithZone:(nullable NSZone *)zone- (id)mutableCopyWithZone:(nullable NSZone *)zone方法。
1
2
3
4
5
6
7
8
9
- (id)copyWithZone:(NSZone *)zone {

Person *person = [[Person allocWithZone:zone] init];

person.name = self.name;
person.age = self.age;

return person;
}

4.这个写法会出什么问题: @property (copy) NSMutableArray *array;

两个问题:

1、添加,删除,修改数组内的元素的时候,程序会因为找不到对应的方法而崩溃.因为 copy 就是复制一个不可变 NSArray 的对象;

2、使用了 atomic 属性会严重影响性能 ;

5.如何给 Category 添加属性?关联对象以什么形式进行存储?

查看的是 关联对象 的知识点。

详细的说一下 关联对象。

关联对象 以哈希表的格式,存储在一个全局的单例中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@interface NSObject (Extension)

@property (nonatomic,copy ) NSString *name;

@end


@implementation NSObject (Extension)

- (void)setName:(NSString *)name {

objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}


- (NSString *)name {

return objc_getAssociatedObject(self,@selector(name));
}

@end

6.说一下 Runtime 消息解析和转发

7.说一下 Runtime 的方法缓存?存储的形式、数据结构以及查找的过程?

cache_t增量扩展的哈希表结构。哈希表内部存储的 bucket_t。

bucket_t 中存储的是 SEL 和 IMP的键值对。

如果是有序方法列表,采用二分查找

如果是无序方法列表,直接遍历查找

7.Category 可不可以添加实例对象?为什么?

每个类的内存布局在编译时期就已经确定了,运行时才加载的category无法添加属性和实例变量

8.Bounds 和Frame的区别

Bounds:一般是相对于自身来说的,是控件的内部尺寸。如果你修改了 Bounds,那么子控件的相对位置也会发生改变。

Frame :是相对于父控件来说的,是控件的外部尺寸。

9.UIViewController 的生命周期

1
2
3
4
5
6
7
8
9
10
11
12
-[ViewController initWithCoder:]
-[ViewController awakeFromNib]
-[ViewController loadView]
-[ViewController viewDidLoad]
-[ViewController viewWillAppear:]
-[ViewController viewWillLayoutSubviews]
-[ViewController viewDidLayoutSubviews]
-[ViewController viewDidAppear:]
-[ViewController viewWillDisappear:]
-[ViewController viewDidDisappear:]
-[ViewController dealloc]
-[ViewController didReceiveMemoryWarning]

10.iOS程序的启动流程

程序完成加载

1
[AppDelegate application:didFinishLaunchingWithOptions:]

点击Home键

1
2
3
[AppDelegate applicationWillResignActive:]; //程序取消激活状态

[AppDelegate applicationDidEnterBackground:];// 程序进入后台

点击APP

1
2
3
[AppDelegate applicationWillEnterForeground:]// 程序进入前台

[AppDelegate applicationDidBecomeActive:];// 程序被激活

注意

applicationWillResignActive(非活动)与applicationDidEnterBackground(后台)的区别。

applicationWillResignActive:
比如当有电话进来或短信进来或锁屏等情况下,这时应用程序挂起进入非活动状态,也就是手机界面还是显示着你当前的应用程序的窗口,只不过被别的任务强制占用了,也可能是即将进入后台状态(因为要先进入非活动状态然后进入后台状态)

applicationDidEnterBackground:
指当前窗口不是你的App,大多数程序进入这个后台会在这个状态上停留一会,时间到之后会进入挂起状态(Suspended)。如果你程序特殊处理后可以长期处于后台状态也可以运行。

Suspended : 程序在后台不能执行代码。系统会自动把程序变成这个状态而且不会发出通知。当挂起时,程序还是停留在内存中的,当系统内存低时,系统就把挂起的程序清除掉,为前台程序提供更多的内存。

点我

11.id 和instanceType有什么区别?

相同点

instancetype 和 id 都是万能指针,指向对象。

不同点:

1.id 在编译的适合不能判断对象的真实类型,instancetype 在编译的时候可以判断对象的真实类型
2.id 可以用来定义变量,可以作为返回值类型,可以作为形参类型;instancetype 只能作为返回值类型

12.__block vs __weak

  1. __block:使用__block修饰的变量在block代码快中会被retain(ARC下,MRC下不会retain)
  2. __weak:使用__weak修饰的变量不会在block代码块中被retain
    同时,在ARC下,要避免block出现循环引用 __weak typedof(self)weakSelf = self;