iOS面试集锦

  1. 写出中序遍历二叉树的算法(不限编程语言,已知 TreeRoot 为二叉树的根)
  2. 快速排序,归并排序的时间复杂度分别是什么?
  3. UITableViewCell 可重用机制是什么?有什么要注意的地方?
  4. OC 中的 @property 和 @synthesize 有什么用?
  5. OC有没有重载(overload)和重写(overwrite)?有的话请举个例子。
  6. 列举出 iOS 开发中三种最常出现的循环引用的场景。
  7. MVC 模式具体指什么?iOS现在流行的 MVVM 是什么?
  8. iOS 中设计金钱计算和比较时,用数值应该用哪个类型来处理?
  9. iOS 上触摸事件的视图检测和事件传递过程是怎样的?
  10. 写一个折半查找或者快速排序

  1. 对内存管理的理解。
  2. 类别的作用
  3. 点击屏幕上的按钮,系统做了什么?

  1. idinstancetype 的区别?
  2. 有方法查看当前系统内存使用的情况吗?
  3. 为什么 NotificationCenter 要 removeObserver? 如何实现自动 remove?
  4. iOS的沙盒目录结构是怎样的? App Bundle 里面都有什么?
  5. 简单描述一下客户端的缓存机制?

  1. 按钮或者 View 在进行 frame 动画的时候,为什么点击 frame 动画的重点位置才能触发事件?如何在动画过程中响应事件?

#####1.写出中序遍历二叉树的算法(不限编程语言,已知 TreeRoot 为二叉树的根)。

