- 声明:面试是对自我审视的一种过程,面试题和iOS程序员本身技术水平没有对等关联,无论你能否全部答出,都不要对自己产生任何消极的评价!
总体大致结构图
1.基础知识点
1.内存管理中各个属性的使用与联系(如strong与weak)?
内存管理属性大总结:https://www.jianshu.com/p/7b7ca100fa94
备注1:深拷贝和浅拷贝的区别
https://www.jianshu.com/p/e0473e249c79
备注2:如何令自己所写的对象具有拷贝功能?
备注3:对weak属性做深入剖析
比如代理要用weak;避免循环引用、当对象释放的时候,系统会对属性赋值nil(object-c有个特性就是对nil对象发送消息也就是调用方法,不会cash)
备注4:为什么IBOutlet修饰的UIView也适用weak关键字?
在xib或者Sb拖控件时,其实控件就加载到了父控件的subviews数组里面,进行了强引用,即使使用了weak,也不造成对象的释放(当我们将控件拖到storyboard或者xib上时,就相当于是创建了一个对象,而这个对象是加到了试图控制器的view上,也就是存放到了subviews数组中。也就是说我们的控件对象是属于view 的,view 对其子控件的关系是强引用。所以当我们使用Outlet属性的时候,这个Outlet属性是有view来进行强引用的,我们是在viewController中仅仅使用了它,没有必要拥有它,所以使用weak进行修饰)
PS:用strong也是可以的
备注5:属性的默认关键字是
默认关键字,基本数据: atomic,readwrite,assign
普通的 OC 对象: atomic,readwrite,strong
备注6:NSString为什么要用copy关键字,如果用strong会有什么问题?
https://blog.csdn.net/huangfei711/article/details/78297894
备注7:assing可以使用在对象中吗?
1.如果用assign修饰对象,当对象释放后(因为不存在强引用,离开作用域对象内存可能被回收),指针的地址还是存在的,也就是说指针并没有被置为nil,下次再访问该对象就会造成野指针异常。对象是分配在堆上的,堆上的内存由程序员手动释放
2.assign修饰基本数据类型或OC数据类型,因为基本数据类型是分配在栈上的,由系统分配和释放,所以不会造成野指针
备注8:通常对象为啥要用strong?
用strong就是要持有他的指针,指针就是指向内存,就是叫被引用的内存不被释放
2.KVC,KVO,Notification,delegate,block的区别和联系?
KVC:KVC (Key-value coding)键值编码,指的是在iOS开发中,开发者可以通过Key名直接访问对象的属性,或者给对象的属性赋值,而不需要调用明确的存取方法,这样就可以在运行的时候动态的访问和修改对象的属性,而不是在编译时确定。比如可以用于字典与模型的转换
KVO:是cocoa框架实现的观察者模式,一般同KVC搭配使用,通过KVO可以监测一个值的变化,比如View的高度变化;是一对多的关系,一个值的变化会通知所有的观察者。比如监测进度条,上拉加载下拉刷新contentsize。KVO使用场景是数据,监听数据变化,比如股票价格变化
https://juejin.im/post/5cf4b4b3518825095b3322d6Notification:通知是是一对多的使用场景;有些情况中KVO和通知是一样的,都是状态变化之后告知对方。通知特点就是需要被观察者先主动发出通知,然后观察者注册监听后再来进行响应,比KVO多了发送通知的一步,但是其优点是监听不局限于属性的变化,还可以对多种多样的状态变化进行监听,监听范围广,比如监听键盘。通知是弱关联,就是委托和代理双方互相之间都都不需要知道是谁
delegate:代理,就是我不想做的事情交给别人做。比如狗需要吃饭,就通过delegate通知主人,主人就会给他做饭、盛饭这些操作,这些狗都不需要关心,只需要调用delegate(代理人)就可以了,由其他类完成所需要的操作,所以delegate是一对一关系。代理使用场景是行为,是强关联,即委托和代理双方互相都需要知道
block:是delegate的另一种形式,是函数式编程的一种形式。使用场景跟delegate一样,相比delegate更灵活,而且代理的实现更直观
附加 - KVC /KVO使用场景:https://www.jianshu.com/p/2ea8bd7a372b
附加 - 以上用于传值场景的demo:https://www.jianshu.com/p/a6faf5d7868a
备注1:block的实质是什么?一共有几种block?都是什么情况下生成的?
block:本质就是一个object-c对象.
block:存储位置,可能分为3个地方:代码去,堆区、栈区(ARC情况下会自动拷贝到堆区,因此ARC下只能有两个地方:代码去、堆区)
代码区:不访问栈区的变量(如局部变量),且不访问堆区的变量(alloc创建的对象),此时block存放在代码去。
堆区:访问了处于栈区的变量,或者堆区的变量,此时block存放在堆区。–需要注意实际是放在栈区,在ARC情况下会自动拷贝到堆区,如果不是ARC则存放在栈区,所在函数执行完毕就回释放,想再外面调用需要用copy指向它,这样就拷贝到了堆区,strong属性不会拷贝、会造成野指针错区
备注2:为什么在默认情况下无法修改被block捕获的变量? __block都做了什么?
*备注3:block和函数指针的理解?
备注4:__block、__weak、__strong 区别?
https://www.cnblogs.com/sunjianfei/p/6688876.html
3.说说你理解的埋点?
4.什么是函数式编程?
Person *person = [[Person alloc] init];
person.run(9.2).eat(@"香蕉").run(1.2).eat(@"面条");
通过一个小例子来解释:上面的就是链式编程+函数式编程。
1.通俗解释:括号里面的参数跟swift的函数调用很相似,包括别的语
言,都用小括号传参,只有OC是冒号传参;2.再看方法调用用的是".",而OC用的是[]+空格;
3.这几个方法调用,如果要按OC的打法,估计要整4行,对象一个一个的调用方法,但链式就是这么一行搞定;
4.分析一下,因为Block可以通过()来传值,我们推断run(para)和eat(para)这两个方法,肯定返回值是一个Block,而且是带一个参数的Block
5.沙盒的文件目录,他们的用途?
6.Swift与OC相比?
Swift比OC的优势:
1.Swift容易阅读
2.Swift更容易维护
3.Swift更加安全
4.Swift代码更少
5.Swift速度更快Swift目前存在的缺点:
1.版本不稳定
2.使用人数比例偏低,目前还是OC的天下
3.社区的开源项目偏少,毕竟OC独大好多年,很多优秀的类库都不支持Swift,不过正在改变,现在有好多优秀的Swift的开源类库了
4.公司使用的比例不高,很多公司以稳为主,还是在使用OC开发,很少一些在进行混合开发,更少一些是纯Swift开发
5.偶尔开发中遇到的一些问题,很难查找到相关资料,这是一个弊端
6.纯Swift的运行时和OC有本质区别,一些OC中运行时的强大功能,在纯Swift中变无效了
7.对于不支持Swift的一些第三方类库,如果非得使用,只能混合编程,利用桥接文件实现总结:
现阶段Swift无法取代 Objective-C;其实到现在为止 Swift 离完全替代 Objective-C 还是很遥远,因为 Apple 内部一直在用 Objective-C 来做一些 Framework 的开发,底层也不可能用 Swift 实现,所以现在更多的替代是体现在外部开发
7.swift语法糖?!的本质(实现原理)
? 和 ! 其实分别是Swift语言中对一种可选类型( Optional) 操作的语法糖。 那可选类型是干什么的呢? Swift中是可以声明一个没有初始值的属性, Swift中引入了可选类型(Optional)来解决这一问题。它的定义是通过在类型生命后加加一个 ? 操作符完成的。
例如: var name: String?
Optional其实是个enum,里面有None和Some两种类型。其实所谓的nil就是Optional.None , 非nil就是Optional.Some, 然后会通过Some(T)包装(wrap)原始值,这也是为什么在使用Optional的时候要拆包(从enum里取出来原始值)的原因
8.OC 和 JS(H5)交互,OC怎么调用JS(H5)函数,JS怎么调用OC方法 ?
WebViewJavascriptBridge:https://www.jianshu.com/p/d12ec047ce52
9.iOS中常用的数据存储方式有哪些?
10.类别与扩展的区别?
11.instancetype和id的异同?
1.相同点
都可以作为方法的返回类型2.不同点
①instancetype可以返回和方法所在类相同类型的对象,id只能返回未知类型的对象;
②instancetype只能作为返回值,不能像id那样作为参数
12.isKindOfClass和isMemberOfClass的区别
isKindOfClass来确定一个对象是否是一个类的成员,或者是派生自该类的成员
isMemberOfClass只能确定一个对象是否是当前类的成员
13.一个动画怎么实现?
Core Animation(核心动画)
1.核心动画都是针对图层来说的,Core Animation的动画执行过程都是在后台操作的,不会阻塞主线程;要注意的是Core Animation是直接作用在CALayer上的,并非UIView2.Core Animation的使用步骤:
1.使用它需要先添加QuartzCore.framework框架和引入主头文件<QuartzCore/QuartzCore.h>(iOS7不需要)
2.初始化一个CAAnimation对象,并设置一些动画相关属性,添加图层想要达到的动画后的结果
3.通过调用CALayer的addAnimation:forKey:方法增加CAAnimation对象到CALayer中,这样就能开始执行动画了(此方法进行动画的触发)
4.通过调用CALayer的removeAnimationForKey:方法可以停止CALayer中的动画
备注1:Core Animation可以直接用吗?他有哪些子类呢?使用Core Animation有哪些属性?
1.对于Core Animation框架,CAAnimation是所有动画类的父类,但是它不能直接使用,应该使用其子类;可以直接使用的子类有CABasicAnimation、CAKeyframeAnimation、CATransition、CAAnimationGroup;不能使用的子类有CAPropertyAnimation(不能直接使用,使用其子类)
2.常见的属性有:
duration:动画的持续时间
repeatCount:动画的重复次数
repeatDuration:动画的重复时间
timingFunction:速度控制函数,控制动画运行的节奏
fillMode:决定当前对象在非active时间段的行为。比如动画开始之前,动画结束之后
beginTime:可以用来设置动画延迟执行时间,若想延迟2s,就设置为CACurrentMediaTime() + 2,CACurrentMediaTime()为图层当前的时间
removedOnCompletion:默认为YES,代表动画执行完毕后就从图层上移除,图形会恢复到动画执行前的状态。如果想让图层保持显示动画执行后的状态,那就设置为NO,不过还要设置fillMode为kCAFillModeForwards
备注2:Core Animation中的事务了解吗?可以把几个动画合成到一起吗?
核心动画事务分隐式事务和显式事务:https://blog.csdn.net/andy_jiangbin/article/details/12111725;动画可以灵活组合
备注3:UIView动画与CALayer动画(Core Animation)的对比
1.实现动画的主要方式就是UIView动画与Core Animation;在真实在开发中一般主要使用UIView封装的动画(建议使用),而很少使用CALayer的动画
2.区别:
UIView动画执行完毕之后不会反弹,CALayer核心动画会反弹
使用CALayer你所看到的动画都是假象,图层的属性一直都没有变过(如改变layer的位置状态,表面上看虽然已经改变了,但是实际上它的位置是没有改变的)
14.如何终止正在运行的工作线程?
一般来讲网络操作都是可以终止的,就 URLSession 来说,每个 task 都有 cancel 方法,直接 cancel 掉就好了。如果说是耗时的计算类线程,在恰当的地方加个 flag,cancel 时把 flag 置 false,线程就能及时终止。但是GCD本身是没有提供这样的API
- 终止一个线程中正在执行的任务:设置一个标识符,假如是BOOL类型的,当它为NO的时候执行任务,当它变为YES的时候终止执行任务
dispatch_async(dispatch_get_global_queue(0, 0), ^{
for (NSInteger i = 0; i < 10000; i++) {
NSLog(@"%lu",(long)i);
sleep(2);
if (flag == YES) {
NSLog(@"终止任务...");
}
}
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"回到主线程刷新UI");
});
});
15.GET和POST的区别?
1.GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连, 操作简单, 不过容易让外界看到, 安全性不高。POST 请求, 将参数放到 body 里面, POST请求的操作相对复杂, 需要将参数和地址分开, 不过安全性高,参数放在body里面, 不容易被捕获
2.GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制
3.一般用GET来进行获取数据,因为有缓存,所以可以降低服务器的压力;而POST一般用来进行操作数据,如增删改
4.GET方式需要使用Request.QueryString来取得变量的值,而POST方式通过Request.Form来获取变量的值
5.GET方式提交数据,会带来安全问题,比如一个登录页面,通过GET方式提交数据时,用户名和密码将出现在URL上,如果页面可以被缓存或者其他人可以访问这台机器,就可以从历史记录获得该用户的账号和密码
16.HTTP与HTTPS的区别?
1.HTTPS协议需要到CA申请证书,一般免费证书很少,需要交费
2.HTTP是明文传输,HTTPS则是具有安全性的SSL加密传输
3.HTTP和HTTPS使用的端口也不一样,前者是80,后者是443
4.HTTPS可进行加密传输、身份认证,比HTTP安全
备注1:简单说说Https的双/单向认证?
https://blog.csdn.net/duanbokan/article/details/50847612#
备注2:http和https工作原理?
https://blog.csdn.net/lr131425/article/details/70316788
17.RSA与AES加密?
18.为什么说Objective-C是一门动态的语言?
object-c类的类型和数据变量的类型都是在运行时确定的,而不是在编译时确定。例如:多态特性,我们可以使用父类指针来指向子类对象,并且可以用来调用子类的方法。运行时(runtime)特性,我们可以动态的添加方法,或者替换方法
19.如果你在使用UITableView的时候,需要改变tableView的Header的高度,直接给他的Frame设值有没有效果
如果Header的高度是动态变化的,则直接设置Frame没有效果的;https://www.jianshu.com/p/265f7a06b59a
20.main()之前的过程有哪些?
21.APP的所有状态
didFinishLaunchingWithOptions 程序加载完成之后调用,再次进入不会再调用(APP还没有被杀死)
applicationWillResignActive APP即将推出到后台
applicationDidEnterBackground APP已经进入后台会回调这个函数
applicationWillEnterForeground APP即将进入前台
applicationDidBecomeActive APP已经变得活跃
applicationWillTerminate APP将要结束
- 备注:applicationWillEnterForeground和applicationDidBecomeActive具体都会在哪些场景下被调用?
当程序进入后台状态时,名为applicationWillEnterForeground委托方法会被调用:
-(void)applicationWillEnterForeground:(UIApplication *)application { }
当程序复原时,applicationDidBecomeActive 委托方法会被调用
推送、支付、应用跳转、分享、退到后台等
22.一个APP从启动到视图展示所有的步骤
+load方法加载->main->UIApplicationMain->AppDelegate->didFinishLaunchingWithOptions->UIWindow->rootViewController
23.描述一个ViewController的生命周期?
当我们调用UIViewControlller的view时,
系统首先判断当前的 UIViewControlller是否存在view,如果存在直接返回view,
如果不存在的话,会调用loadview方法,
然后判断loadview方法是否是自定义方法,
如果是自定义方法,就执行自定义方法,
如果不是自定义方法,判断当时视图控制器是否有xib、stroyboard。
如果有xib、stroyboard 就加载xib、stroyboard。
如果没有创建一个空白的view。
调用viewDidLoad方法。
最后返回viewloadView->viewDidLoad->viewWillAppear->viewWillLayoutSubviews->viewDidLayoutSubviews->viewDidAppear->viewWillDisappear->viewDidDisappear
24.在开发中你一般是如何调试程序、Bug?
打断点、lldb、instrument中调试内存泄漏:
https://www.jianshu.com/p/05b68c84913a
https://www.jianshu.com/p/c86b79c09d34
- 在运行过程中,如果出现EXC_BAD_ACCESS 异常,往往提示的信息很少或者没有提示,启用NSZombieEnabled后在控制台能打印出更多的提示信息,便于debug,请注意,僵尸模式下的调试工作只能在模拟器中实现,我们无法在物理设备上完成这一诊断流程
- 异常断点,一般程序crash时Xcode一般会定位到main函数中,得不到详细的crash信息,打上异常断点后就极大可能定位到程序的crash处,利于debug
- 一般来说,在创建工程的时候,应该在Build Settings启用Analyze During 'Build',这样每次编译时都会自动静态分析。这样的话,写完一小段代码之后,就马上知道是否存在内存泄露或其他bug问题,并且可以修bugs
- 如果你想在运行的时候查看APP是否存在内存泄露,你可以使用Xcode上instruments工具上的Leaks模块进行内存分析。但是有些内存泄露是很难检查出来,有时只有通过手动覆盖dealloc方法,看它最终有没有调用
备注:Bugly项目bug检测,你有没有配置过符号表呢?如果线上出现问题在bugly上反映出来了你要怎么定位问题呢?
可以结合符号表工具配置,通过符号表来具体定位bug的位置
https://www.jianshu.com/p/b0afae74d34b
https://www.jianshu.com/p/72d593725855
25.如何对iOS设备进行性能测试?
Instruments 是应用程序用来动态跟踪和分析 Mac OS X 和 iOS 代码的实用工具。这是一个灵活而强大的工具,它让你可以跟踪一个或多个进程,并检查收集的数据
- 备注:如果设计一种机制检测UIViewController的内存泄漏时,一般可用Instrument来测试
26.setNeedsLayout和layoutIfNeeded,layoutSubviews的功能是什么
(https://www.jianshu.com/p/a84f85729952)
layoutSubviews:继承于UIView的子类重写,进行布局更新,刷新视图。如果某个视图自身的bounds或者子视图的bounds发生改变,那么这个方法会在当前runloop结束的时候被调用(不能直接调用这个方法)
setNeedsLayout:标记为需要重新布局,异步调用layoutIfNeeded刷新布局,不立即刷新,在下一轮runloop结束前刷新,对于这一轮runloop之内的所有布局和UI上的更新只会刷新一次,layoutSubviews一定会被调用
layoutIfNeeded:如果有需要刷新的标记,立即调用layoutSubviews进行布局(如果没有标记,不会调用layoutSubviews)
27.事件传递的顺序和流程(https://www.jianshu.com/p/2e074db792ba)
事件的传递和事件的响应刚好相反
事件的传递:寻找最合适的view的过程。 UIApplication-> keyWindow->父视图->子视图 - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event方法进行递归查找
事件的响应:寻找能处理的view。子视图->父视图->keyWindow->UIApplication->丢弃响应事件
28.UILayer & UiView?
29.switch 语句 if 语句区别与联系?
1.均表示条件的判断,switch语句表达式只能处理的是整型、字符型和枚举类型,而选择流程语句则没有这样的限制
2.switch语句比选择流程控制语句效率更高
30.imageName和mageWithContextOfFile的区别?哪个性能高
31.传值通知&推送通知(本地&远程)
32.项目中哪些地方用了单例,单例详解?
单例模式主要实现唯一实例,存活于整个程序范围内,一般存储用户信息经常用到单例,比如用户密码,密码在登录界面用一次,在修改密码界面用一次,而使用单例,就能保证密码唯一实例。如果不用单例模式,init 两个的实例的堆栈地址不一样,所以存放的数据的位置也不一样,当其中一个数据改变,另一个数据依然不变
备注:系统为我们提供的单例类有哪些?
UIApplication(应用程序实例类)
NSNotificationCenter(消息中心类)
NSFileManager(文件管理类)
NSUserDefaults(应用程序设置)
NSURLCache(请求缓存类)
NSHTTPCookieStorage(应用程序cookies池)https://www.jianshu.com/p/a92c0283f243
https://www.jianshu.com/p/f902712d0e5e
https://www.jianshu.com/p/90bfe676b17a
- 单例模式的代码示例如下:
.h文件
#ifndef Singleton_h
#define Singleton_h
@interface Singleton : NSObject
@property (nonatomic, copy) NSString *pass;
+ (Singleton *) sharedInstance;
@end
.m文件
#import <Foundation/Foundation.h>
#import "Singleton.h"
@implementation Singleton
static id sharedSingleton = nil;
+ (id)allocWithZone:(struct _NSZone *)zone {
if (sharedSingleton == nil) {
dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedSingleton = [super allocWithZone:zone];
});
}
return sharedSingleton;
}
- (id)init {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedSingleton = [super init];
});
return sharedSingleton;
}
+ (instancetype)sharedInstance {
return [[self alloc] init];
}
+ (id)copyWithZone:(struct _NSZone *)zone {
return sharedSingleton;
}
+ (id)mutableCopyWithZone:(struct _NSZone *)zone {
return sharedSingleton;
}
@end
33.实现控制器上下滑动隐藏或显示导航栏的效果?
34.谓词实现查找功能,请问你是怎么使用的谓词?
Cocoa 中提供了一个NSPredicate的类,该类主要用于指定过滤器的条件,每一个对象通过谓词进行筛选,判断条件是否匹配;
谓词详解:https://www.jianshu.com/p/88be28860cde
35.如何hook一个对象的方法,而不影响其它对象?
1.Hook 技术又叫做钩子函数,在系统没有调用该函数之前,钩子程序就先捕获该消息,钩子函数先得到控制权,这时钩子函数既可以加工处理(改变)该函数的执行行为,还可以强制结束消息的传递。简单来说,就是把系统的程序拉出来变成我们自己执行代码片段;
2.hook一个对象的方法,而不影响其它对象,这个用runtime交换方法就ok了https://blog.csdn.net/shihuboke/article/details/83511788
https://www.cnblogs.com/n1ckyxu/p/6186850.html
36.WebViewJavascriptBridge能说一下他怎么使用嘛?你是用的UIWebView还是WKWebView?
WebViewJavascriptBridge的基本使用:https://www.jianshu.com/p/d12ec047ce52
WebView的那些事:https://www.jianshu.com/p/9cd4ee141653
37.第三方库&第三方平台
第三方库一般是指大牛封装好的一一个框架(库) ,或者第三方给我们提供的一个库,这里比较笼统*第三方平
台:指第三方提供的-些服务,其实很多方面跟第三方库是一样的,但是还是存在一些区别。区别:库: AFN, ASI, Alomofire, MJRefresh, MJExtension, MBProgressHUD 平台:极光,百度,友盟,Mob,环信
38.git版本控制器SourceTree的使用?
39.手机可以通过USB直接运行xcode项目进行注册安装App,如果只通过打包的形式怎么让新的测试机安装上APP
通过蒲公英扫码获取手机的UDID,再添加UDID,重新下载配置文件进行双击完成注册
40.UDID & UUID
41.你在上线的时候有没有遇到过APP被拒的情况,如果有,那是什么问题造成的
有遇到,造成的原因有很多种。例如使用定位或者相机的时候没有具体告诉用户使用它们来干嘛就会被拒绝;
APP上线详细流程:https://www.jianshu.com/p/0c08d6b350bf
42.static、self、super关键字的作用
43.#include与#import的区别,#import 与@class 的区别
44.@public、@protected、@private 它们的含义与作用
45.nonatomic和atomic的区别?atomic是绝对的线程安全么?
nonatomic:表示非原子,不安全,但是效率高;
atomic:表示原子行,安全,但是效率低;
atomic:不能绝对保证线程安全,当多线程同时访问的时候,会造成线程不安全。可以使用线程锁来保证线程的安全
46.属性的实质是什么?包括哪几个部分?@dynamic关键字和@synthesize关键字是用来做什么的?
各种变量区别:https://blog.csdn.net/tenmios/article/details/51612350
47.NSCache优于NSDictionary的几点?
1.nscache 是可以自动释放内存的
2.nscache是线程安全的,我们可以在不同的线程中添加,删除和查询缓存中的对象
3.一个缓存对象不会拷贝key对象
48.isa指针?(对象的isa,类对象的isa,元类的isa)
49.类方法和实例方法有什么区别?
50.objc中向一个nil对象发送消息将会发生什么?(返回值是对象,是标量,结构体)
• 如果一个方法返回值是一个对象,那么发送给nil的消息将返回0(nil)。例如:Person * motherInlaw = [ aPerson spouse] mother]; 如果spouse对象为nil,那么发送给nil的消息mother也将返回nil。
• 如果方法返回值为指针类型,其指针大小为小于或者等于sizeof(void*),float,double,long double 或者long long的整型标量,发送给nil的消息将返回0。
• 如果方法返回值为结构体,正如在《Mac OS X ABI 函数调用指南》,发送给nil的消息将返回0。结构体中各个字段的值将都是0。其他的结构体数据类型将不是用0填充的。
• 如果方法的返回值不是上述提到的几种情况,那么发送给nil的消息的返回值将是未定义的。
51.如何提高json解析效率呢?
使用一些相关工具进行解析,比如安卓可用Fastjson进行解析。iOS可以用MJExtension或者YYModel
备注:解析复杂json数据
https://www.jianshu.com/p/8bd5c128e37d
https://www.jianshu.com/p/c3eb1ed0269f
52.在下拉刷新表格时如何让上面的轮播图也继续自动轮播?
1.自定义轮播图实现思路
1.横向滚动的banner;UIScrollViw+UIImageView或者UICollectionView+UICollectionViewCell。前者需要自己做重用UIImageView,后者可以直接重用UICollectionViewCell;如果前者没有做重用,会多占用内存
2.自动循环播放banner;可以使用计时器触发循环播放,拖动或手动滑动banner时,停止自动循环播放banner;手势停止后,开启自动循环播放banner
3.特殊banner位的处理;处于第1个或最后1个时,为保证横向自动滑动效果流畅性,不跳动,需要特殊处理下;在生成banner时,第1个前面插入最后1个banner。最后1个banner后面插入第1个banner;当滑动到最后1个banner时,重置于第2个banner位2.主线程的 RunLoop 里有两个预置的 Mode:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode。这两个 Mode 都已经被标记为"Common"属性,DefaultMode 是 App 平时所处的状态,TrackingRunLoopMode 是追踪 ScrollView 滑动时的状态。当你创建一个 Timer 并加到 DefaultMode 时,Timer 会得到重复回调,但此时滑动一个TableView时,RunLoop 会将 mode 切换为 TrackingRunLoopMode,这时 Timer 就不会被回调,不会影响到滑动操作(滑动时定时器不工作了)。如果想让定时器继续工作,就切换Mode,也就是滑动与不滑动取决于你timer的runloop的mode是什么模式的
3.系统默认注册了5个Mode:
(1)kCFRunLoopDefaultMode::App的默认 Mode,通常主线程是在这个 Mode 下运行的;
(2)UITrackingRunLoopMode::界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响;(3)UIInitializationRunLoopMode:在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用;
(4)GSEventReceiveRunLoopMode:接受系统事件的内部 Mode,通常用不到;
(5)kCFRunLoopCommonModes:这是一个占位的 Mode,没有实际作用
https://www.jianshu.com/p/b8622cee2ce3为什么 UIScrollView 的滚动会导致 NSTimer 失效?
https://www.jianshu.com/p/93a65a2b4699
53.简述一下MVC和MVVM的区别和联系
MVC:架构中M表示MOdel,负责存储、定义、操作数据;V表示视图View,展示界面进行交互;C表示控制器Controller,协调进行Model和View的通信。MVC可以解除控制逻辑、业务逻辑和视图之间的耦合,提升系统的可扩展性和可维护性。主要由模型、控制器和视图三个部分组成。
1.其中控制器的主要责任是接受客户所提交的请求,并将请求转发给适当的模型对象进行处理,再将处理的结果发给视图,进行显示;
2.模型的主要作用是根据客户的请求来进行相应的业务运算;3.控制器将模型运算的结果发送到视图,视图负责将这部分数据显示给客户
- 缺点:
1.较差的可测试性;由于View Controller混合了视图处理逻辑和业务逻辑(业务逻辑和业务展示强耦合),分离这些成分的单元测试成了一个艰巨的任务
2.Controller将愈发厚重;随着项目越写越大,Controller的业务逻辑及代码会越来越多
3.遗失的网络逻辑;苹果使用的 MVC 的定义:所有的对象都可以被归类为一个 Model、一个 view或一个控制器。就这些,那么把网络代码放哪里?网络调用应该使用异步,放在 Model 对象和 view 里都不合适,因此只剩下控制器了,但加剧来控制器的厚重
MVVM:是Model-View-ViewMode模式的简称;由视图(View)、视图模型(ViewModel)、模型(Model)三部分组成。比MVC更加释放控制器臃肿,将一部分逻辑(耗时,公共方法,网络请求等)和数据的处理等操作从控制器里面搬运到ViewModel中,使得Controller只需要专注于数据调配的工作。MVVM特点如下:
1.低耦合;View可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变
2.可重用性;可以把一些视图的逻辑放在ViewModel里面,让很多View重用这段视图逻辑
3.独立开发;开发人员可以专注与业务逻辑和数据的开发(ViewModel)。设计人员可以专注于界面(View)的设计
4.可测试性;可以针对ViewModel来对界面(View)进行测试
2.底层知识解释分析
1.iOS 内存管理相关面试题
https://mp.weixin.qq.com/s/kTgvpOp_wgw-202Z3dhNkg
结合查看:基础知识第一条的内存相关属性
2.Autorelease pool的实现原理?
Autorelease Pool作用:缓存池,可以避免我们经常写relase的一种方式。其实就是延迟release,将创建的对象,添加到最近的autoreleasePool中,等到autoreleasePool作用域结束的时候,会将里面所有的对象的引用计数器-1
https://www.jianshu.com/p/50bdd8438857
https://www.jianshu.com/p/1b66c4d47cd7
3.APP崩溃及内存泄露的几种情况
BViewController *bViewController = [[BViewController alloc] init];
bViewController.delegate = self; //假设 self 是AViewController
[self.navigationController pushViewController:bViewController animated:YES];
/**
假如是 strong 的情况
bViewController.delegate ===> AViewController (也就是 A 的引用计数 + 1)
AViewController 本身又是引用了 ===> delegate 引用计数 + 1
导致: AViewController Delegate ,也就循环引用啦
*/
备注:野指针详解?
https://www.jianshu.com/p/8aba0ee41cd7
4.怎么实现一个精准的NSTimer?
- 不准的原因如下:
1.NSTimer加在main runloop中,模式是NSDefaultRunLoopMode;main负责所有主线程事件例如UI界面的操作、复杂的运算,这样在同一个runloop中timer就会产生阻塞
2.模式的改变;主线程的 RunLoop 里有两个预置的 Mode:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode;当你创建一个 Timer 并加到 DefaultMode 时,Timer 会得到重复回调。但此时滑动一个ScrollView时,RunLoop 会将 mode 切换为 TrackingRunLoopMode,这时 Timer 就不会被回调,并且也不会影响到滑动操作,所以就会影响到NSTimer不准的情况。
PS:DefaultMode 是 App 平时所处的状态,rackingRunLoopMode 是追踪 ScrollView 滑动时的状态
- 常用2种解决方法:
方法1.在主线程中进行NSTimer操作,但是将NSTimer实例加到main runloop的特定mode(模式)中;
避免被复杂运算操作或者UI界面刷新所干扰
NSTimer *timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(showTime) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
方法2.在子线程中进行NSTimer的操作,再在主线程中修改UI界面显示操作结果;
- (void)timerMethod2 {
NSThread *thread = [[NSThread alloc] initWithTarget:self
selector:@selector(newThread) object:nil];
[thread start];
}
- (void)newThread {
@autoreleasepool {
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(showTime) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] run];
}
}
总结:一开始的时候系统就为我们将主线程的main runloop隐式的启动了,
在创建线程的时候,可以主动获取当前线程的runloop,每个子线程对应一个runloop
5.NSThread、NSOprention和gcd的差别与联系?(多线程)
https://www.jianshu.com/p/2c5840b96ff1
补充:https://www.jianshu.com/p/4f3c4cde8177项目中用GCD例子:比如下载的地方要用gcd,多线程,然后同步回调的时候用信号量加锁也是用gcd
备注1:GCD使用详解及死锁现象
GCD详解一:https://www.jianshu.com/p/3b022383c774
GCD详解二:https://www.jianshu.com/p/a09c44b2e0c3
https://www.jianshu.com/p/20e310f8bd72
信号量:https://www.jianshu.com/p/3ea873c38740
备注2:如何使用队列来避免资源抢夺?
当我们使用多线程来访问同一个数据的时候,就有可能造成数据的不准确性。这个时候我么可以使用线程锁的来来绑定。也是可以使用串行队列来完成。如:fmdb就是使用FMDatabaseQueue,来解决多线程抢夺资源
6.Objective C都有哪些锁机制,你一般用哪个?
iOS开发中常用的锁有如下几种:
1.@synchronized 同步锁
2.NSLock 对象锁
3.NSRecursiveLock 递归锁
4.NSConditionLock 条件锁
5.pthread_mutex 互斥锁(C语言)
6.dispatch_semaphore 信号量实现加锁(GCD)
7.OSSpinLock 参考YY
https://www.jianshu.com/p/93a37d228be6
7.死锁的四个必要条件
1.互斥条件:一个资源每次只能被一个进程使用。
2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
3.不剥夺条件:进程已获得的资源,在末使用完之前不能强行剥夺
4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁
-
死锁的经典代码:
比如这个最简单的OC命令行程序就会导致死锁,运行后不会看到任何结果。回到上面的死锁代码中:首先明确的是:执行这个dispatch_get_main_queue队列的是主线程。执行了dispatch_sync函数后,将block添加到了main_queue中,同时调用dispatch_syn这个函数的线程(也就是主线程)被阻塞,等待block执行完成,而执行主线程队列任务的线程正是主线程,此时他处于阻塞状态,所以block永远不会被执行,因此主线程一直处于阻塞状态。因此这段代码运行后,并非卡在block中无法返回,而是根本无法执行到这个block
修改方法:
dispatch_async(dispatch_get_global_queue(0,0), ^(void){
NSLog(@"这就不死锁了");
});
- 备注:死锁概念及解决办法
https://www.jianshu.com/p/342d60d67bbc
8.什么是runloop,它和线程有什么关系。你在工作中什么时候用的过的?
https://www.jianshu.com/p/59babb56eb19
https://www.cnblogs.com/jiangzzz/p/5619512.html#_labelTop
https://www.jianshu.com/p/52730bb30aab备注:runloop中有几种mode,·每一种都是什么作用?
9.runtime在项目中用得多不多,你都拿来实现过什么功能?
(1).方法交换(①AFNetWorking对NSUrlSession的暂停和开启的方法注入通知,让开发者能得到当前session的状态②统计埋点的实现,交换系统方法)
(2).遍历属性(①MJExtension的实现②如果一个类含有很多属性,并且需要归档,可以用这个方法)
(3).消息转发
(4).分类的关联属性
(5).比如我们项目中很多地方需要添加圆角,我们就用runtime给UIView添加分类。动态添加属性,跟系统的设置圆角相类似的属性,但是我们再底层做了处理,不会出现离屏渲染备注1:
Runtime简介:https://www.jianshu.com/p/ae2f023f58e9
OC最实用的runtime总结,面试、工作你看我就足够了:https://www.jianshu.com/p/ab966e8a82e2
备注2:运行时能增加成员变量么?能增加属性么?如果能,如何增加?如果不能,为什么?
可以添加属性的,但必须我们实现它的getter和setter方法。但是没有添加带下滑线同名的成员变量
但是我们使用runtime我们就可以实现添加成员变量方法如下
- (void)setName:(NSString *)name {
/**
* 为某个类关联某个对象
*
* @param object#> 要关联的对象 description#>
* @param key#> 要关联的属性key description#>
* @param value#> 你要关联的属性 description#>
* @param policy#> 添加的成员变量的修饰符 description#>
*/
objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name {
/**
* 获取到某个类的某个关联对象
*
* @param object#> 关联的对象 description#>
* @param key#> 属性的key值 description#>
*/
return objc_getAssociatedObject(self, @selector(name));
}
10.从runtime层面上解释__weak的实现?
runtime 对注册的类, 会进行布局,对于 weak 对象会放入一个 hash 表中。 用 weak 指向的对象内存地址作为 key,当此对象的引用计数为0的时候会 dealloc,假如 weak 指向的对象内存地址是a,那么就会以a为键, 在这个 weak 表中搜索,找到所有以a为键的 weak 对象,从而设置为 nil
11.iOS消息转发机制原理?(Runtime相关)
基本分为三个步骤:1.动态方法解析 2.备用接受者 3.完整转发
动态方法解析
对象在接收到未知的消息时,首先会调用所属类的类方法+resolveInstanceMethod:(实例方法)或者+resolveClassMethod:(类方法)进行判断。如果YES则能接受消息,NO不能接受消息,进入第二步备用接受者
动态方法解析无法处理消息,则会走备用接受者。这个备用接受者只能是一个新的对象,不能是self本身,否则就会出现无限循环。如果我们没有指定相应的对象来处理aSelector,则应该调用父类的实现来返回结果完整消息转发
如果第2步返回self或者nil,则说明没有可以响应的目标,则进入第三步走完整消息转发
12.TCP为什么是三次握手和四次挥手?为什么要使用HTTP?为什么不直接用TCP?Ping是什么协议
三次握手:
- 第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
- 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包,即SYN+ACK包,此时服务器进入SYN+RECV状态;
- 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次状态
四次挥手:
- 第一次挥手:客户端发送一个FIN,用来关闭客户端到服务端的数据传送,客户端进入FIN_WAIT_1状态
- 第二次挥手:服务端收到FIN后,发送一个ACK给客户端,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),服务端进入CLOSE_WAIT状态
- 第三次挥手:
服务端发送一个FIN,用来关闭服务端到客户端的数据传送,服务端进入LAST_ACK状态- 第四次挥手:
客户端收到FIN后,客户端进入TIME_WAIT状态,接着发送一个ACK给服务端,确认序号为收到序号+1,服务端进入CLOSED状态,完成四次挥手
13.AF的线程是怎么管理的。你在项目中是怎么使用线程的?
AFNetWorking的源码读过没有,具体说一下实现流程
(https://www.jianshu.com/p/856f0e26279d)AFN为什么添加一条常驻线程?
1.AFN 的做法是把网络请求的发起和解析都放在同一个子线程中进行,但由于子线程默认不开启 runloop,它会向一个 C语言程序那样在运行完所有代码后退出线程。而网络请求是异步的,这会导致获取到请求数据时,线程已经退出,代理方法没有机会执行。因此,AFN 的做法是使用一个 runloop 来保证线程不死。然而频繁的创建线程并启动runloop肯定会造成内存泄露(runloop 无法停止.线程无法退出),所以AFN就创建了一个单例线程,并且保证线程不退出
2.开辟线程请求网络数据,如果没有常住线程的话,就会每次请求网络就去开辟线程,完成之后销毁开辟线程,这样就造成资源的浪费,开辟一条常住线程,就可以避免这种浪费,我们可以在每次的网络请求都添加到这条线程
14.NSURLSession 与NSURLConnection有什么不同,NSURLSession的好处是什么?
①NSURLSession在处理下载做了优化,不再像NSURLConnection一样,NSURLConnection下载文件时,先是将整个文件下载到内存,然后再写入到沙盒,如果文件比较大,就会出现内存暴涨的情况 而使用NSURLSessionUploadTask下载文件,会默认下载到沙盒中的tem文件中,不会出现内存暴涨的情况,但是在下载完成后会把tem中的临时文件删除,需要在初始化任务方法时,在completionHandler回调中增加保存文件的代码。②断点续传的方式 (https://www.jianshu.com/p/056b1817d25a)
③NSURLConnection发起请求后,这条线程并不能随风而去,而需要一直处于等待回调的状态。NSURLSession发起的请求,不再需要在当前线程进行代理方法的回调!可以指定回调的delegateQueue,这样我们就不用为了等待代理回调方法而苦苦保活线程(为什么AFNetworking2.0需要一条常驻线程而3.0不需要了 https://www.jianshu.com/p/b5c27669e2c1)
15.在网络请求的时候有没有用过缓存,你要怎么去实现缓存?
16.在使用AFNetWorking的时候你是直接用还是二次封装,二次封装你是怎么做的?
二次封装。首先创建一个基础类,用于转发AFN的block。将自己所需的基础配置写好。这里可以设计post。get,上传和下载的通用接口。这样在其他地方就可以直接用了。我这边会写一个协议将成功和失败的回调转发出来,然后在实现了协议的地方就可以回调。这样可以把网络操作集中起来。对于一些特定的网络请求可以调用前面的基础类,实现更高程度的封装
17.在你使用的众多第三方库中,你觉得哪个对你来说印象深刻,使用的时候需要注意什么?遇到过什么问题没有,怎么解决?看过哪些源码,讲讲思路(SD、YY、AFN、MJ等)
SDWebImage的实现原理
1.从内存(字典)中找图片(当这个图片在本次使用程序的过程中已经被加载过),找到直接使用。
2.从沙盒中找(当这个图片在之前使用程序的过程中被加载过),找到使用,缓存到内存中。
3.从网络上获取,使用,缓存到内存,缓存到沙盒FMDB的详细使用
https://blog.csdn.net/weixin_39339407/article/details/81699267在集成第三方sdk的时候-objc这个有什么用途?
https://blog.csdn.net/wangzeqivip/article/details/40837715
18.存一个通讯录,包括增删改查,用什么数据结构?
CNContact\CNMutableContact :https://www.cnblogs.com/jiwangbujiu/p/5467302.html
iOS通讯录总结:https://www.jianshu.com/p/2684bffcf827
19.iOS编译过程做了哪些事情?
https://www.jianshu.com/p/3c51a42b87a6
20.什么时候会调用dealloc方法?
alloc是申请内存,dealloc就是释放内存;dealloc是系统调的,当当前类所持有的所有对象都释放了就会调用。比如说vc里面,所以你vc里面存在循环引用,dealloc就不会调用;循环引用会占用内存(就是那块内存就一直被占用了),然后内存累积太多就会被系统的看门狗杀死,奔溃一般很少
iOS 在 ARC 环境下 dealloc 的使用、理解误区:https://www.2cto.com/kf/201405/299286.html
iOS中造成dealloc不调用的原因:https://www.jianshu.com/p/ae7378a36739
3.场景问题解答
1.假如Controller太臃肿,如何优化?
2.当app越做越大时, 会发现App冷启动时速度很慢, 你有没有遇到过? 你是怎么优化的?
一般而言,启动时间是指从用户点击 APP 那一刻开始到用户看到第一个界面这中间的时间。我们进行优化的时候,我们将启动时间分为 pre-main 时间和 main 函数到第一个界面渲染完成时间这两个部分。大家都知道 APP 的入口是 main 函数,在 main 之前,我们自己的代码是不会执行的。而进入到 main 函数以后,我们的代码都是从didFinishLaunchingWithOptions开始执行的,所以很明显,优化这两部分的思路是不一样的。为了方便起见,我们将 pre-main 时间成为 t1 时间,而将main 函数到第一个界面渲染完成这段时间称为 t2 时间。 然后用profile 工具来分析出哪些代码是耗时的
3.造成TableView的卡顿原因以及如何解决优化TableView?
1.最常用的就是cell的重用, 注册重用标识符
如果不重用cell时,每当一个cell显示到屏幕上时,就会重新创建一个新的cell;如果有很多数据的时候,就会堆积很多cell;如果重用cell,为cell创建一个ID,每当需要显示cell 的时候都会先去缓冲池中寻找可循环利用的cell,如果没有再重新创建cell2.避免cell的重新布局
cell的布局填充等操作比较耗时,一般创建时就布局好,如可以将cell单独放到一个自定义类,初始化时就布局好3.提前计算并缓存cell的属性及内容
当我们创建cell的数据源方法时,编译器并不是先创建cell再定cell的高度
而是先根据内容一次确定每一个cell的高度,高度确定后,再创建要显示的cell。滚动时,每当cell进入凭虚都会计算高度,提前估算高度告诉编译器,编译器知道高度后,紧接着就会创建cell,这时再调用高度的具体计算方法,这样可以方式浪费时间去计算显示以外的cell4.减少cell中控件的数量
尽量使cell得布局大致相同,不同风格的cell可以使用不同的重用标识符,初始化时添加控件,不适用的可以先隐藏5.缓存行高:
estimatedHeightForRow不能和HeightForRow里面的layoutIfNeed同时存在,这两者同时存在才会出现“窜动”的bug。所以我的建议是:只要是固定行高就写预估行高来减少行高调用次数提升性能。如果是动态行高就不要写预估方法了,用一个行高的缓存字典来减少代码的调用次数即可
http://www.cocoachina.com/ios/20150518/11854.html6.不要使用ClearColor,无背景色,透明度也不要设置为0
渲染耗时比较长7.使用局部更新,尽量避免全局更新
如果只是更新某组的话,使用reloadSection进行局部更新8.加载网络数据下载图片时,使用异步加载并缓存
9.不要实现无用的代理方法,tableView只遵守两个协议
10.预渲染图像
当新的图像出现时,仍然会有短暂的停顿现象。解决的办法就是在bitmap context里先将其画一遍,导出成UIImage对象,然后再绘制到屏幕;
避免离屏渲染,尽量避免使用 layer 的 border、corner、shadow、mask 等技术备注-iOS 保持界面流畅的技巧:https://blog.ibireme.com/2015/11/12/smooth_user_interfaces_for_ios/
备注-iOS总体性能优化技巧:https://www.jianshu.com/p/02db934bab29
4.简述一下你的APP中你觉得亮眼的功能,为什么觉得写得好?
可以根据实际情况讲一些自己封装或者优化用了不错的技术等等...
5.iOS 纯代码、xib、storyboard的选择?
storyboard可用于简单的逻辑页面间跳转,开发比较块;但是SB对于逻辑项目比较复杂的时候,开发起来比较慢。不适合多人合作开发;也不利于版本的梗系和后期的维护。使用sb在项目变异编译的时候,也都会直接加载到内存中,造成内存的浪费;
xib 可以在一些例如 cell 或者一些比较简单的 View 中使用,好处与坏处都和 storyboard 差不多;
纯代码可用于编辑复杂逻辑界面,也易于维护
6.项目中网络层如何做安全处理?
7.怎么防止别人反编译你的app?
8.容错处理你们一般是注意哪些?
在团队协作开发当中,由于每个团队成员的水平不一,很难控制代码的质量,保证代码的健壮性,经常会发生由于后台返回异常数据造成app崩溃闪退的情况,为了避免这样的情况项目中做一些容错处理,显得格外重要,极大程度上降低了因为数据容错不到位产生崩溃闪退的概率。例如:1.字典、2.数组、3.野指针、4.NSNull
备注:如果项目开始容错处理没做?如何防止拦截潜在的崩溃?
- 例如:
1.category给类添加方法用来替换掉原本存在潜在崩溃的方法
2.利用runtime方法交换技术,将系统方法替换成类添加的新方法
3.利用异常的捕获来防止程序的崩溃,并且进行相应的处理- 总结:
1.不要过分相信服务器返回的数据会永远的正确
2.在对数据处理上,要进行容错处理,进行相应判断之后再处理数据,这是一个良好的编程习惯
9.在适配 iOS 11时, 经常出现的问题都有哪些? 以及你是怎么解决的?
适配点一:项目中使用状态栏中图标判断当前网络的具体状态
此时可以看到运行崩溃了,因为从iPhone X取出来之后只有view层级的信息,所以采用以下方法确定2G/3G/4G
NSArray *typeStrings2G = @[CTRadioAccessTechnologyEdge,
CTRadioAccessTechnologyGPRS,
CTRadioAccessTechnologyCDMA1x];
NSArray *typeStrings3G = @[CTRadioAccessTechnologyHSDPA,
CTRadioAccessTechnologyWCDMA,
CTRadioAccessTechnologyHSUPA,
CTRadioAccessTechnologyCDMAEVDORev0,
CTRadioAccessTechnologyCDMAEVDORevA,
CTRadioAccessTechnologyCDMAEVDORevB,
CTRadioAccessTechnologyeHRPD];
NSArray *typeStrings4G = @[CTRadioAccessTechnologyLTE];
// 该 API 在 iOS7 以上系统才有效
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
CTTelephonyNetworkInfo *teleInfo= [[CTTelephonyNetworkInfo alloc] init];
NSString *accessString = teleInfo.currentRadioAccessTechnology;
if ([typeStrings4G containsObject:accessString]) {
NSLog(@"4G网络");
} else if ([typeStrings3G containsObject:accessString]) {
NSLog(@"3G网络");
} else if ([typeStrings2G containsObject:accessString]) {
NSLog(@"2G网络");
} else {
NSLog(@"未知网络");
}
} else {
NSLog(@"未知网络");
}
适配点二:解决这个问题后项目跑起来发现,整个app界面上下各空出大概40pt的高度.造成这个的原因是启动图使用 Launch Images Source 设置的时候没有勾选并设置对应的图片.
但是即使按照上面的操作进行之后,会发现底部 UITabBar 依旧是高出一些高度,查看层级关系后发现,同样是由于安全区的原因,UITabBar 高度由49pt变成了83pt,因此这里也要对iPhone X 及其模拟器进行适配适配点三:iPhone X 只有 faceID,没有touchID,如果in的应用有使用到 touchID 解锁的地方,这里要根据机型进行相应的适配
适配点四: iPhone X更大的坑是屏幕的适配Safe area
10.如何自己高效实现NSUserDefault?
数据量一大读取成本就高,敏感数据容易被破解,因为NSUserDefault实际上是明文存在 plist 中的,所以建议用户安全相关的(如 token)尽量不要放在 UserDefault 中,即使要存也最好做一次加密再存,最好的方式是存在 Keychain 中。UserDefault 更适合存一些轻量的数据,如当前版本(可用来做检测更新以及展示欢迎页或其他逻辑)。建议使用 Sqlite 或其他数据存储方式
11.一般开始做一个项目,你的架构是如何思考的?
4.算法题
1.A和b不用中间变量怎么实现交换
使用位运算可以实现;https://blog.csdn.net/j8121/article/details/51926438#
5.非技术问题
1.自我介绍
面试官最希望知道的是求职者能否胜任工作,包括:最强的技能、最深入研究的知识领域、个性中最积极的部分、做过的最成功的事,主要的成就等
2.你认为自己的技术能力怎么样?
(保持高度自信)技术中等吧,我正努力提升自己的技术
3.你们开发APP的周期是多久?
一般4个月;团队进行模块化分工
4.三年工作中有没有去阅读过第三方库的源码?
阅读过,看过AF、SD;平时有时间也会去研究一些好的Demo,比如SD
5.为什么做iOS?没有考虑别的编程语言?
喜欢iOS,对苹果产品也很深的兴趣,想有针对性的使用学习;考虑过其他的编程语言,喜欢多学习一些,技多不压身,努力成为一个全面的高级开发者
6.在iOS上对自己的职业规划有什么打算?
先努力往这个领域继续深入研究挖掘,成为一个高级开发者;同时也多关注学习后台、前端、安卓等技术,努力在未来成为一个全栈工作师或者架构师
7.为什么离职?
寻求更大突破发展、 原来公司管理有问题、和自己的规划相冲突
- 你对加班的是什么看法?
这个问题并不是非要让你加班,只是想测试你是否愿意为公司奉献。参考回答:如果是工作需要我会义不容辞加班,可以全身心的投入工作。同时,我也会提高工作效率,减少不必要的加班
9.如果公司强制996,你有什么心里话要对老板说吗?
没什么话啊,这个要看个人是否能够接受。如果你也认同,那就好好工作。其实真正有效的解决方法并不是努力加班加点,而正好相反:工作更少的时间。更少的工作时间,更高的工作效率才是我们应该掌握的。疲劳的时候工作让你产出值降低,你需要花越来越多的时间来解决问题,然后很快你就会发现你完全在浪费时间。持续长时间的工作会让你难以集中注意,因为你很快就精疲力尽了
- 如果让你当总监,你会怎么带领你的团队?
基本要素:明确公司的业务及产品,提炼出能解决当下市场问题的需求
明确定位目标用户,提炼出高资质客户做一整份详细的规划(实操):
1.明确分工:固定角色模块化负责
2.确定目标:制定长期目标及阶段性任务与时间
3.定期沟通:定期时间进行成员交流,汇报进度、遇到问题及解决方案
4.团队建设:建设高效、氛围和睦的团队,团队规范化,完善奖励机制
11.面试后如何复盘?
6.反问面试官的问题(你还有什么问题要问我的吗?)
1.职位空缺的原因?(上个员工为什么离职)
2.公司如何保证人才不流失?
3.公司对新入公司的员工有没有培训或者阶段性总结交流?
4.贵公司的晋升机制是什么样的?
5.试用期时间和通过试用期的标准?
6.公司近期的目标和未来的战略目标