前段时间更新了一篇 给iOS中高级面试官的一份招聘要求 收到不少小伙伴的点赞与关注。可能有不少小伙伴已经带着我在那篇文章给你们提供的一些面试技巧 & 其中的面试题 已经开始招聘或者应聘了!这里应你们要求,对里面的面试题提供相关答案!相信不管是面试官仍是求职者都是有所收获的~~html
PS:篇幅有点长,你们能够关注或者点赞收藏以备不时之需!!!java
1:讲讲你对
atomic
&nonatomic
的理解ios
atomic
修饰的属性(不重载设置器和访问器)只保证了对数据读写的完整性,也就是原子性,可是与对象的线程安全无关。nonatomic
替代atomic
,固然也能够一直使用atomic
。2:被
weak
修饰的对象在被释放的时候会发生什么?是如何实现的?知道sideTable
么?里面的结构能够画出来么?git
被weak修饰的对象在被释放时候会置为nil,不一样于assign;github
Runtime
维护了一个 weak表
,用于存储指向某个对象的全部weak指针
。weak表
实际上是一个 hash(哈希)表
,Key
是所指对象的地址,Value
是 weak指针
的地址(这个地址的值是所指对象指针的地址)数组。web
runtime
会调用 objc_initWeak函数
,初始化一个新的 weak指针
指向对象的地址。objc_initWeak函数
会调用 objc_storeWeak() 函数
, objc_storeWeak()
的做用是更新指针指向,建立对应的弱引用表。clearDeallocating函数
。clearDeallocating函数
首先根据对象地址获取全部 weak指针地址
的数组,而后遍历这个数组把其中的数据设为 nil
,最后把这个 entry
从 weak表
中删除,最后清理对象的记录。struct SideTable {
// 保证原子操做的自旋锁
spinlock_t slock;
// 引用计数的 hash 表
RefcountMap refcnts;
// weak 引用全局 hash 表
weak_table_t weak_table;
}
struct weak_table_t {
// 保存了全部指向指定对象的 weak 指针
weak_entry_t *weak_entries;
// 存储空间
size_t num_entries;
// 参与判断引用计数辅助量
uintptr_t mask;
// hash key 最大偏移值
uintptr_t max_hash_displacement;
};
复制代码
3:
block
用什么修饰?strong
能够?面试
block
自己是像对象同样能够 retain
,和 release
。可是,block
在建立的时候,它的内存是分配在栈(stack)上,而不是在堆(heap)上。他自己的做于域是属于建立时候的做用域,一旦在建立时候的做用域外面调用block将致使程序崩溃。retain
也能够,可是block的retain行为默认是用copy的行为实现的block
变量默认是声明为栈变量的,为了可以在block的声明域外使用,因此要把 block
拷贝(copy)到堆,因此说为了 block
属性声明和实际的操做一致,最好声明为 copy
。4:
block
为何可以捕获外界变量?__block
作了什么事?算法
研究Block的捕获外部变量就要除去函数参数这一项,下面一一根据这4种变量类型的捕获状况进行分析。编程
首先 全局变量global_i
和 静态全局变量static_global_j
的值增长,以及它们被Block
捕获进去,这一点很好理解,由于是全局的,做用域很广,因此Block
捕获了它们进去以后,在Block
里面进行++
操做,Block
结束以后,它们的值依旧能够得以保存下来。设计模式
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__Block_byref_a_0 *a; // by ref
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_a_0 *_a, int flags=0) : a(_a->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
复制代码
__main_block_impl_0结构体
就是这样把自动变量捕获进来的。也就是说,在执行 Block
语法的时候,Block
语法表达式所使用的自动变量的值是被保存进了Block
的结构体实例中,也就是 Block
自身中。
这里值得说明的一点是,若是Block
外面还有不少自动变量,静态变量,等等,这些变量在Block
里面并不会被使用到。那么这些变量并不会被Block
捕获进来,也就是说并不会在构造函数里面传入它们的值。
Block
捕获外部变量仅仅只捕获Block
闭包里面会用到的值,其余用不到的值,它并不会去捕获。
5:谈谈你对事件的传递链和响应链的理解
UIResponser
包括了各类Touch message
的处理,好比开始,移动,中止等等。常见的 UIResponser
有 UIView及子类
,UIViController
,APPDelegate
,UIApplication
等等。回到响应链,响应链是由UIResponser
组成的,那么是按照哪一种规则造成的。
A: 程序启动 UIApplication
会生成一个单例,并会关联一个APPDelegate
。APPDelegate
做为整个响应链的根创建起来,而``UIApplication会将本身与这个单例连接,即
UIApplication的
nextResponser(下一个事件处理者)为
APPDelegate`。
B:建立UIWindow 程序启动后,任何的UIWindow
被建立时,UIWindow
内部都会把nextResponser
设置为UIApplication单例
。UIWindow
初始化rootViewController
,rootViewController
的nextResponser
会设置为UIWindow
C:UIViewController初始化 loadView
, VC
的view
的nextResponser
会被设置为VC
.
D:addSubView addSubView
操做过程当中,若是子subView不是VC的View,那么subView
的nextResponser
会被设置为superView
。若是是VC
的View
,那就是 subView -> subView.VC ->superView
若是在中途,subView.VC
被释放,就会变成subView.nextResponser = superView
咱们使用一个现实场景来解释这个问题:当一个用点击屏幕上的一个按钮,这个过程具体发生了什么。
APP
检测的那个端口。2.APP
启动主线程RunLoop
会注册一个端口事件,来检测触摸事件的发生。当事件到达,系统会唤起当前APP
主线程的RunLoop
。来源就是App主线程事件
,主线程会分析这个事件。
3.最后,系统判断该次触摸是否致使了一个新的事件, 也就是说是不是第一个手指开始触碰,若是是,系统会先从响应网中 寻找响应链。若是不是,说明该事件是当前正在进行中的事件产生的一个Touch message
, 也就是说已经有保存好的响应链
二:事件传递链
经过两种方法来作这个事情。
// 先判断点是否在View内部,而后遍历subViews
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;
//判断点是否在这个View内部
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event; // default returns YES if point is in bounds
复制代码
A: 流程
1:先判断该层级是否可以响应(1.alpha>0.01 2.userInteractionEnabled == YES 3.hidden = NO)
2:判断改点是否在view
内部,
3:若是在那么遍历子view
继续返回可响应的view,直到没有。
B:常见问题
父view设置为不可点击,子view能够点击吗
不能够,hit test 到父view就截止了
子view设置view不可点击不影响父类点击
同父view覆盖不影响点击
手势对responder方法的影响
C:实际用法
点一一个圆形控件,如何实现只点击圆形区域有效,重载pointInside
。此时可将外部的点也判断为内部的点,反之也能够。
事件响应链在复杂功能界面进行不一样控件间的通讯,简便某些场景下优于代理和block
6:谈谈 KVC 以及 KVO 的理解?
7:
RunLoop
的做用是什么?它的内部工做机制了解么?
字面意思是“消息循环、运行循环”,runloop
内部实际上就是一个do-while循环
,它在循环监听着各类事件源、消息,对他们进行管理并分发给线程来执行。
1.通知观察者将要进入运行循环。 线程和 RunLoop 之间是一一对应的
2.通知观察者将要处理计时器。
3.通知观察者任何非基于端口的输入源即将触发。
4.触发任何准备触发的基于非端口的输入源。
5.若是基于端口的输入源准备就绪并等待触发,请当即处理该事件。转到第9步。
6.通知观察者线程即将睡眠。
7.将线程置于睡眠状态,直到发生如下事件之一:
8.通知观察者线程被唤醒。
9.处理待处理事件。
10.通知观察者运行循环已退出。
8:苹果是如何实现
autoreleasepool
的?
arc下编译器会优化成
void *context = objc_autoreleasePoolPush();
// {}中的代码
objc_autoreleasePoolPop(context);
复制代码
AutoreleasePoolPage
,中写入须要自动释放的对象,相似一种标记,调用objc_autoreleasePoolPop(context)
后,就会把这中间的对象release
一下。Thread Local Storage(TLS)
线程局部存储,每次存入线程或者从线程取出来。{}
中的自动释放对象,会在每一个runloop
结束时候去释放,至关于一个大的autoreleasepool
中。9:谈谈你对
FRP (函数响应式)
的理解,延伸一下RxSwift
或者RAC
!
参考文章:RxSwift(1)— 初探 看这一篇文章也就够了!而后结合 RxSwift
映射到 RAC
!函数响应式的思想是不变的!至于内部的封装有所不一样,可是最终倒是异曲同工!
10:平时开发有没有玩过
Instrument
?
分析:这里的内容很是有意思,对于一个iOS高级开发人员,我以为还有颇有必要掌握的!尤为开发3-5年,若是没有掌握这些内容我以为是不合格的
我我的建议在掌握面试题的同时还须要求职者更多的去分析和拓展!好比你的探索思路,你在这个知识点意外的延伸。还有你再实际开发过程的落地!而这些都是加分项!
1:什么是 isa,isa 的做用是什么?
2:一个实例对象的
isa
指向什么?类对象指向什么?元类isa 指向什么?
isa
指向类isa
指向元类3:objc
中类方法和实例方法有什么本质区别和联系?
类方法:
实例方法:
4:
load
和initialize
的区别?
+load
+load
方法会在当前类被加载到内存的时候调用, 有且仅会调用一次+load
方法时, 会先调用父类的+load
方法, 再调用子类的+load
方法+load
方法+load
方法时,不会调用父类的+load
方法+load
方法,+load
方法的调用顺序,与Compile Sources
中出现的顺序一致+initialize
initialize
方法在整个程序的运行过程当中只会被调用一次, 不管你使用多少次这个类都只会调用一次initialize
用于对某一个类进行一次性的初始化initialize
再调用子类的initialize
initialize
方法时,会把父类的实现继承过来调用一遍,再次以前父类的initialize
方法会被优先调用一次Category
都实现了initialize
方法,会覆盖类中的方法,只执行一个(会执行Compile Sources
列表中最后一个Category
的initialize
方法)5:
_objc_msgForward
函数是作什么的?直接调用会发生什么问题?
当对象没有实现某个方法 ,会调用这个函数进行方法转发。 (某方法对应的IMP
没找到,会返回这个函数的IMP
去执行)
若是直接调用这个方法,就算实现了想调用的方法,也不会被调用,会直接走消息转发步骤。
6:简述下
Objective-C
中调用方法的过程
Objective-C
是动态语言,每一个方法在运行时会被动态转为消息发送,即:objc_msgSend(receiver, selector)
,整个过程介绍以下:objc
在向一个对象发送消息时,runtime
库会根据对象的isa指针找到该对象实际所属的类unrecognized selector sent to XXX
《何时会报unrecognized selector的异常》
中的说明PS:Runtime
铸就了Objective-C
是动态语言的特性,使得C语言具有了面向对象的特性,在程序运行期建立,检查,修改类、对象及其对应的方法,这些操做均可以使用runtime中的对应方法实现。
7:可否想向编译后获得的类中增长实例变量?可否向运行时建立的类中添加实例变量?为何?
解释:
runtime
中,类结构体中的objc_ivar_list
实例变量的链表和instance_size
实例变量的内存大小已经肯定, runtime
会调用 class_setvarlayout
或 class_setWeaklvarLayout
来处理 strong weak
引用.因此不能向存在的类中添加实例变量class_addIvar函数
.可是的在调用objc_allocateClassPair
以后, objc_registerClassPair
以前,缘由同上.8:谈谈你对切面编程的理解
维基百科对于切面编程(AOP)的解释是这样的:面向切面的程序设计(aspect-oriented programming,AOP
,又译做面向侧面的程序设计、观点导向编程、剖面导向程序设计)是计算机科学中的一个术语,指一种程序设计范型。该范型以一种称为切面的语言构造为基础,切面是一种新的模块化机制,用来描述分散在对象、类、函数)中的横切关注点。参考文章
分析:
Runtime
这个模块iOS面试不管初中高都会面试。我以为这个模块不光只是仅仅问问关于知识点内容,我更新想要听到求职者在这里面的爬坑探索辛历路程!Runtime
这个模块是刷开页面开发的关键点!
1:HTTP的缺陷是什么?
HTTP 主要有这些不足,例举以下。
这些问题不只在HTTP
上出现,其余未加密的协议中也会存在这类问题。
2:谈谈三次握手,四次挥手!为何是三次握手,四次挥手?
参考文章 我以为这个地方仍是须要自我理解,用本身的话去表达出来!
3:
socket
链接和Http
链接的区别
http
是基于 socket
之上的。socket
是一套完整的 tcp,udp
协议的接口。
HTTP协议
:简单对象访问协议,对应于应用层,HTTP
协议是基于TCP链接的。
TCP/IP是传输层协议
,主要解决数据如何在网络中传输,而HTTP协议是应用层协议,主要解决如何包装数据。
Socket是对TCP/IP 协议的封装
,它自己不是协议,而是一个调用接口,经过Socket
,咱们才能使用TCP/IP协议
。
http链接
:就是所谓的短链接,即客户端向服务器端发送一次请求,服务器端响应后链接即会断掉。http
是客户端用http
协议进行请求,发送请求时候须要封装http
请求头,并绑定请求的数据,服务器通常有web
服务器配合。http
请求方式为客户端主动发起请求,服务器才能给响应,一次请求完毕后则断开链接以节省资源。服务器不能主动给客户端响应。iPhone
主要使用的类是NSUrlConnection
。socket
是客户端跟服务器直接使用socket“套接字”
进行拼接,并无规定链接后断开,因此客户端和服务器能够保持链接,双方均可以主动发送数据。通常在游戏开发或者股票开发这种即时性很强的而且保持发送数据量比较大的场合使用。主要类是CFSocketRef。
4:HTTPS,安全层除了SSL还有,最新的? 参数握手时首先客户端要发什么额外参数
5:何时POP网络,有了
Alamofire
封装网络URLSession
为何还要用Moya
?
POP网络
:面向协议编程的网络可以大大下降耦合度!网络层下沉,业务层上浮。中间利用 POP网络
的Moya
隔开。若是你的项目是 RxSwift
函数响应式的也没有关系!由于有 RxMoya
参考文章:
6:如何实现
dispatch_once
+ (instancetype)sharedInstance
{
/*定义相应类实例的静态变量; 意义:函数内定义静态变量,不管该函数被调用多少次, 在内存中只初始化一次,而且能保存最后一次赋的值 */
static ClassName *instance = nil;
/*定义一个dispatch_once_t(其实也就是整型)静态变量, 意义:做为标识下面dispatch_once的block是否已执行过。 static修饰会默认将其初始化为0,当值为0时才会执行block。 当block执行完成,底层会将onceToken设置为1,这也就是为什 么要传onceToken的地址(static修饰的变量能够经过地址修改 onceToken的值),同时底层会加锁来保证这个方法是线程安全的 */
static dispatch_once_t onceToken;
/*只要当onceToken == 0时才会执行block,不然直接返回静态变量instance*/
dispatch_once(&onceToken, ^{
instance = [[ClassName alloc] init];
//...
});
return instance;
}
复制代码
7:可否写一个读写锁?谈谈具体的分析 8:何时会出现死锁?如何避免? 9:有哪几种锁?各自的原理?它们之间的区别是什么?最好能够结合使用场景来讲
分析:这个模块多是通常开发人员的盲区。对于这一块必定要有本身的理解!学习的方向就是查漏补缺,一步一个吃掉!若是你一整块去啃,你会发现很枯燥!虽然开发过程当中你可能用不到,可是面试这一块是你必需要掌握的!
1.数据结构的存储通常经常使用的有几种?各有什么特色?
数据的存储结构是数据结构的一个重要内容。在计算机中,数据的存储结构能够采起以下四中方法来表现。
简单的说,顺序存储方式就是在一块连续的存储区域 一个接着一个的存放数据。顺序存储方式把逻辑上相连的结点存储在物理位置上相邻的存储单元里,结点间的逻辑关系由存储单元的邻接挂安息来体现。顺序存储方式也称为顺序存储结构(sequentialstorage structure),通常采用数组或者结构数组来描述。 线性存储方式主要用于线性逻辑结构的数据存放,而对于图和树等非线性逻辑结构则不适用。
连接存储方式比较灵活,其不要求逻辑上相邻的结点在物理位置上相邻,结点间的逻辑关系由附加的引用字段表示。一个结点的引用字段每每指导下一个结点的存放位置。 连接存储方式也称为连接式存储结构(LinkedStorage Structure),通常在原数据项中增长应用类型来表示结点之间的位置关系。
索引存储方式是采用附加索引表的方式来存储结点信息的一种存储方式。索引表由若干个索引项组成。索引存储方式中索引项的通常形式为:(关键字、地址)。其中,关键字是可以惟一标识一个结点的数据项。
索引存储方式还能够细分为以下两类:
稠密索引(Dense Index):这种方式中每一个结点在索引表中都有一个索引项。其中,索引项的地址指示结点所在的的存储位置;
稀疏索引(Spare Index):这种方式中一组结点在索引表中只对应一个索引项。其中,索引项的地址指示一组结点的起始存储位置。
散列存储方式
散列存储方式是根据结点的关键字直接计算出该结点的存储地址的一种存储的方式。 在实际应用中,每每须要根据具体数据结构来决定采用哪种存储方式。同一逻辑结构采用不一样额存储方法,能够获得不一样的存储结构。并且这四种节本存储方法,既能够单独使用,也能够组合起来对数据结构进行存储描述。
2.集合结构 线性结构 树形结构 图形结构 3.单向链表 双向链表 循环链表 4.数组和链表区别 5.堆、栈和队列
6.输入一棵二叉树的根结点,求该树的深度?
若是一棵树只有一个结点,它的深度为1。 若是根结点只有左子树而没有右子树, 那么树的深度应该是其左子树的深度加1,一样若是根结点只有右子树而没有左子树,那么树的深度应该是其右子树的深度加1. 若是既有右子树又有左子树, 那该树的深度就是其左、右子树深度的较大值再加1。
public static int treeDepth(BinaryTreeNode root) {
if (root == null) {
return 0;
}
int left = treeDepth(root.left);
int right = treeDepth(root.right);
return left > right ? (left + 1) : (right + 1);
}
复制代码
7.输入一课二叉树的根结点,判断该树是否是平衡二叉树?
1.时间复杂度
在计算机科学中,时间复杂性,又称时间复杂度,算法的时间复杂度是一个函数,它定性描述该算法的运行时间。这是一个表明算法输入值的字符串的长度的函数。时间复杂度经常使用大O符号表述,不包括这个函数的低阶项和首项系数。使用这种方式时,时间复杂度可被称为是渐近的,亦即考察输入值大小趋近无穷时的状况。 时间复杂性
2.空间复杂度
空间复杂度(Space Complexity)是对一个算法在运行过程当中临时占用存储空间大小的量度,记作S(n)=O(f(n))。好比直接插入排序的时间复杂度是O(n^2),空间复杂度是O(1) 。而通常的递归算法就要有O(n)的空间复杂度了,由于每次递归都要存储返回信息。一个算法的优劣主要从算法的执行时间和所须要占用的存储空间两个方面衡量。 时间复杂度&空间复杂度
3.经常使用的排序算法
4.字符串反转
- (NSString *)reversalString:(NSString *)originString{
NSString *resultStr = @"";
for (NSInteger i = originString.length -1; i >= 0; i--) {
NSString *indexStr = [originString substringWithRange:NSMakeRange(i, 1)];
resultStr = [resultStr stringByAppendingString:indexStr];
}
return resultStr;
}
复制代码
5.链表反转(头差法)
public Node reverseList(){
Node cur = head;
Node prev = null;
Node curNext = head.next;
Node reverHead = null;
while(cur!=null){
cur.next = prev;
cur = curNext;
prev = cur;
curNext = curNext.next;
}
reverHead = cur;
return reverHead;
}
> 6.有序数组合并
```objc
- (void)merge {
/* 有序数组A:一、四、五、八、10...1000000,有序数组B:二、三、六、七、9...999998,A、B两个数组不相互重复,请合并成一个有序数组C,写出代码和时间复杂度。 */
//(1).
NSMutableArray *A = [NSMutableArray arrayWithObjects:@4,@5,@8,@10,@15, nil];
// NSMutableArray *B = [NSMutableArray arrayWithObjects:@2,@6,@7,@9,@11,@17,@18, nil];
NSMutableArray *B = [NSMutableArray arrayWithObjects:@2,@6,@7,@9,@11,@12,@13, nil];
NSMutableArray *C = [NSMutableArray array];
int count = (int)A.count+(int)B.count;
int index = 0;
for (int i = 0; i < count; i++) {
if (A[0]<B[0]) {
[C addObject:A[0]];
[A removeObject:A[0]];
}
else if (B[0]<A[0]) {
[C addObject:B[0]];
[B removeObject:B[0]];
}
if (A.count==0) {
[C addObjectsFromArray:B];
NSLog(@"C = %@",C);
index = i+1;
NSLog(@"index = %d",index);
return;
}
else if (B.count==0) {
[C addObjectsFromArray:A];
NSLog(@"C = %@",C);
index = i+1;
NSLog(@"index = %d",index);
return;
}
}
//(2).
//时间复杂度
//T(n) = O(f(n)):用"T(n)"表示,"O"为数学符号,f(n)为同数量级,通常是算法中频度最大的语句频度。
//时间复杂度:T(n) = O(index);
}
复制代码
7.查找第一个只出现一次的字符(Hash查找)
两个思路:
hash
�不一样编译器对字符数据的处理不同,因此hash以前先把字符类型转成无符号类型;buffer数组
记录当前只找到一次的字符,避免二次遍历。# define SIZE 256
char GetChar(char str[])
{
if(!str)
return 0;
char* p = NULL;
unsigned count[SIZE] = {0};
char buffer[SIZE];
char* q = buffer;
for(p=str; *p!=0; p++)
{
if(++count[(unsigned char)*p] == 1)
*q++ = *p;
}
for (p=buffer; p<q; p++)
{
if(count[(unsigned char)*p] == 1)
return *p;
}
return 0;
}
复制代码
8.查找两个子视图的共同父视图
这个问的实际上是数据结构中的二叉树,查找一个普通二叉树中两个节点最近的公共祖先问题 假设两个视图为UIViewA
、UIViewC
,其中 UIViewA
继承于UIViewB
,UIViewB
继承于UIViewD
,UIViewC
也继承于UIViewD
;即 A->B->D,C->D
- (void)viewDidLoad {
[super viewDidLoad];
Class commonClass1 = [self commonClass1:[ViewA class] andClass:[ViewC class]];
NSLog(@"%@",commonClass1);
// 输出:2018-03-22 17:36:01.868966+0800 两个UIView的最近公共父类[84288:2458900] ViewD
}
// 获取全部父类
- (NSArray *)superClasses:(Class)class {
if (class == nil) {
return @[];
}
NSMutableArray *result = [NSMutableArray array];
while (class != nil) {
[result addObject:class];
class = [class superclass];
}
return [result copy];
}
- (Class)commonClass1:(Class)classA andClass:(Class)classB {
NSArray *arr1 = [self superClasses:classA];
NSArray *arr2 = [self superClasses:classB];
for (NSUInteger i = 0; i < arr1.count; ++i) {
Class targetClass = arr1[i];
for (NSUInteger j = 0; j < arr2.count; ++j) {
if (targetClass == arr2[j]) {
return targetClass;
}
}
}
return nil;
}
复制代码
O(N^2)
一个改进的办法:咱们将一个路径中的全部点先放进NSSet中.由于NSSet的内部实现是一个hash表,因此查询元素的时间的复杂度变成 O(1)
,咱们一共有N个节点,因此总时间复杂度优化到了O(N)
- (Class)commonClass2:(Class)classA andClass:(Class)classB{
NSArray *arr1 = [self superClasses:classA];
NSArray *arr2 = [self superClasses:classB];
NSSet *set = [NSSet setWithArray:arr2];
for (NSUInteger i =0; i<arr1.count; ++i) {
Class targetClass = arr1[i];
if ([set containsObject:targetClass]) {
return targetClass;
}
}
return nil;
}
复制代码
9.无序数组中的中位数(快排思想)
10.给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。
你能够假设每一个输入只对应一种答案,且一样的元素不能被重复利用。 示例:给定nums = [2, 7, 11, 15], target = 9
--- 返回 [0, 1]
思路:
class Solution {
public int[] twoSum(int[] nums, int target) {
int len = nums.length;
int[] result = new int[2];
for(int i = 0; i < len; i++){
for(int j = i+1; j < len; j++){
if(nums[i] + nums[j] == target){
result[0] = i;
result[1] = j;
return result;
}
}
}
return result;
}
}
复制代码
分析:这个模块是绝大部分开发人员的软肋!这个模块是最能测试求职者思惟能力的!可是我不建议面试官直接让求职者手写 在那样的面试紧张环境,手写数据结构或者一些算法代码,是很是有挑战的!思惟到我以为差很少!
1:设计模式是为了解决什么问题的?
设计模式(Design pattern)是一套被反复使用、多数人知晓的、通过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。
设计模式最主要解决的问题是经过封装和隔离变化点来处理软件的各类变化问题。 隔离变化的好处在于,将系统中常常变化的部分和稳定的部分隔离,有助于增长复用性,并下降系统耦合度。不少设计模式的意图中都明显地指出了其对问题的解决方案,学习设计模式的要点是发现其解决方案中封装的变化点。
三本经典书籍:《GOF设计模式》,《设计模式解析》,《Head First Design Pattern》
设计模式是软件开发领域的精髓之一。学好设计模式是目前每个开发人员的必修课,
2:看过哪些第三方框架的源码,它们是怎么设计的?
这个题目就看你我的的感触,考量你平时的功底! 你们能够针对性一些常见的框架:RxSwift
、Alamofire
、Moya
、AFNetworing
、YYKit
.... 掌握会用的同时,必需要掌握底层的核心思想!
3:能够说几个重构的技巧么?你以为重构适合何时来作?
在新功能增长时候,在扩展再也不简单的时候。重构是一个不断的过程。
4:开发中经常使用架构设计模式你怎么选型?
这里也是一道开放性题目!并非说某一种架构就是最优秀的~只有最合适的!根据公司状况,项目现状,以及开发者水平及时调整,设计!
5:你是如何组件化解耦的?
iOS 解藕
、组件化最经常使用的是使用统跳路由的方式,目前比较经常使用的 iOS 开源路由框架主要是JLRoutes
、MGJRouter
、HHRouter
等,这些路由框架各有优势和缺点,基本能够知足大部分需求。目前最经常使用来做路由跳转,以实现基本的组件化开发,实现各模块之间的解藕。可是,在实际中开发中会发现,没法完全使用它们完成全部模块间通讯,好比模块间的同步、异步通讯等。再好比,咱们在配置了相关路由跳转的 URL 后,如何在上线以后动态修改相关跳转逻辑?在模块间通讯时,如何在上线后动态修改相关参数?APP 可否实现相似 Web 的302跳转
?学习参考
分析:架构设计这一层对于一个iOS中高级开发人员来讲。这一块那是他必需要去思考和感觉总结的!若是这位求职者开发4-5年了,一直都在作应用层界面开发,那么想必他将来的职业晋升是已经落后了的!面试官不妨在这一个模块单独设计成一面,就和求职者一块儿交流讨论。毕竟这些思惟的设计,也许可以给面试官带来一些不同的东西!😊
1:
tableView
有什么好的性能优化方案?2: 界面卡顿和检测你都是怎么处理?
3:谈谈你对离屏渲染的理解?
4:如何下降APP包的大小
5:平常如何检查内存泄露?
6:APP启动时间应从哪些方面优化?
分析:如今APP性能优化已经成为iOS中高级开发人员必需要去关系的东西!这一块我我的建议结合实际开发去和求职者交流。而不是仅仅停留在知识点问答,由于没有实际开发能力的性能优化都只是纸上谈兵!
这一套面试题仍是有必定的水平和难度的!可是对于要应聘一份iOS中高级开发岗位,仍是比较中肯的!但愿你们可以在接下来的跳槽涨薪有本身的思想。
文章有长,建议关注备份,无论是正在面试仍是即将面试,应该对你有帮助!既然看到这里:麻烦点个赞吧!👍
PS:对本文内容存在疑问还望指出,谢谢!加油,静候你的佳音