最近在学 Python 所以整理了一个 Python 版的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# -- coding: UTF-8 --
# @Date : 2017-02-21
# @Author : CepheusSun
# @Version : python 2.7
class Tree(object):
def __init__(self, data, left, right):
self.data = data
self.left = left
self.right = right
def in_visit(tree):
"""递归中序遍历"""
if tree:
in_visit(tree.left)
print (tree.data)
in_visit(tree.right)
def in_stack(tree):
"""堆栈中序遍历"""
if tree:
my_stack = []
node = tree
while node or my_stack:
while node:
my_stack.append(node)
node = node.left
node = my_stack.pop()
print(node.data)
node = node.right
print my_stack2.pop().data
def main():
node1 = Tree(1, 0, 0)
node2 = Tree(2, 0, 0)
node3 = Tree(3, node1, node2)
node4 = Tree(4, 0, 0)
node5 = Tree(5, node4, node3)
print("the post_visit is ...")
post_visit(node5)
post_stack(node5)
print("the pre_visit is ...")
pre_visit(node5)
pre_stack(node5)
print("the in_visit is ...")
in_visit(node5)
in_stack(node5)
if __name__ == '__main__':
main()
2.快速排序,归并排序的时间复杂度分别是什么?
  • 归并排序:稳定,时间复杂度 O(nlog n)
  • 快速排序:不稳定,时间复杂度 最理想 O(nlogn) 最差时间O(n^2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# -- coding: UTF-8 --
# @Date : 2017-02-21
# @Author : CepheusSun
# @Version : python 2.7
def quick_sort(array, first_index, last_index):
"""快速排序"""
if first_index < last_index:
div_index = partition(array, first_index, last_index)
quick_sort(array, first_index, div_index)
quick_sort(array, div_index + 1, last_index)
else:
return
def partition(array, first_index, last_index):
i = first_index - 1
for j in range(first_index, last_index):
if array[j] <= array[last_index]:
i += 1
array[i], array[j] = array[j], array[i]
array[i + 1], array[last_index] = array[last_index], array[i + 1]
return i
def merge(left, right):
i, j = 0, 0
res = []
while i < len(left) and j < len(right):
if left[i] <= right[j]:
res.append(left[i])
i += 1
else:
res.append(right[j])
j += 1
res += left[i:]
res += right[j:]
return res
def merge_sort(array):
"""并归排序"""
if len(array) <= 1:
return array
num = len(array) / 2
left = merge_sort(array[:num])
right = merge_sort(array[num:])
return merge(left, right)
def main():
array = [1, 4, 7, 5, 4, 9, 5, 8, 76, 5, 567, 54, 6, 54, 5, 5, 4, 0]
print("initial array : \n", array)
print("merge sort result: \n", merge_sort(array))
quick_sort(array, 0, len(array) - 1)
print("result array :\n", array)
if __name__ == '__main__':
main()
```
##### 3.UITableViewCell 可重用机制是什么?有什么要注意的地方?
UITableView 通过重用单元格来达到节省内存的目的:通过为每个单元格指定一个重用标识符,即指定来单元格的种类,以及当单元格滚出屏幕时,允许恢复单元格以便重用。对于不同种类的单元格使用不同的ID,对于简单的表格,一个标识符就够了。
需要注意的地方:
取出来的cell是有可能已经捆绑过数据或者加过子视图的,如果有必要,要清除需要用与显示的数据和remove掉add过的子视图。不然会造成错乱的情况
##### 4.OC 中的 @property 和 @synthesize 有什么用?
答:
iOS2.0 Apple引入 `@property` `@synthesize` 概念,两者组合使用可以自动生成 `seter` `geter`方法,iOS4.0以后只需要 `@property` 即可实现 自动生成 `seter` `geter`方法。

//setter

  • (void)setObjStr:(NSString *)objStr {
    if (_ objStr != objStr) {
    [_objStr release];
     _objStr = [objStr copy];
    
    }
    }
    //getter
  • (NSString *)objStr {
    return _objStr;
    }
    1
    以上代码等价于

//iOS2.0-iOS4.0
@interface Obj : NSObject
@property (nonatomic, copy) NSString *objStr;
@end

@implementation Object
@synthesize objStr = _ objStr;
@end

1
iOS4.0及以后

@interface Obj : NSObject
@property (nonatomic, copy) NSString *objStr;
@end

1
2
3
4
5
6
7
8
9
10
11
##### 5.OC有没有重载(overload)和重写(overwrite)?有的话请举个例子。
答:
OC 语言不支持重载
```oc
-(void)doSth:(NSInteger)integer;
-(void)doSth:(NSString *)str;
//对Objective-C而言是一样的,都叫方法doSth: 同时定义实现这两个方法是无法编译通过的。 若要达到类似重载的效果,可以这样跟不同参数:
-(void)doSthWithInt:(NSInteger)integer;
-(void)doSthWithStr:(NSString *)str

OC 支持重写

子类重写父类方法
6.列举出 iOS 开发中三种最常出现的循环引用的场景。

答:

  • delegate 被强引用了,代理应该使用 weak (拓展 weak 干了啥使自己可以防止循环的出现)
  • 使用 block 的时候,注意是否出现互相持有。
  • 使用 NSTimer 的时候,我们可能会使+scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: 这个方法在建立的时候需要指定 target ,会被 timer retain 一份。因为 timer 还在一直执行,就会导致无法运行 dealloc的方法。正确的做法是在 viewDidDisappear: 的时候停止timer
7.MVC 模式具体指什么?iOS现在流行的 MVVM 是什么?

MVC:

MVC模式考虑三种对象:模型对象、视图对象和控制器对象。 模型对象负责应用程序的数据和定义操作数据的逻辑; 视图对象知道如何显示应用程序的模型数据; 控制器对象是M与V之间的协调者。

MVVM:

MVVM 把 View Controller 作为 View
View 和 Model 之间没有紧耦合
MVVM 是在 View 和 ViewModel 之间进行绑定。
什么是 ViewModel 呢?基本上来说,它是 View 和 View 状态的独立于     UIKit 外的一个呈现,ViewModel 调用 Model 中的的变化,根据 Model 的变化进行调整,并且通过 View 和 ViewModel 的绑定,同步调整 View。
8.iOS 中设计金钱计算和比较时,用数值应该用哪个类型来处理?
  • NSDecimalNumber 继承于 NSNumber
  • NSDecimalNumber 包含 加减乘除,幂运算,指数运算,四舍五入,比较运算。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    /** 示例 比较运算
    NSOrderedAscending 升序
    NSOrderedSame 相等
    NSOrderedDescending 降序
    - (NSComparisonResult)compare:(NSNumber *)decimalNumber;
    */
    NSDecimalNumber *discount1 = [NSDecimalNumber decimalNumberWithString:@"1.2"];
    NSDecimalNumber *discount2 = [NSDecimalNumber decimalNumberWithString:@"1.3"];
    NSComparisonResult result = [discount1 compare:discount2];
    if (result == NSOrderedAscending) {
    NSLog(@"1.2 < 1.3");
    } else if (result == NSOrderedSame) {
    NSLog(@"1.2 == 1.3");
    } else if (result == NSOrderedDescending) {
    NSLog(@"1.2 > 1.3");
    }
    输出结果 1.2 < 1.3
    ```
    ##### 9.iOS 上触摸事件的视图检测和事件传递过程是怎样的?
    * 发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中。(为什么是队列而不是栈?因为队列的特定是先进先出,先产生的事件先处理才符合常理,所以把事件添加到队列。)
    * UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow)。
    * 主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件,这也是整个事件处理过程的第一步。
    找到合适的视图控件后,就会调用视图控件的touches方法来作具体的事件处理。
    ##### 10.写一个折半查找或者快速排序
    用 Python写了一个二分查找
    ```python
    # -- coding: UTF-8 --
    # @Date : 2017-02-21
    # @Author : CepheusSun
    # @Version : python 2.7
    def in_bisect(word_list, word):
    """check weather a word is in a list using bisection search.
    Precondition: the words in the list are sorted
    :param word_list: list of strings
    :param word: string
    """
    if len(word_list) == 0:
    return False
    # 结果四舍五入
    i = len(word_list) // 2
    if word_list[i] == word:
    return True
    if word_list[i] > word:
    # search the first half
    return in_bisect(word_list[:i], word)
    else:
    # search the second half
    return in_bisect(word_list[i + 1:], word)
    def main():
    array = ['1', 'asf', 'sf2', 'df1', '2das', '5asdfd', '0sadf',
    '2ge', 'efc2', '1eds', '2ef', '2apple', 'apple', 'orange']
    print(in_bisect(array, '1'))
    print(in_bisect(array, '111'))
    if __name__ == '__main__':
    main()

Question 1.内存管理理解不正确的是
A 程序A里有一段内存被成功申请完成之后,内存计数器就从0变为1 (这个过程是alloc);
B 程序B里要使用已存在内存,那么内存计数器从1变为2 (这个过程是retain或者copy);
C 紧接着程序A不需要这个内存了,那么程序A就把这个内存计数器减1 (这个过程是release);
D 当系统发现这个内存计数器变为小于等于0,那么就调用垃圾回收程序把这段内存回收(这个过程是dealloc);

Question 2.类别的作用不正确的是
A 将类的实现分散到多个不同文件或多个不同框架中。
B 创建对私有方法的前向引用。
C 向对象添加非正式协议。 继承可以增加,修改或者删除方法。
D 不能添加属性

Question 3.点击屏幕上的按钮,系统做了什么?

Answer

Answer 1. B 使用并不会增加引用技术,持有才会。
Answer 2. D

class-continuation分类是唯一能给添加属性的分类。而所谓的关联对象,我在52个方法中找到了这样一句话:
    * “定义关联对象时可以指定内存管理语义,用以模仿定义属性时所采用的“拥有”和“非拥有关系””
可见,关连对象跟属性是两个不同的概念,不能混为一谈。

类别的三个作用:
    * 可以将类的实现分散到多个不同文件或多个不同框架中,方便代码管理。
    * 创建对私有方法的前向引用。比如在别人的类或者框架中有一个方法的是没有说明的,这时候通过类别声明这个方法,就可以在不破坏原来框架的情况下,使用到这个方法。
    * 向对象添加非正式协议。

Answer 3.

  • 触摸事件的传递是从父空间传递到子控件,如果父空间不能接收触摸事件,那么子控件就不能接收触摸事件
  • 发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中。(为什么是队列而不是栈?因为队列的特定是先进先出,先产生的事件先处理才符合常理,所以把事件添加到队列。)
  • UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow)。
  • 主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件,这也是整个事件处理过程的第一步。
    找到合适的视图控件后,就会调用视图控件的touches方法来作具体的事件处理。

