iOS碎碎日常一题
1.iOS笔试题
- 介绍下内存的几大区域?
- 写一个”标准"宏MIN,这个宏输入两个参数并返回较小的一个。当你这样用时least = MIN(*p++, b);时会发生什么?
- 什么情况使用 weak 关键字,相比 assign 有什么不同?
- 一个objc对象的isa的指针指向什么?有什么作用?
- ViewController生命周期
- 如果页面A跳转到页面B,A的 viewDidDisappear 方法和B的 viewDidAppear 方法哪个先调用?
- 下面的代码输出什么?
@implementation Son : Father
- (id)init {
if (self = [super init]) {
NSLog(@"%@", NSStringFromClass([self class]));
NSLog(@"%@", NSStringFromClass([super class]));
}
return self;
}
@end
8.以下代码运行结果如何?
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2");
});
NSLog(@"3");
}
9.单例的优点和弊端?
10.runloop 和线程有什么关系?
11.http和scoket通信的区别。
2.iOS笔试题答案
1. 介绍下内存的几大区域?
- 代码区:存放函数二进制代码
- 数据区:系统运行时申请内存并初始化,系统退出时由系统释放。存放全局变量、静态变量、常量
- 堆区:通过malloc等函数或new等操作符动态申请得到,需程序员手动申请和释放
- 栈区:函数模块内申请,函数结束时由系统自动释放。存放局部变量、函数参数
2. 写一个”标准"宏MIN
,这个宏输入两个参数并返回较小的一个。当你这样用时least = MIN(*p++, b);
时会发生什么?
答案:
#define MIN(A,B) ((A) <= (B) ? (A) : (B))
((*p++) <= (b) ? (*p++) : (*p++))
//这个表达式会产生副作用,指针p会做三次++自增操作。
3. 什么情况使用 weak 关键字,相比 assign 有什么不同?
-
什么情况使用 weak 关键字?
- 在 ARC 中,在有可能出现循环引用的时候,往往要通过让其中一端使用 weak 来解决,比如: delegate 代理属性
- 自身已经对它进行一次强引用,没有必要再强引用一次,此时也会使用 weak,自定义 IBOutlet 控件属性一般也使用 weak;当然,也可以使用strong。在下文也有论述:《IBOutlet连出来的视图属性为什么可以被设置成weak?》
-
不同点:
- weak 此特质表明该属性定义了一种“非拥有关系” (nonowning relationship)。为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。此特质同assign类似, 然而在属性所指的对象遭到摧毁时,属性值也会清空(nil out)。 而 assign 的“设置方法”只会执行针对“纯量类型” (scalar type,例如 CGFloat 或 NSlnteger 等)的简单赋值操作。
- assign 可以用非 OC 对象,而 weak 必须用于 OC 对象
4. 一个objc对象的isa的指针指向什么?有什么作用?
答:指向他的类对象,从而可以找到对象上的方法。
5. ViewController生命周期
按照执行顺序排列:
1.initWithCoder:通过nib文件初始化时触发。
2.awakeFromNib:nib文件被加载的时候,会发生一个awakeFromNib的消息到nib文件中的每个对象。
3.loadView:开始加载视图控制器自带的view。
4.viewDidLoad:视图控制器的view被加载完成。
5.viewWillAppear:视图控制器的view将要显示在window上。
6.updateViewConstraints:视图控制器的view开始更新AutoLayout约束。
7.viewWillLayoutSubviews:视图控制器的view将要更新内容视图的位置。
8.viewDidLayoutSubviews:视图控制器的view已经更新视图的位置。
9.viewDidAppear:视图控制器的view已经展示到window上。
10.viewWillDisappear:视图控制器的view将要从window上消失。
11.viewDidDisappear:视图控制器的view已经从window上消失。
6. 如果页面A跳转到页面B,A的 viewDidDisappear
方法和B的 viewDidAppear
方法哪个先调用?
1.A -->viewWillDisappear
2.B-->viewWillAppear
3.A-->viewDidDisappear
4.B-->viewDidAppear
7. 下面的代码输出什么?
@implementation Son : Father
- (id)init {
if (self = [super init]) {
NSLog(@"%@", NSStringFromClass([self class])); // Son
NSLog(@"%@", NSStringFromClass([super class])); // Son
}
return self;
}
@end
答案:Son Son
解析:
self 是类的隐藏参数,指向当前调用方法的这个类的实例。<br />
super是一个Magic Keyword,它本质是一个编译器标示符,和self是指向的同一个消息接收者。
不同的是:super会告诉编译器,调用class这个方法时,要去父类的方法,而不是本类里的。
上面的例子不管调用[self class]还是[super class],接受消息的对象都是当前 Son *obj 这个对象。
8. 以下代码运行结果如何?
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2");
});
NSLog(@"3");
}
// 只输出:1。(主线程死锁)
9. 单例的优点和弊端?
-
优点:
- 一个类只被实例化一次,提供了对唯一实例的受控访问。
- 节省系统资源
- 允许可变数目的实例。
-
缺点:
- 一个类只有一个对象,可能造成责任过重,在一定程度上违背了
单一职责原则
。 - 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
- 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。
- 一个类只有一个对象,可能造成责任过重,在一定程度上违背了
10. runloop 和线程有什么关系?
runloop与线程是一一对应的,一个runloop对应一个核心的线程,为什么说是核心的,是因为runloop是可以嵌套的,但是核心的只能有一个,他们的关系保存在一个全局的字典里。
runloop是来管理线程的,当线程的runloop被开启后,线程会在执行完任务后进入休眠状态,有了任务就会被唤醒去执行任务。
runloop在第一次获取时被创建,在线程结束时被销毁。
对于主线程来说,runloop在程序一启动就默认创建好了。
对于子线程来说,runloop是懒加载的,只有当我们使用的时候才会创建,所以在子线程用定时器要注意:确保子线程的runloop被创建,不然定时器不会回调。
11. http和scoket通信的区别。
答:
-
http是客户端用http协议进行请求,发送请求时候需要封装http请求头,并绑定请求的数据,服务器一般有web服务器配合(当然也非绝对)。 http请求方式为客户端主动发起请求,服务器才能给响应,一次请求完毕后则断开连接,以节省资源。服务器不能主动给客户端响应(除非采取http长连接 技术)。
-
scoket是客户端跟服务器直接使用socket“套接字”进行连接,并没有规定连接后断开,所以客户端和服务器可以保持连接通道,双方都可以主动发送数据。一般在游戏开发或股票开发这种要求即时性很强并且保持发送数据量比较大的场合使用。主要使用类是CFSocketRef。