iOS 面试题累计 (三)
PS 初衷: 记录面试题不仅仅是为了针对于我们的面试,而是在有时候可以提醒在我们用某些东东的时候会自主的想这是为什么,从而避免一些 BUG 产生。
以下是从 CocoaChina 招人的事结了,放出面试题,分享一下 看到的面试题,个人不知道学习啥的时候看看,尝试解答。
- 1、下面代码在按钮点击后,在
ARC
下会发生什么,MRC
下呢?为什么 ?
@property(nonatomic, assign) void(^block)();
- (void)viewDidLoad {
[super viewDidLoad];
int value = 10;
void(^blockC)() = ^{
NSLog(@"just a block === %d", value);
};
NSLog(@"%@", blockC);
_block = blockC;
}
- (IBAction)action:(id)sender {
NSLog(@"%@", _block);
}
- 2、在
ARC
环境下这段代码为什么不会崩溃?
@property(nonatomic, weak) void(^block)();
- (void)viewDidLoad {
[super viewDidLoad];
void(^ __weak blockA)() = ^{
NSLog(@"just a block");
};
_block = blockA;
}
- (IBAction)action:(id)sender {
_block();
}
- 3、下面是一个员工表,
manager_id
表示对应的boss
的ID
。通过一个SQL
找出下表中比boss
工资还高的人。。。。
id name salary manager_id
1 Noah 70000 NULL
2 西兰花 80000 1
3 椰菜花 80000 NULL
4 没钱花 80000 3
输出格式为:
name
西兰花
- 4、写一个函数,输入一个数如 38,拆分 3 + 8 = 11,1 + 1 = 2,最后 2 无法拆分就返回(伪代码也行)
- 5、通过
runtime
添加的“关联对象”和类的实例变量有什么区别?使用时要注意什么? - 6、用一个生活中的例子来说说同步和异步。
- 7、线程间通信在 OC 中有几种方式?分别是?常用那种?
- 8、使用快速枚举迭代一个可变数组时需要注意什么问题?怎么避免?
- 9、什么是面向对象的多态性?
- 10、
UIViewController
的presentViewController
和UINavigationController
的pushViewController
方法分别多用于什么交互场景? - 11、
NSOperation
和GCD
的区别是什么?前者多用于什么场景? - 12、面向接口编程指的是什么?为什么说面向实现编程是一种错误的编程方式?
- 13、在iOS开发中遇到那些类族
(Class Cluster)
?如NSNumber
这种。为什么需要这种设计方式? - 14、
javascript
的原型链和 OC 的继承有什么区别? - 15、
Hybrid
开发的优势在哪里?目前有那些框架可以实现Hybrid
开发? - 16、使用了
ARC
是不是就等于没有内存泄漏了?如果不是的话请举例。 - 17、下面代码中为什么可以直接用
self
?
[UIView animateWithDuration:1 animations:^{
self.view.backgroundColor = [UIColor yellowColor];
}];
下面这段代码可以用 self
吗?为什么?
- (void)doSomething {
[BlockClass doSomethingUseBlock:^{
NSLog(@"%@", self);
}];
}
- 18、进程的内存布局是怎样的?
- 19、在
GCD
中,那几种场景会出现死锁的现象?怎么避免? - 20、怎么用
NSOperation
封装一个异步请求?这个Operation
需要放到NSOperationQueue
里调度的。 - 21、
CoreFoundation
和Foundation
有什么区别? - 22、怎么判断两个链表是双交的?
- 23、怎么判断一个链表存在环?
- 24、当一个
View
的bounds
原点不为0的时候会出现什么情况? - 25、OC的数组是怎么实现的?和C的数组区别在?简单说一下即可。
- 26、
weak
和assign
有什么区别? - 27、
setNeedLayout
的作用是什么? - 28、什么时候用
NS_OPTIONS
,NS_ENUM
?
对以上部分问题进行解答
1-2 、 对 Block 及其关键字的理解
1、在 ARC 下直接打印处两个不一样的 block, _block 还是其本身值。
在 MAC 下直接 崩溃,注意此处是 assgin 的关键字,此时 _block 相当于是已经被释放了。
2、此处直接打印 “just a block”,在ARC下,本类内该 block 是没有被释放的。
4、考察我们的函数思维
- (void)testGetValueNumber:(NSInteger)testNumber {
while (testNumber >= 10) {
testNumber = [self getTotalValueNumberWithTestNumber:testNumber];
}
}
- (NSInteger)getTotalValueNumberWithTestNumber:(NSInteger)number {
NSString *numberStr = [NSString stringWithFormat:@"%ld",number];
// 如果是个位数则直接返回
if (numberStr.length < 2) {
return number;
}
NSInteger allValue = 0;
// 获取每一项的数
for (NSInteger i = 0; i < numberStr.length; i++) {
NSInteger locationNumber = [[numberStr substringWithRange:NSMakeRange(i, 1)] integerValue];
allValue += locationNumber;
}
return allValue;
}
5、通过 runtime 添加的“关联对象”和类的实例变量有什么区别, 考察 Associated Objects 的理解。
这个问题其实,按我的理解可以划分为两个问题:
- 关联对象 和 常规 Property 有什么区别 ?
- Property 和 实例变量有什么区别的?
先理解 Associated Objects 实现原理,首先可以再次回顾 雷纯锋 所画的图:
Associated Objects 的理解PS : 图源自: Objective-C Associated Objects 的实现原理
简而言之的说,访问的方式不一样的,用的场景不一样。
- 关联对象:是存储在单独的哈希表中,被关联对象本身的存储并没有直接的关系; 一般我们常用在 为现有的类添加属性时。
- Property: 直接通过访问属性本质上通过消息机制,一般设置值时用它。
- 实例变量:是在运行期查找成员的偏移量,这样就计算出了成员相应位置的内存地址,从而直接访问其内存,速度更快;一般简单取值时,以及 init dealloc 中尽量用 实例变量。
7、线程间的通信
此处看经典的两个例子:
- 异步加载图片,主线程显示图片的例子
dispatch_async(dispatch_get_global_queue(0, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
//回到主线程更新
});
});
- 并行时,结束时的一个标志, dispatch_group_notify 最后时执行
// 创建 dispatch_group
dispatch_group_t group = dispatch_group_create();
// 添加到 group 中
dispatch_group_async(group, queue, ^{
NSLog(@"block 1");
});
dispatch_group_async(group, queue, ^{
NSLog(@"block 2");
});
dispatch_group_async(group, queue, ^{
NSLog(@"block 3");
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"end");
});
NSLog(@"go");
8、使用快速枚举迭代一个可变数组时需要注意什么问题?怎么避免?
不要在可变数组中直接删除,通过 倒叙遍历的方式避免。
9、什么是面向对象的多态性?
直接的说:对于不同对象响应同一个方法时做出的不同反应。
常见的场景:不同的子类共用父类的方法,或者这么说他们各自以自己的方式响应相同的消息 。
明显的好处: 如果父类有的方法,那么子类不能调用,那么每次都得子类自己再写一个方法,就显的有点麻烦啦。
13、在iOS开发中遇到那些类族(Class Cluster) ?如NSNumber这种。为什么需要这种设计方式?
- 类族: 其实应该说 类簇,是一种设计模式,它管理了一组隐藏在公共接口下的私有类。
NSNumber *testChar = [NSNumber numberWithChar:’t’];
NSNumber *testInt = [NSNumber numberWithInt:10];
NSNumber *testFloat = [NSNumber numberWithFloat:20.0];
NSNumber *testDouble = [NSNumber numberWithDouble:1.0];
- 好处:可以隐藏抽象基类背后的复杂细节,使用者只需调用基类简单的方法就可以返回不同的子类实例。
16、使用了ARC 是不是就等于没有内存泄漏了?如果不是的话请举例。
- 循环引用的情况: Delegate, Block, NSTimer, 这里可展开的太多了,也是我们平常接触比较多的。
- CoreFundation/CoreGraphics 相关函数
CGBitmapContextCreate(, , , , , , )
CGImageRelease(CGImageRef image)
这两者都是配套使用的哦,这个可能平时直接使用的不多的。
18、进程的内存布局是怎样的?
- 进程: 一个正在运行的程序可以看做一个进程。
- 内存布局:代码段、全局/静态存储区、常量区、自由存储区、堆、栈。
这一块可以再次回顾内存相关的东东: 对于内存的几点笔记
19、在 GCD 中,那几种场景会出现死锁的现象?怎么避免?
这个问题看到一篇不错的文章总结,直接巧这里: 说说GCD中的死锁。
文章中举例说明了,我们可能遇到的三种场景:
- 主线程调用主线程
- 同步串行队列嵌套自己
- 信号量阻塞主线程
话说自己真的好像基本没有遇到过哎,😓😓😓
20、怎么用 NSOperation 封装一个异步请求?这个Operation 需要放到NSOperationQueue 里调度的?
-
真心说平时 NSOperation 用的也不多的,但作为 GCD 的更高层封装,有着直接取消和依赖的特征,确实是有其优势的。
-
我认为此处考察的主要是 NSOperation 的异步执行,对其子类 NSInvocationOperation 和 NSBlockOperation 用法的考察。
- NSInvocationOperation 默认直接是执行同步的,需要添加到 NSOperationQueue 中去才会去执行异步的。
- 当然也可以直接用 NSBlockOperation 添加多任务来进行异步任务的。
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(request) object:nil];
[operationQueue addOperation:operation];
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"Main :%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^() {
NSLog(@"Excution:%@", [NSThread currentThread]);
}];
[operation start];
- 需要调度,可以设置最大操作数目的。
// 最大并发数为4
[operationQueue setMaxConcurrentOperationCount:4];
21、CoreFoundation 和 Foundation 有什么区别?
#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>
- Core Foundation是一个通用的C框架,而Foundation是一个通用的Objective-C框架。
- 两者都提供集合类,运行循环等,并且许多 Foundation 类是围绕 CF 类的再次包装。
- CF大多是开源的,而 Foundation 是封闭源。
注意下,Core Foundation 中 __bridge 关键字, 很强大的。
25、OC的数组是怎么实现的?和C的数组区别在?简单说一下即可。
这个问题我是懵逼的,然后找到了一篇文章 NSMutableArray原理揭露, 才略微了解下的,这篇文章可以拜读下,哈哈。
27、setNeedLayout 的作用是什么?
简单的说,调用 setNeedLayout 之后,后续会调用 layoutSubviews, 然后陆续调整 当前视图及子视图的布局。
28、什么时候用NS_OPTIONS,NS_ENUM?
- 1、NS_ENUM 枚举项的值为 NSInteger,NS_OPTIONS 枚举项的值为 NSUInteger;
- 2、NS_ENUM 定义通用枚举,NS_OPTIONS 定义位移枚举;
- 3、NS_ENUM 是每一个值自动被赋予从0开始依次累加1的值,而 NS_OPTIONS 是手动被赋予一个带有一个bit偏移量的值:类似1 << 0、 1 << 1、 1 << 2等。
此处参考: 详解枚举NS_OPTIONS与NS_ENUM的区别与格式, 说的很详细。直接用时感觉就是第二个的区别,也就是 NS_OPTIONS 可以同时用多个枚举值,而NS_ENUM 只能用一个枚举值。
Finally: 自我吐槽
发现自己从事 iOS 工作也算有一段时间啦, 发现现在和去年好像是差不多的水准,除了业务能力熟悉了下,技术水准貌似木有提高哎,涉及到稍微底层还是懵逼哦,😓😓😓,只能自我安慰其他非技术方面有些进步啦。。。