#####1. idinstancetype 的区别?

  1. 在 ARC(Auto Reference Count)环境下:

    instancetype 用来在编译期确定实例的类型,而使用 id 的话,编译器不检查类型, 运行时检查类型.
    

    在 MRC(Manual Reference Count)环境下:

    instancetype 和 id 一样,不做具体类型检查
    
  2. id 可以作为方法的参数,但 instancetype 不可以
    instancetype 只适用于初始化方法和便利构造器的返回值类型

#####2. 有方法查看当前系统内存使用的情况吗?
一般我上手新的项目,检查内存问题三部曲;

  1. 静态分析, 初步了解代码不规范的地方,或者是一些内存泄漏问题。
  2. instrument, 初略的定位我们在什么地方发生了内存泄漏。
  3. 代码测试内存泄漏, 观察对象的生成和销毁是否配对。使用MLeaksFinder来配合检查
  • 两个对象互相持有,主要是 delegate 使用 weak 属性, 在 iOS8 上系统 delegate 使用的是 assign 这会带来一些问题,踩过坑的老司机可以提一下。
  • 有时候需要使用 removeFromSuperView 来释放, a 持有了 b , b 被 add 到了 c 上, 而在程序设计中b 的生命周期应该和 a 相同, 这个时候使用 self.b = nil 并不会吧 b 释放, 我们应该在之前加上 [b removeFromSuperView]

