iOS面试备战BATios面试

二、iOS经典面试题(一)

2017-07-12  本文已影响181人  DeepChafferer

我为什么要写这篇文章

一、简述iOS中UIViewController的生命周期

先来看一张那个图

生命周期
一般一个UIViewController从被创建到显示在屏幕上会经历如下过程
1、alloc 创建对象并在内存中开辟一块空间
2、init(initWithNibName) 初始化控制器对象并且初始化数据
3、loadView 如果view不存在则会调用此方法,在控制器没有被销毁前此方法可能会执行多次
4、viewDidLoad 在loadView方法执行完成view被创建成功后执行此方法,一般这个方法只执行一次
5、 viewWillAppare 视图将要显示在屏幕上的时候调用
6、 viewWillLayoutSubviews 视图将要布局子控件时候调用
7、 viewDidLayoutSubviews 视图刚刚布局好子控件时候调用
8、 viewDidAppear 视图加载到窗口时调用
9、 viewWillDisappear 视图即将消失、被覆盖或是隐藏时调用
10、viewDidDisappear 视图已经消失、被覆盖或是隐藏时调用

二、什么是响应者链,它是怎么工作的

首先了解下响应者对象这个概念:响应者对象指的是有响应和处理事件能力的对象。iOS中所有响应者对象都继承于UIResponder


UIResponder

所谓响应者链就是讲一系列响应者链式地串联起来,形成一条响应链,当某一对象不能处理事件时就将事件传递给下一个响应者对象。我们来看一张图

响应者链

拓展:

三、什么是序列化,怎么将一个包含自定义对象的数组序列化到磁盘

所谓序列化就是将对象状态转换为可保持或者可传输格式的过程。在iOS中实现序列化只要实现NSCoding协议即可
我们先写下如下代码

#import "ViewController.h"
#import "Person.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    Person *person = [[Person alloc]init];
    NSArray *array = @[person];
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
    NSLog(@"%@---%@",array,data);
}

@end

这时我们command + R运行下你会看见如下错误:

error

这是因为我们没有实现NSCoding协议方法,于是我们回到Person写如下代码:

#import "Person.h"

@interface Person()<NSCoding>

@end

@implementation Person

//序列化
- (instancetype)initWithCoder:(NSCoder *)aDecoder{
    if (self = [super init]){
        self = [aDecoder decodeObjectForKey:@"person"];
    }
    return self;
}

//反序列化
- (void)encodeWithCoder:(NSCoder *)aCoder{
    [aCoder encodeObject:self forKey:@"person"];
}

@end

ok,现在运行下

success

总结:

四、你了解沙盒吗,沙盒目录结构是怎样的,什么是App Bundle,里面都有些什么

iOS沙盒可以简单地理解成是一个目录,而且我们修改这个目录的时候对操作系统不会造成任何的损失,一个iOS APP的操作都是在自己的沙盒中进行的。我们先来看一张图


iOS沙盒

iOS沙盒结构:

五、在UIKit中,frame与bounds的区别是什么

六、父类实现深拷贝时,子类如何实现深度拷贝。父类没有实现深拷贝时,子类如何实现深度拷贝

#import "ViewController.h"
#import "Person.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    Person *person = [[Person alloc]init];
    Person *aPerson = [person copy];
    NSLog(@"%p---%p",person,aPerson);
}

@end

运行后发现崩了,错误信息是

error

意思是我们没有实现NSCopying协议中copyWithZone的方法,回到Person文件

#import "Person.h"

@interface Person()<

NSCopying>

@end

@implementation Person

- (instancetype)copyWithZone:(NSZone *)zone{
    return [[Person allocWithZone:zone]init];
}

@end

运行,ok成功了

success

拓展:

NSString *str = @"string";
NSString *cpStr = [str copy];
NSMutableString *mucpStr = [str mutableCopy];
NSLog(@"str:%p-%@-cpStr:%p-%@-mucpStr%p-%@",str,str,cpStr,cpStr,mucpStr,mucpStr);

我们来看下打印输出

str:0x10b7ba138-string-cpStr:0x10b7ba138-string-mucpStr0x608000250cb0-string

从打印的信息可以看出当调用copy复制时是浅拷贝,调用mutableCopy复制时是深拷贝,若拷贝的对象是可变对象时均为深拷贝,这里没有列出

七、KVO,NSNotification,delegate及block区别

首先什么是KVO:
所谓KVO即Key-Value-Observing,是cocoa框架实现的观察者模式,一般会和KVC一块使用,通过KVO可以监测某一个值的变化,比如一个UIView高度的变化,是一对多的关系,一个值的变化会通知所有的观察者

[self.tableView addObserver: self forKeyPath:@"contentOffSet" options: NSKeyValueObservingOptionNew context: nil];
 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    //做一些处理的操作
}

以上就给一个tableView添加了一个控制器作为它的观察者,当它有y轴上的偏移时,就会调用observeValueForKeyPath方法,更多关于[KVO]
(http://www.jianshu.com/p/742b4b248da9)
NSNotification:
NSNotification是通知,也是一对多的使用场景。在某些情况下,KVO和NSNotification是一样的,都是状态变化之后告知对方。NSNotification的特点,就是需要被观察者先主动发出通知,然后观察者注册监听后再来进行响应,比KVO多了发送通知的一步,但是其优点是监听不局限于属性的变化,还可以对多种多样的状态变化进行监听,监听范围广,使用也更灵活。

//发送通知
[[NSNotificationCenter defaultCenter]postNotificationName:@"notification" object:nil userInfo:@{@"key":@"value"}];
//添加通知
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(noted) name:@"notifiction" object:nil];
//注销通知
[[NSNotificationCenter defaultCenter]removeObserver:self name:@"notification" object:nil];

delegate:
delegate 是代理,就是我不想做的事情交给别人做。比如狗需要吃饭,就通过delegate通知主人,主人就会给他做饭、盛饭、倒水,这些操作,这些狗都不需要关心,只需要调用delegate(代理人)就可以了,由其他类完成所需要的操作。所以delegate是一对一关系。
block:
block是delegate的另一种形式,是函数式编程的一种形式。使用场景跟delegate一样,相比delegate更灵活,而且代理的实现更直观。
拓展:

八、 怎么将一个函数放到主线程中执行

//方法一:GCD方法,通过向主线程队列发送一个block块,使block里的方法可以在主线程中执行。
dispatch_async(dispatch_get_main_queue(), ^{
  //需要执行的方法
});

//方法二:NSOperationQueue
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue]; //主队列
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
  //需要执行的方法
}];
[mainQueue addOperation:operation];

//方法三:NSThread
[self performSelector:@selector(method) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES models:nil];
[self performSelectorOnMainThread:@selector(method) withObject:nil waitUntilDone:YES];
[[NSThread mainThread] performSelector:@selector(method) withObject:nil];

//方法四:Runloop
[[NSRunLoop mainRunLoop] performSelector:@selector(method) withObject:nil];

九、当定时器repeats属性设为YES时,能在dealloc中调用invalid吗,为什么

不能在dealloc中调用, 因为一旦设置repeats为yes,计时器会强持有self,导致dealloc永远不会被调用,这个类就永远无法被释放。比如可以在viewDidDisappear中调用,这样当类需要被回收的时候就可以正常执行dealloc方法了。
拓展:

十、线程是什么?进程又是什么?区别和联系

这是问的操作系统相关的了,是基础

==============================================================
未完待续。。。
先总结十条吧,希望对您面试有帮助,如有什么错误欢迎指正

上一篇 下一篇

猜你喜欢

热点阅读