#####3. 为什么 NotificationCenter 要 removeObserver? 如何实现自动 remove?

  • 如果不移除,万一注册通知的类被销毁之后又发送了通知, 程序会 crash。 因为野指针。
  • 实现自动 remove;通过自动释放机制, 通过动态属性将 remove 转移给第三者,解除耦合,达到自动实现 remove 。

#####4. iOS的沙盒目录结构是怎样的? App Bundle 里面都有什么?

  1. 沙盒结构
    • Application: 存放程序源文件, 上架前经过数字签名,上架后不可修改
    • Documents: 常用目录, iCloud 备份目录,存放数据,这里不能缓存文件,否则上架不被通过
    • Library
      • Caches: 存放体积大又不需要备份的数据, SDWebImage 就是这个
      • Preference: 设置目录, iCloud会备份设置信息。
      • tmp: 存放临时文件,不会被备份,而且这个文件下的数据有可能随时被清除
  2. App Bundle
    • Info.plist: 文件的配置信息,系统依赖次文件获取应用程序的相关信息。
    • 可执行文件: 此文件包含应用程序的入口和通过静态链接到应用程序 target 的代码。
    • 资源文件: 图片声音
    • 其他: 可以潜入定制的数据资源。
5.简单描述一下客户端的缓存机制?
  • 缓存可以分为:
    • 内存数据缓存
    • 数据库缓存
    • 文件缓存
  • 每次想获取数据的时候
    1. 检查内存中有无缓存
    2. 检查本地有无缓存(数据库\文件)
    3. 发起请求
    4. 将服务器返回的数据进行缓存(内存数据库文件)

1.按钮或者 View 在进行 frame 动画的时候,为什么点击 frame 动画的重点位置才能触发事件?如何在动画过程中响应事件?

答:
动画开始后有两个图层:
(修改原因:不是动画开始后,而是 view 出现了的时候。只要 view 出现在试图上,他都具有这两个图层。)
iOS 中对于 UIView 具有一个 CALayer 类的属性 layer 我们姑且叫他 rootLayer。而每一个 CALayer 都有两个属性:
一个 view.layer.presentationLayer 用来显示动画(属性随动画过程慢慢改变)
(修改原因:感觉显示动画这个用法不大准确,我语文也不好😂)
一个resentationLayer 指呈现图层,是模型图层的复制,他的属性值代表了在任何指定时刻当前的显示。所以在 UIView 没有出现的时候这个 view 的属性值为 nil, 出现之后无论 view 是否动画,这个值的内存地址每次打印都不一样。

一个 view.layer 用来处理用户交互(动画一开始属性值立即改变到动画结束时的状态和位置)
(修改原因: CALayer 是不处理交互的,这一点可以从UIView有userInteractionEnabled这个属性,而CALayer没有可以看出,并且看 iOS-CoreAnimation这本书,这样使用 modelLayer 来描述更 MVC 一些)
一个modelLayer 指模型层,在 view 显示出来的时候view.layer = view.layer.presentationLayer.modelLayer = view.layer.view.layer.modelLayer。 三者内存地址是一样的,保存实际的属性值。

最后总结:当一个图层的属性改变的时候,我们设置的属性并没有直接调用图层的外观,只是定义了图层动画结束之后将要变化的外观。具体关系见下图:


from《iOS-CoreAnimation》

② 要在移动动画的过程中处理 触摸可以重写 UIView的hitTest 方法
(总的来说,通过view.layer.presentationLayer的相关属性,就可以实现响应需求了,通过touchbegan判断用户点击的位置是否在view.layer.presentationLayer.frame之内,是《iOS—CoreAnimation》中另外一个实现方式)

1
2
3
4
5
6
7
8
9
10
11
12
- (id)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
NSArray *subViews = self.subviews;
for (UIView *subView in subViews) {
if([subView isKindOfClass:[FoamImageView class]]){ //是要找的图片
CALayer *layer = subView.layer.presentationLayer; //图片的显示层
if(CGRectContainsPoint(layer.frame, point)){ //触摸点在显示层中,返回当前图片
return subView;
}
}
}
return [super hitTest:point withEvent:event];
}
1
2
3
4
5
6
7
8
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
CGPoint point = [[touches anyObject] locationInView:self.view];
if (CGRectContainsPoint(button_.layer.presentationLayer.frame, point)) {
NSLog(@"youxiangying");
[self buttonEvent:button_];
}
}

参考资料
资料1

Objective-C 之 @property和@synthesize

回炉篇之(一)– @property和@synthesize

iOS开发:Objective-C精确的货币计算

‘NSDecimalNumber–十进制数’使用方法(带例子)

objective c-OC中有方法重载吗?具体是怎么样?

http://www.cnblogs.com/LiLihongqiang/p/5645907.html
http://www.infocool.net/kb/IOS/201610/200104.html
http://www.cocoachina.com/ios/20160113/14896.html
http://www.jianshu.com/p/2e074db792ba

think python

www.voidcn.com
iOS-CoreAnimation


写在后面的话

这个系列所有的文章都是在一个QQ群里面跟小伙伴们讨论出来的,每个 topic 都已经放在了 GitHub 的一个仓库中 这是地址。 所有内容的更新的将在这个仓库中进行,在博客中将不再进行更新。有任何问题,都可以在这个仓库中给我们提 issue 或者 pull request.

CepheusSun wechat
订阅我的公众号,每次更新我都不一定会告诉你!
坚持原创技术分享,您的支持将鼓励我继续创作!
0%