IOS面试:基础题库(上)
原创:知识点总结性文章
创作不易,请珍惜,之后会持续更新,不断完善
个人比较喜欢做笔记和写总结,毕竟好记性不如烂笔头哈哈,这些文章记录了我的IOS成长历程,希望能与大家一起进步
温馨提示:由于简书不支持目录跳转,大家可通过command + F 输入目录标题后迅速寻找到你所需要的内容
目录
- 宏观题
- 一、KVO
- 二、Runtime
- 三、网络
- 四、多线程
- 五、Block
- 六、OC对象
- 七、Category
- 八、内存管理
- 九、RunLoop
- 十、View
- 十一、通知和委托
- 十二、性能优化和安全
- 十三、框架和架构
- 十四、Swift
- 十五、图像音视频
- 十六、本地缓存
- 十七、数据结构和算法
- 十八、其他系统框架
- 十九、设计模式
宏观题
1、谈安卓与苹果的优缺点
- 苹果系统优点是左右流畅,软件多,界面华丽,图标统一,很美观;缺点是系统封闭,不允许用户过多的个性化设置,而且只能在苹果手机上用。
- 安卓系统优点是开放,可以自己扩展的东西很多,支持的硬件也多,各个价位的手机都有;缺点就是软件太杂乱,兼容性有问题,图标混乱不美观。
- iOS的确比android流畅,这仅仅体现在较大软件切换时,其他差不多流畅。
- iOS系统更新没有android那么频繁,爱体验的人会选安卓,那些怕烦的会选iOS。
2、简单说一下APP的启 动过程,从main文件开始说起
有storyboard情况下:
1.main
函数
2.UIApplicationMain
a、创建UIApplication
对象;
b、创建UIApplication
的delegate
对象
3.根据Info plist
获得最主要story board
的文件名, 加载最主要的storyboard
(有launch storyboard
)
a、创建UIWindow;
b、创建和设置UIWindow
的rootViewController;
c、显示窗口
没有storyboard情况下:
1.main
函数
2.UIApplicationMain
a、创建UIApplication
对象;
b、创建UIApplication
的delegate
对象
3.delegate
对象开始处理(监听)系统事件(没有storyboard
)
a、程序启动完毕的时候,就会调用代理的application:didFinishI aunchingWithOptions:
方法
b、在application:didFinishLaunchingWithOptions:
中创建UIWindow
c、创建和设置UIWindow
的rootViewController;
d、显示窗口
3、在提交苹果审核时,遇到哪些问题被拒绝,对于被拒绝的问题是如何处理的?
app中有虚拟物品交易,但是没走内购导致被拒。
音频类App或者使用到音频相关的app,因为版权问题而被拒。
App出现必闪退而被拒。
4、iOS应用程序的状态有哪些?
Not running
未运行:应用还没有启动,或者应用正在运行但是途中被系统停止
Inactive
未激活:应用正在前台运行但是不接收事件,(也许正在执行其他代码)。一般当应用要从一个状态切换到另一个不同状态时,中途过度会短暂停留在此状态。唯一在此状态停留事件较长的情况是:当用户锁屏时,或者系统提示用户去响应某些(如来电,有未读短信)事件的时候。
Active
激活:程序在前台运行而且接收到了事件。这也是前台的一个正常的模式。
Backgroud
后台:程序在后台而且能执行代码,大多数程序进入这个状态后会在在这个状态上停留一会,时间到之后会进入挂起状态(Suspended
)。有的程序经过特殊的请求后可以长期处于Backgroud
状态。如果一个程序要求启动时直接进入后台运行,这样的应用会直接从not running
状态直接进入background
状态,中途不会经过inactive
状态。
Suspended
挂起:程序在后台不能执行代码。系统会自动把程序变成这个状态而且不会发出通知。当挂起时,程序还是停留在内存中的,当系统内存低时,系统就把挂起的程序清除掉,为前台程序提供更多的内存。
刚启动时
application:didFinishLaunchingWithOptions:
applicationDidBecomeActive:
进入后台时
applicationWillResignActive:
applicationDidEnterBackground:
进入前台时
applicationWillEnterForeground:
applicationDidBecomeActive:
5、Swift是面向对象还是函数式的编程语言?
Swift 既是面向对象的,又是函数式的编程语言。说Swift是面向对象的语言,是因为Swift支持类的封装、继承、和多态。说Swift是函数式编程语言,是因为Swift支持map
, reduce
, filter
这类去除中间状态、数学函数式的方法,更加强调运算结果而不是中间过程。
6、请说明并比较Swift语言中的-些关键词: Open, Public, Internal, File-private, Private
Swift 有五个级别的访问控制权限,从高到底依次为比如Open, Public, Intemal, File-private, Private
。
他们遵循的基本原则是:
高级别的变量不允许被定义为低级别变量的成员变量。比如一个private
的class
中不能含有public
的String
。反之,低级别的变量却可以定义在高级别的变量中。比如public
的class
中可以含有private
的Int
。
Open
具备最高的访问权限。其修饰的类和方法可以在任意Module
中被访问和重写;
Public
的权限仅次于Open
。与Open
唯一的区别在于它修饰的对象可以在任意Module中被访问,但不能重写。
Intermal
是默认的权限。它表示只能在当前定义的Module
中访问和重写,它可以被一个Module
中的多个文件访问,但不可以被其他的Module
中被访问。
File-pivate
其被修饰的对象只能在当前文件中被使用。例如它可以被一个文件中的class
, extension
, struct
共同使用。
Private
是最低的访问权限。它的对象只能在定义的作用域内使用。离开了这个作用域,即使是同一个文件中的其他作用域,也无法访问。
7、编译过程做了哪些事情?
C++
, Objective C
都是编译语言。编译语言在执行的时候,必须先通过编译器生成机器码,机器码可以直接在CPU上执行,所以执行效率较高。
iOS开发目前的常用语言是: Objctive
和Swift
。二者都是编译语言,换句话说都是需要编译才能执行的。二者的编译都是依赖于Clang
+LLVM
。
iOS编译:不管是OC还是Swift,都是采用Clang
作为编译器前端,LLVM(Low level vritual machine)
作为编译器后端。
编译器前端的任务是进行:语法分析,语义分析,生成中间代码(intermediate representation)
。在这个过程中,会进行类型检查, 如果发现错误或者警告会标注出来在哪一行。
编译器后端会进行机器无关的代码优化,生成机器语言,并且进行机器相关的代码优化。
LLVM
机器码生成器会针对不同的架构,比如arm64
等生成不同的机器码。
编译各个m
文件,使用CompileC
和clang
命令。
8、 C和Objective c如何混用
objc
的编译器处理后缀为m
的文件时,可以识别obj-c
和c
的代码,处理mm
文件可以识别objc
,c
,c++
代码,但cpp
文件必须只能用c/c++
代码,而且cpp
文件include
的头文件中。
9、请解释一下启动画面 (Launch Images)
启动应用程序后,进入主功能界面前会有一张图片或一段动画效果,停留数秒钟后消失。这张图片或这段动画效果我们称之为应用的启动画面。
由于启动画面在每次打开应用时都会出现,并且停留很短的时间,就像闪现的效果一样,所以也有人把启动画面称之为闪屏。
从用户体验的角度考虑,产品应当尽可能快的让用户进入程序并进行功能操作。如此看来,启动画面就是多余的存在。
但是,应用程序本质上是由多种代码命令和数据组合而成的。启动应用程序的过程实质上是运行代码和数据读取的过程,而这个过程是需要一定时间的。
与其给用户看代码运行的过程,不如给用户展示图片,这也是用户体验。
10、AppDelegate扮演着什么样的角色?
创建应用程序之后,默认有AppDelegate
文件 。AppDelegate
为整 个应用的一个代理,提供程序启动、退出等类似监控的接口,控制着应用的生命周期。
11、iOS应用开发流程。
注册APP ID
注册成为苹果开发者
创建开发证书、发布证书
开发
真机调试
打包和发布
等待审核
上线
一、KVO
1、实现原理
KV0
是基于runtime
机制实现的。当某个类的属性对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的setter
方法。派生类在被重写的setter
方法内实现真正的通知机制。
如果原类为Person
, 那么生成的派生类名为NSKVONotifying_ Person
每个类对象中都有一个isa
指针指向当前类,当一个类对象的第一次被观察, 那么系统会偷偷将isa
指针指向动态生成的派生类,从而在给被监控属性赋值时,执行的是派生类的setter
方法。
键值观察通知依赖于NSObject
的两个方法: willChangeValueForKey:
和didchangevluefoprkey:
。在一个被观察属性发生改变之前, willChangeValueForKey:
一定会被调用,这就会记录旧的值。
而当改变发生后,didChangeValueForKey:
会被调用,
继而observeValueForKey:ofObjct:change :context:
也会被调用。
{
// pre setting code here
[self willChangeValueForKey: key];
(*imp)(self, _cmd, val);
// post setting code here
[self didChangeValueForKey: key];
}
2、哪些情况下使用kvo会崩溃,怎么防护崩溃
-
KVO
的被观察者dealloc
时仍然注册着KVO
导致的crash
-
KVO
注册观察者与移除观察者次数不匹配,比如重复注册,多次移除
3、如何手动触发KVO?
- 手动调用
willChangeValueForKey:
和`didChangeValueForKey: -
KVC
会触发KVO
,也会调用重写的set
方法 - 直接修改成员变量不会触发
KVO
,因为直接修改成员变量并没有走set
方法
4、KVO的观察者如果为weak,会有什么影响?
set
方法实际执行的是父类的 willchangge
, setvalue
以及didchangge
方法。 如果为weak
,可能导致观察者被释放,而无法监测到值的变更。
5、什么是KVC和KVO?
KVO:键值监听,观察某一属性的方法
KVC:键值编码,是一种间接访问对象的属性。
KVC(Key-Value-Coding)
内部的实现:一个对象在调用setValue
的时候,
键值编码是一种间接访问对象的属性,使用字符串来标识属性,而不是通过调用存取方法,直接通过实例变量访问的机制。
KVC
的缺点:一旦使用 KVC
你的编译器无法检查出错误,即不会对设置的键、键路径进行错误检查, 且执行效率要低于合成存取器方法和自定的setter
和 getter
方法。因为使用 KVC
键值编码,它必须先解析字符串,然后在设置或者访问对象的实例变量。
KVO (Key-Value- Observing) :
当观察者为一个对象的属性进行了注册,被观察对象的isa指针被修改的时候,isa指针就会指向一个中间类,而不是真实的类。所以isa指针其实不需要指向实例对象真实的类。
键值观察机制是一种能使得对象获取到其他对象属性变化的通知 ,极大的简化了代码。
实现 KVO 键值观察模式,被观察的对象必须使用 KVC 键值编码来修 改它的实例变量,这样才能被观察者观察到。因此,KVC是KVO的基础。
6、KVC和KV0的keyPath一定是属性么?
keypath
就是属性链式访问
KVC
支持实例变量,KV0
只能手动设定实例变量的KV0
实现监听。
7、如何给一个对象的私有属性赋值?
利用KVC即键值编码来给对象的私有属性赋值。
二、Runtime
1、介绍下runtime的内存模型(isa、对象、类、metaclass、结构体的存储信息等)
struct objc_object {
private:
isa_t isa;
}
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
};
2、为什么要设计metaclass
通过meta-class
创建类对象
3、消息发送,消息转发机制和其他语言的消息机制优劣对比
-
objc_msgSend
流程: 判断receiver
是否为nil
,获取isa
,cache
查找,lookUpImpOrForward
->method list
查找(线性或者二分查找),按照继承链(superclass)
查找,走动态解析; - 动态解析:
resolveMethod
,再走method list
查找,按照继承链(superclass)
查找,走消息转发; - 消息转发:
forwardingTargetForSelector
转发到其他对象,重复走上述的objc_msgSend
流程。 - 再走
methodSignatureForSelector:
方法 -> 随后走forwardInvocation:
方法。
4、super
struct objc_super {
/// Specifies an instance of a class.
__unsafe_unretained _Nonnull id receiver;
/// Specifies the particular superclass of the instance to message.
__unsafe_unretained _Nonnull Class super_class;
#endif
/* super_class is the first class to search */
};
objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...);
5、Runtime用处
- KVC
- OC动态性由runtime支撑和实现
- 关联对象(Objective-C Associated Objects)给分类增加属性
- 方法魔法(Method Swizzling)方法添加和替换和KVO实现
- 消息转发(热更新)解决Bug(JSPatch)
- 实现NSCoding的自动归档和自动解档
- 实现字典和模型的自动转换(MJExtension)
6、给一个对象发消息,中间过程是怎样的?
根据isa
查找(缓存,继承链) -> 动态解析(自身方法实现) -> 消息转发(转发、方法签名、invoke
) -> 崩溃not recognise
7、设计一个方案,在消息转发的阶段中统一处理掉找不到方法的这种crash
resolveMethod
中通过runtime
增加方法
8、什么是动态绑定?
在编译时,方法的调用并不和代码绑定在一起,只有在消实发送出来之后,才确定消息的接收者和被调用的方法。
9、我们说的oc是动态运行时语言是什么意思?
主要是将数据类型的确定由编译时,推迟到了运行时。这个问题其实浅涉及到两个概念,运行时和多态。
简单来说,运行时机制使我们直到运行时才去决定一个对象的类别,以及调用该类别对象指定方法。
多态:不同对象以自己的方式响应相同的消息的能力叫做多态。意思就是假设生物类(life)
都用有一个相同的方法-eat;
那人类属于生物,猪也属于生物,都继承了life
后,实现各自的eat
,但是调用是我们只需调用各自的eat
方法。也就是不同的对象以自己的方式响应了相同的消息(响应了eat
这个选择器)。因此也可以说, 运行时机制是多态的基础。在OC中动态类型id
是实现多态的一种方式,id
是一个独特的数据类型,可以转换为任何数据类型。
10、响应者链
响应者对象指的是有响应和处理事件能力的对象。
响应者链就是由一系列的响应者对象构成的一个层次结构。
UIResponder
是所有响应对象的基类,在UIResponder
类中定义了处理上述各种事件的接口。我们熟悉的UIApplication
、UIViewController
、 UIWindow
和所有继承自UIView
的UIKit
类都直接或间接的继承自UIResponder
,所以它们的实例都是可以构成响应者链的响应者对象。
响应者链有以下特点:
1、响应者链通常是由视图(UIView)
构成的;
2、一个视图的下一个响应者是它视图控制器(UIViewController)
(如果有的话),然后再转给它的父视图(Super View)
;
3、视图控制器(如果有的话)的下一个响应者为其管理的视图的父视图;
4、单例的窗口(UIWindow)
的内容视图将指向窗口本身作为它的下一个响应者
5、单例的应用(UIApplication)
是一个响应者 链的终点,它的下一个响应者指向nil
,以结束整个循环。
11、runtime怎么添加属性、方法等
给系统的类添加属性的时候可以使用runtime
动态添加属性、方法。
本质: 动态添加属性就是让某个属性与对象产生关联。
class_ addIvar
class_ addMethod
class_ addProperty
class_ addProtocol
class_ replaceProperty
12、runtime如何实现weak属性?
weak
策略表明该属性定义了一种非拥有关系(nonowning relationship
)。为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。此特质同assign
类似,然而在属性所指的对象遭到摧毁时,属性值也会清空(nil)
。
runtime
对注册的类,会进行布局,会将weak
对象放入一个hash
表中。用weak
指向的对象内存地址作为key
,当此对象的引用计数为0的时候会调用对象的dealloc
方法,假设weak
指向的对象内存地址是a
,那么就会以a
为key
,在这个weak hash
表中搜索,找到所有以a
为key
的weak
对象,从而设置为nil
。
13、使用runtime Associate方法关联的对象,需要在主对象dealloc的时候释放么?
被关联的对象在生命周期内要比对象本身释放的晚很多,它们会在被NSObject -dealloc
调用的object_ _dispose
方法中释放。
14、_ objc_ msgForward函数是做什么的?直接调用它将会发生什么?
_objc. _msgForward
是IMP
类型,用于消息转发的: 当向一个对象发送一条消息,但它并没有实现的时候,_ objc. msgForward
会尝试做消息转发。
直接调用_ _objc_ msgForward
是非常危险的事,这是把双刃刀,如果用不好会直接导致程序Crash
,但是如果用得好,能做很多非常酷的事。
15、简述下Objective-C中调用方法的过程(runtime)
Objective-C
是动态语言,每个方法在运行时会被动态转为消息发送,即: objc_ msgSend(receiver,selector)
整个过程介绍如下:
objc
在向一个对象发送消息时,runtime
库会根据对象的isa
指针找到该对象实际所属的类。然后在该类中的方法列表以及其父类方法列表中寻找方法运行。如果在最顶层的父类(一般也就NSObjcct
)中依然找不到相应的方法时,程序在运行时会挂掉并抛出异常unrecognized selector sent to XXX
。但是在这之前,objc
的运行时会给出三次拯救程序崩溃的机会。
补充说明: Runtime
铸就了0bjective-C
是动态语言的特性,使得C语言具备了面向对象的特性,在程序运行期创建,检查修改类、对象及其对应的方法,这些操作都可以使用runtime
中的对应方法实现。
16、什么是method swizling?
简单说就是进行方法交换
在Objcctive-C
中调用一个方法,其实是向一个对象发送消息, 查找消息的唯一依据是selector
的名字。利用objctive-C
的动态特性,可以实现在运行时偷换sclector
对应的方法实现,达到给方法挂钩的目的。
每个类都有一个方法列表,存放着方法的名字和方法实现的映射关系, selector
的本质其实就是方法名,IMP
有点类似函数指针,指向具体的Method
实现,通过selector
就可以找到对应的IMP
。
交换方法的几种实现方式:
利用method_ exchangelmplementations
交换两个方法的实现
利用class replaceMethod
替换方法的实现
利用method_ setlmplementation
来直接设置某个方法的IMP
17、什么时候会报unrecognized selector的异常?
当调用该对象上某个方法,而该对象上没有实现这个方法的时候,可以通过“消息转发’进行解决。objc
是动态语言,每个方法在运行时会被动态转为消息发送,即: objc_ msgSend(receiver, selector)
。objc
在向一个对象发送消息时,runtime
库会根据对象的isa
指针找到该对象实际所属的类,然后在该类中的方法列表以及其父类方法列表中寻找方法运行,如果在最顶层的父类中依然找不到相应的方法时,程序在运行时会挂掉并抛出异常unrecognized selector sent to XXX
。
18、performSelector:withObject:afterDelay:内部大概是怎么实现的,有什么注意事项么?
创建一个定时器时间结束后系统会使用runtime
通过方法名称(Selector
本质就是方法名称)去方法列表中找到对应的方法实现并调用方法。调用performSelctor:withObject:afterDelay:
方法时先判断希望调用的方法是否存在respondsToSelector:
。这个方法是异步方法,必须在主线程调用,在子线程调用永远不会调用到想调用的方法。
19、class_copyIvarList & class_copyPropertyList区别
class_copyPropertyList:
通过类名获得类的属性变量。获得的是由@property
修饰过的变量。
class_copyIvarList:
通过类名获得类的实例变量。获得的是class_copyPropertyList
修饰的以及在m
文件的中@implementation
内定义的变量。
20、load、initialize方法的区别什么?在继承关系中他们有什么区别?
+load:在这个文件被程序装载时调用。只要是在Compile Sources
中出现的文件总是会被装载,这与这个类是否被用到无关,因此+load
方法总是在main
函数之前调用。调用方式并不是采用runtime
的objc_msgSend
方式调用的,而是直接采用函数的内存地址直接调用的; 多个类的load
调用顺序,是依赖于compile sources
中的文件顺序决定的,根据文件从上到下的顺序调用,子类和父类同时实现load
的方法时,父类的方法先被调用本类与category
的调用顺序是,优先调用本类的(注意:category
是在最后被装载的) 。load是被动调用的,在类装载时调用的。
initialize:当类或子类第一次收到消息时被调用(即:静态方法或实例方法第一次被调用,也就是这个类第一次被用到的时候),方式是通过runtime
的objc_msgSend
的方式调用的,此时所有的类都已经装载完毕;子类和父类同时实现initialize
,父类的先被调用,然后调用子类的;本类与category
同时实现initialize
,category
会覆盖本类的方法,只调用category
的initialize
一次(这也说明initialize
的调用方式采用objc_msgSend
的方式调用的);initialize
是主动调用的,只有当类第一次被用到的时候才会触发。
三、网络
1、四层结构
应用层 -> http, DNS, ftp
-> DNS(domain name system)
传输层 -> tcp, UDP
网络层 -> ip
-> ARP(address resolution protocol)
链路层
2、请求报文 响应报文
请求报文:请求方法、请求uri、协议版本、可选的请求首部、内容实体
响应报文:协议版本、状态码、解释状态码的原因短语、可选的请求首部、内容实体
3、url统一资源标识符
http:// user:pass@ www.example.com: 80 /dir/index.html ?uid=1#ch
协议 登录信息 服务器地址 端口 层次的路径 查询字符串
4、请求方法
GET
: 获取资源
POST
: 传输实体主体
PUT
: 传输文件,不带验证机制
HEAD
: 获取报文首部
DELETE
: 删除文件
OPTIONS
: 询问支持的method
TRACE
: 追踪路径,查询发送出去的请求怎样被加工、篡改
CONNECT
: 邀请用隧道协议连接代理
5、状态码
1xx
: 信息性状态码
2xx
: 成功状态码 200、204、206
3xx
: 重定向状态码 301、302、303、304、307
4xx
: 客户端错误 400、401、403、404
5xx
: 服务端错误 500、502、503、504
6、HTTPS
http的不足
1、通信使用明文,内容可能被窃取
2、不验证通信方的身份,因此可能遭遇伪装
3、无法证明报文的完整性,所以有可能被篡改
https
= http
+ 加密 + 认证 + 完整性保护
https(ssl,tsl)的不足
1、消耗网络资源
2、消耗cpu和内存等硬件资源
7、socket连接与http连接
http连接:短连接。即客户端向服务端发送一次请求,服务端响应之后,链接即会断掉。
socket连接:长连接。即客户端一旦与服务器建立接连,便不会主动断掉。
8、什么是可扩展标记语言extensible markup language XML ?
XML指可扩展标记语言(EXtensible Markup Language
)
XML是一种标记语言,很类似HTML
XML的设计宗旨是传输数据,而非显示数据
XML标签没有被预定义。您需要自行定义标签。
XML被设计为具有自我描述性。
XML是W3C
的推荐标准。
9、XML与HTML的区别。
XML
与HTML
的设计区别是:XML
的核心是数据,其重点是数据的内容。而HTML
被设计用来显示数据,其重点是数据的显示。
XML
和HTML
语法区别:HTML
的标记不是所有的都需要成对出现,XML
则要求所有的标记必须成对出现;HTML
标记不区分大小写,XML
则大小敏感,即区分大小写。
10、HTTP协议的主要特点。
1.支持客户/服务器模式。
2.简单快速:
客户向服务器请求服务时,只需传送请求方法和路径。
请求方法常用的有GET
、HEAD
、POST
。
每种方法规定了客户与服务器联系的类型不同。
由于HTTP
协议简单,使得HTTP
服务器的程序规模小,因而通信速度很快。
3.灵活:HTTP
允许传输任意类型的数据对象。正在传输的类型由Content-Type
加以标记。
4.无连接:
无连接的含义是限制每次连接只处理一个请求。
服务器处理完客户的请求,并收到客户的应答后,即断开连接。
采用这种方式可以节省传输时间。
5.无状态:
HTTP
协议是无状态协议。
无状态是指协议对于事务处理没有记忆能力。
缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。
另一方面, 在服务器不需要先前信息时它的应答就较快。
11、TCP/UDP区别联系
TCP
---传输控制协议提供的是面向连接、可靠的字节流服务。
当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP
连接,之后才能传输数据。
TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。
UDP
---用户数据报协议,是一个简单的面向数据报的运输层协议。
UDP
不提供可靠性,它只是把应用程序传给IP
层的数据报发送出去,但是并不能保证它们能到达目的地。
由于UDP
在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。
12、socket连接和http连接的区别
http连接:http连接就是所谓的短连接,即客户端向服务器端发送一次请求,服务器端响应后连接即会断掉;
socket连接:
socket
连接就是所谓的长连接,理论上客户端和服务器端一旦建立起连接将不会主动断掉; 但是由于各种环境因素可能会导致连接断开,比如说:服务器端或客户端主机down
了,网络故障,或者两者之间长时间没有数据传输,网络防火墙可能会断开该连接以释放网络资源。
所以当一个socket
连接中没有数据的传输,那么为了维持连接需要发送心跳消息,具体心跳消息格式是开发者自 己定义的。
13、什么是TCP连接的三次握手?
握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。
14、利用Socket建立网络连接的步骤?
建立Socket
连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket
,另一个运行于服务器端,称为ServerSocket
。
套接字之间的连接过程分为三个步骤: 服务器监听,客户端请求,连接确认。
1。服务器监听:
服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,
实时监控网络状态,等待客户端的连接请求。
2。客户端请求:
指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。
为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
3。连接确认:
当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦 客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求
15、在App中混合HTML5开发App如何实现的。在App中使用HTML5的优缺点是什么?
在iOS中,通常是UIWebView
来实现,当然在iOS8以后可以使用WKWebView
来实现。有以下几种实现方法:iOS加入H5
响应比原生要慢很多,体验不太好,这是缺点。iOS加入H5
可以实现嵌入别的功能入口,可随时更改,不用更新版本就可以上线,这是最大的优点。
16、JSPatch使用了iOS的什么原理?
通过JS调用和改写0C方法最根本的原因是Objective-C
是动态语言,OC上所有方法的调用/类的生成都通过Objective-C Runtime
在运行时进行。
17、你使用过json解析方式么,他们的底层是如何处理的你了解么?
底层原理遍历字符串中的字符,最终根据格式规定的特殊字符,比如{}号, []号, :号等进行区分,{}号是一个字典的开始,[]号是一 个数组的开始, :号是字典的键和值的分水岭,最终乃是将json数据转化为字典,字典中值可能是字典,数组,或字符串而已。
18、iOS的签名机制大概是怎样的?
签名机制:
先将应用内容通过摘要算法,得到摘要
再用私钥对摘要进行加密得到密文
将源文本、密文、和私钥对应的公钥一并发布
验证流程:
查看公钥是否是私钥方的
然后用公钥对密文进行解密得到摘要
将APP用同样的摘要算法得到摘要,两个摘要进行比对,如果相等那么一切正常
以上过程只要有一步出问题就视为无效。
19、WKWebView的优点
拥有60fps
滚动刷新率
内置手势
高效的app和web信息交换通道
和Safari
相同的JavaScript
引擎
四、多线程
1、iOS开发中有多少类型的线程?分别对比
pthread
- C语言框架,跨平台,基本不用。
- 手动管理生命周期。
NSThread
-
pthread
的封装,面向对象,比较少用。 - 手动管理生命周期。
- 不太适合复杂任务,比如涉及线程状态、线程依赖、线程同步等。
GCD
- 优化应用程序以支持多核处理器,自动管理线程的生命周期,不需要编写任何线程管理代码。
- 控制起来比较麻烦,比如取消一个线程。
- 无法对任务设置优先级。
NSOperation
- 面向对象,对
gcd
的封装 - 可进行取消、暂停操作
- 配合
queue
可以对任务设置优先级
2、GCD有哪些队列,默认提供哪些队列?
队列:serial
、concurrent
、main
、global
同步异步:队列决定任务执行顺序,sync
, async
决定是否开启新线程
3、GCD有哪些方法api?
dispatch_sync
、dispatch_async
dispatch_barrier_async
、dispatch_group_async
dispatch_after
、dispatch_once
dispatch_apply
、dispatch_semaphore
4、如何实现同步,有多少方式就说多少?
group
、semaphore
、串行队列、加锁、barrier
5、dispatch_once实现原理?
系统级的信号量
6、什么情况下会死锁
禁止抢占(no preemption) :系统资源不能被强制从一个进程中退出。
持有和等待(hold and wait):一个进程可以在等待时持有系统资源。
互斥(mutual exclusion) :资源只能同时分配给一个行程,无法多个行程共享。
循环等待(circular waiting) :一系列进程互相持有其他进程所需要的资源。
7、有哪些类型的线程锁,分别介绍下作用和使用场景
- 互斥锁:线程会进入休眠状态等待被唤醒
-
pthread_mutex
互斥锁,等待锁的线程会处于休眠状态 -
NSLock
、NSRecursiveLock
是对pthread_mutex
的封装 NSConditionLock
@synchronized
-
OSSpinLock
自旋锁:线程等待锁的线程仍然占用CPU资源,即忙等 - 信号量
dispatch_semaphore
:通过dispatch_semaphore_wait
与dispatch_semaphore_signal
控制可访问线程的数量来达到同步的目的
8、属性修饰符atomic的内部实现是怎么样的? 能保证线程安全吗?
spinlock_t
,真实底层实现为mutex_t
中的os_unfair_lock
。
能保证属性自身的读写是安全的,但不能保证属性内的值读写是安全的。
9、NSOperationQueue中的maxConcurrentOperationCount默认值
-1,表示不进行限制,由NSOperationQueue
根据系统状态动态确定,支持并发操作。
10、NSTimer、CADisplayLink、dispatch_source_t 的优劣
前两者依赖runloop
执行,作为timesource
塞进mode
的集合中。
后者不依赖runloop
,系统级,可取消。
11、异步绘制过程中,将生成的image赋值给contents的这种方式,会有什么问题?
设置image
也是通过给layer.contents
赋值来实现的;iOS要求所有的UI操作都必须在主线程上完成,所以如果在异步绘制完成image
,就需要切换到主线程给contents
赋值;
12、Object C中创建线程的方法是什么?
线程创建有三种方法: 使用NSThread
创建 、使用GCD
的dispatch
、使用子类化的NSOperation
,然后将其加入NSOperationQueue;
。
13、如果在主线程中执行代码,方法是什么?
在主线程执行代码,方法是performSelectorOnMainThread
。
14、如果想延时执行代码、方法是什么?
如果想延时执行代码可以用performSelector:onThread:withObject:waitUntilDone:
。
15、线程与进程的区别和联系
进程和线程都是由操作系统所控制的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。进程和线程的主要差别在于它们是不同的操作系统资源管理方式。
进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。
线程有自己的堆栈和局部变量,但线程没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
16、NSTimer创建后,会在哪个线程运行?
用scheduledTimerWithTimeInterval
创建的,在哪个线程创建就会被加入哪个线程的RunLoop
中就运行在哪个线程。
17、dispatch_ sync 和dispatch_ async区别是什么?
dispatch_ async
:异步队列,dispatch_ async
函数会立即返回,block
会在后台异步执行。
dispatch_ sync
:同步队列,dispatch_ sync
函数不会立即返回,阻塞当前线程,等待block
同步执行完成。
18、以scheduledTimerWithTimeInterval的方式触发的timer,在滑动页面上的列表时,timer会暂停, 为什么?该如何解决?
其一是将timer
加入到NSRunloopCommonModes
中。
其二是将timer
放到另一个线程中,然后开启另一个线程的runloop
,这样可以保证与主线程互不干扰,而现在主线程正在处理页面滑动。
19、GCD执行原理?
GCD有一个底层线程池,这个池中存放的是一个个的线程。之所以称为“池”,很容易理解出这个“池”中的线程是可以重用的,当一段时间后这个线程没有被调用,这个线程就会被销毁。
注意:开多少条线程是由底层线程池决定的,池是系统自动来维护。而程序员只关心的是向队列中添加任务,队列调度即可。
如果队列中存放的是同步任务,则任务出队后,底层线程池中会提供一条线程供这 个任务执行,任务执行完毕后这条线程再回到线程池。这样队列中的任务反复调度,因为是同步的,所以当我们用currentThread
打印的时候,就是同一条线程。
如果队列中存放的是异步的任务,当任务出队后,底层线程池会提供一个线程供任务执行,因为是异步执行,队列中的任务不需等待当前任务执行完毕就可以调度下一个任务,这时底层线程池中会再次提供一个线程供第二个任务执行,执行完毕后再回到底层线程池中。
这样就对线程完成一个复用,而不需要每一个任务执行都开启新的线程,也就从而节约的系统的开销,提高了效率。
20、NSOperationQueue相对于GCD来说有哪些优点?
可以很方便的取消一个NSOperation
的执行
可以更容易的添加任务的依赖关系
提供了任务的状态: isExecuteing
, isFinished
可以通过设置maxConcurrentOperationCount
属性来控制并发任务的数量
21、请描述一下同步和异步,说说它们之间的区别。
首先,我们要明确一点,同步和异步都是在线程中使用的。在iOS开发中,比如网络请求数据时,若使用同步请求,则只有请求成功或者请求失败得到响应返回后,才能继续往下走,也就是才能访问其它资源(会阻塞了线程)。网络请求数据异步请求时,不会阻塞线程,在调用请求后,可以继续往下执行,而不用等请求有结果才能继续。
线程同步是多个线程访问同一资源时,只有当前正在访问的线程访问结束之后,其他线程才能开始访问(被阻塞)。线程异步是多个线程在访问竞争资源时,可以在空闲等待时去访问其它资源(不被阻塞)。
22、 dispatch_ barrier_ async的作用是什么?
在并行队列中,为了保持某些任务的顺序,需要等待一些任 务完成后才能继续进行,使用barrier
来等待之前任务完成,避免数据竞争等问题。
dispatch_ barrier async
函数会等待追加到Concurrent Dispatch Queue
并行队列中的操作全部执行完之后,然后再执行dispatch_ barrier _async
函数追加的处理,等dispatch_ barrier _async
追加的处理执行结束之后,Concurrent DispatchQueue
才恢复之前的动作继续执行。
23、Thread的创建分为显式和隐式两种类型
显式方式
Thread.detachNewThreadSelector(selector: toTarget: with:)
Thread.init(target: selector: object:)
隐式
object.performSelector(inBackground: with:)
object.performSelector(inBackground: afterDelay with: )
24、 iOS提供了哪些类型的线程锁(保持线程同步的方式)
NSLock
RecursiveLock
ConditionLock
信号量
pthread mutex
@synchronized
25、并发、串行、同步和异步描述
并发:多个任务同时执行
串行:一个任务执行完成后,再执行下一个任务
同步:在当前线程中执行任务,不会开启新线程
异步:在新的线程中执行任务
26、CADisplayLink和Timer
CADisplayLink
使用场合相对专一,适合做UI的不停重绘。
NSTimer
的使用范围要广泛的多,各种需要单次或者循环定时处理的任务都可以使用。
在UI相关的动画或者显示内容使用CADisplayLink
比起用NSTimer
的好处就是我们不需要再格外关心屏幕的刷新频率。
CADisplayLink
可用于自定义动画弓|擎或者视频播放的渲染。
五、Block
1、block的内部实现,结构体是什么样的?
struct Block_layout {
void *isa;
volatile int32_t flags; // contains ref count
int32_t reserved;
void (*invoke)(void *, ...);
struct Block_descriptor_1 *descriptor;
// imported variables
// 捕获对象时,编译器会增加对'variables'的内存管理方法
};
2、block是类吗,有哪些类型
OC 对象,继承自NSObject
,封装了函数调用。
NSGlobalBlock
: 在block
内部为静态或者全局变量。
NSStackBlock
: block
内部使用了auto
修饰符的都是NSStackBlock
类型
NSMallocBlock
: NSStackBlock
调用copy
得到的就是NSMallocBlock
类型。
3、block的变量截获
- 局部变量值类型捕获其值
- 对象连带修饰符一起捕获
- 对于静态变量转化为指针
- 全局变量不捕获,直接访问
-
forwarding
:指向自己的指针,不管__block
变量配置在栈上还是堆上,都能够正确地访问该变量
4、block在修改NSMutableArray,需不需要添加__block
如果是对数组内修改不需要。如果是修改数组本身,则需要。
在block
中访问的外部变量是复制过去的,即: 写操作不对原变量生效。但是你可以加上_block
来让其写操作生效。
5、block怎么进行内存管理的
自身:_Block_copy
,_Block_release
捕获变量:_Block_object_assign
, _Block_object_dispose
6、block可以用strong修饰吗
可以,与copy
一样。修饰为copy
后会对block
里面的对象retain
一次,防止里面的对象提前释放。
7、block循环引用,block分配在栈还是堆,什么 情况下block会从栈区复制到堆区?
NSConcreteStackBlock:
只用到外部局部变量、成员属性变量,且没有强指针引用的block
都是StackBlock
。StackBlock
的生命周期由系统控制的,一旦返回之后,就被系统销毁了。
NSConcreteMallocBlock:
有强指针引用或copy
修饰的成员属性引用的block
会被复制一份到堆中成为MallocBlock
,没有强指针引用即销毁, 生命周期由程序员控制。
没有用到外界变量或只用到全局变量、静态变量的block
为NSConcreteGlobalBlock
, 生命周期从创建到应用程序结束。
8、使用系统的某些block api (如UIView的block版本写动画时),是否也考虑引用循环问题?
系统的某些block api
中,如UIView
的block
版本写动画时不需要考虑。
9、block的本质是什么?为啥在block里面更改外面变量的值,要给外面的变量加_ block修饰,加_ block修饰的原理是什么?
block
多用于参数传递,代替代理方法, 有多个参数需要传递或者多个代理方法需要实现还是推荐使用代理方法。
block
是一 个0C对象,它的功能是保存代码片段预先准备好代码,并在需要的时候执行。
六、OC对象
1、OC对象
instance
对象包含 isa
以及成员变量
object_getClass(instance)
获得class
对象,其包含isa
以及instance方法
object_getClass(class)
获得meta-class
对象 ,其包含isa
以及类方法
2、isa 与 superclass
instance
里存的是真实值,class
,meta-class
则是类的描述信息
instance
的 isa
指向class
class
的 isa
指向meta-class
meta-class
的 isa
指向基类的meta-class
class
的 superclass
指向 父类的 class
; 如果没有父类,superclass
为nil
meta-class
的 superclass
指向父类的meta-calss
;
基类的meta-class
的 superclass
指向 基类的 class
,NSObject
的特殊性
3、NSString 用什么关键字?为什么
copy
,为了避免数据被污染,比如可变对它进行赋值,如果不是copy
,会导致数据变化。
4、深拷贝和浅拷贝
是否生成新的对象,即retaincount
是增加1,还是创建新的对象。
5、NSString使用copy关键字,内部是怎么实现的?
copyWithZone:
=> 推测内部进行了一次retain
6、使用NSArray 保存weak对象,会有什么问题?
没问题、保存到数组时,会进行一次强引用。
7、被id声明的对象有什么特性?
id声明的对象具有运行时的特性,即可以指向任意类型的objcetive-c
的对象。
8、常见的object- c的数据类型有那些,和C的基本数据类型有什么 区别?
object-c
的数据类型有NSString
,NSNumber
, NSArray
, NSMutableArray
, NSData
等等, 这些都是class
,创建后便是对象,而C语言的基本数据类型int
,只是一定字节的内存空间, 用于存放数值;
NSInteger
是基本数据类型,并不是NSNumber
的子类,当然也不是NSObject
的子类。NSInteger
是基本数据类型Int
或者Long
的别名,它的区别在于,NSInteger
会根据系统是32位还是64位来决定是本身是int
还是Long
。
9、对于语句NSString* obj = [NSData alloc] init]; obj在编译时和运行时分别是什么类型的对象?
编译时是NSString
的类型; 运行时是NSData
类型的对象。
10、readwrite, readonly, assign, retain, copy, nonatomic各是有什么作用?
readwrite
是可读可写特性;
readonly
是只读特性,只会生成getter
方法,不会生成setter
方法不希望属性在类外改变
assign
是赋值特性,setter
方法将传入参数赋值给实例变量
retain
表示持有特性,setter方法将传入参数先保留,再赋值,传入参数的retaincount会+1;
copy
表示赋值特性,setter
方 法将传入对象复制一份; 需要完全一份新的变量时。
nonatomic
非原子操作,决定编译器生成的setter
getter
是否是原子操作,atomic
表示多线程安全,防止在写未完成的时候被另外一个线程读取,造成数据错误。一般使用nonatomic
,访问器只是简单地返回这个值。
11、#import跟#include又什么区别,@class呢, #import<>跟#import ""又什么区别?
#import
是Objective-C
导入头文件的关键字,#include
是C/C++
导 入头文件的关键字。使用#import
头文件会自动只导入一次,不会重复导入,相当于#include
和#pragma once;
。
@class
则告诉编译器某个类的声明,当执行时,才去查看类的实现文件,可以解决头文件的相互包含问题。
#import <>
用来包含系统的头文件,#import()
用来包含用户头文件。
12、请描述下Objective-C有哪些优缺点?
Objective-C的优点:
1、Cateogies;
3、动态绑定;
6、不是一个过度复杂的C衍生语言;
7、 Objective-C与C++可混合编程
缺点:
1、不支持命名空间;
2、不支持运算符重载;
3、不支持多重继承;
4、使用动态运行时类型,所有的方法都是函数调用,所以很多编译时优化方法都用不到。
13、方法和选择器有何不同?
selector
是一个方法的名字,method
是 一个组合体,包含了名字和实现。
14、tableView的重用机制是什么?
UTTableView
通过重用单元格来达到节省内存的目的: 通过为每个单元格指定一个重用标识符(reuse Ienifir)
,即指定了单元格的种类以及当单元格滚出屏幕时,允许恢复单元格以便重用对于不同种类的单元格使用不同的ID
,对于简单的表格一个标识符就够了。
假如一个TableView
中有I0个单元格,但是屏幕上最多能显示4个,那么实际上iPhone
只是为其分配了4个单元格的内存没有分配10个,当滚动单元格时,屏幕内显示的单元格重复使用这4个内存。
15、Objective C类方法loadView和initialize的区别?
loadView
是只要类所在文件被引用就会被调用,而initialize
是在 类或者其子类的第一个方法被调用前调用。所以如果类没有被引用进项目,就不会有load
调用; 但即使类文件被引用进来,但是没有使用,那么initialize
也不会被调用。
它们的相同点在于:方法只会被调用一次。
调用的顺序: 父类(Superclass)
的方法优先于子类(SubClass)
的方法,类中的方法优先于类别(Category)
中的方法。
16、 @synthesize和@dynamic分别有什么作用?
@property
有两个对应的词, 一个是@synthesize
,一个是@dynamic
。
@synthesize
的语义是如果你没有手动实现setter
方法和getter
方法,那么编译器会自动为你加上这两个方法。
@dynamic
告诉编译器:属性的setter
与getter
方法由用户自己实现,不自动生成(当然对于readonly
的属性只需提供getter
即可)。假如一个属性被声明为@dynamic var
,然后你没有提供@setter
方法和@getter
方法编译的时候没问题,但是当程序运行到instance.var = someVar
,由于缺setter
方法会导致程序崩溃;或者当运行到someVar = instance.var
时,由于缺getter
方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。
17、在一个对象的方法里面:self.name =“object";和name =”object"有什么不同吗?
self.name = "object"
会调用对象的setName
方法,会使object
引用计数加1,
name = "object"
会直接把object
赋值给当前对象的name
属性,引用计数不增加。
18、怎么用copy关键字?
NSString
、NSArray
、NSDictionary
等等经常使用copy
关键字,是因为他们有对应的可变类型: NSMutableString
、NSMutableArray
、NSMutableDictionary
。
当属性类型为NSString
时,经常用此特质来保护其封装性,因为传递给设置方法的新值有可能指向一个NSMutableString
类的实例。这个类是NSStrng
的子类,表示一种可修改其值的字符串,此时若是不拷贝字符串,那么设置完属性之后,字符串的值就可能会在对象不知情的情况下遭人更改。
@property (copy) NSMutableArray *array;
这个写法会出什么问题?
添加, 删除,修改数组内的元素的时候程序会因为找不到对应的方法而崩溃,因为copy
就是复制一个不可变NSArray
的对象;
block
也经常使用copy
关键字, block
使用copy
是从MRC
遗留下来的“传统;
在MRC
中,方法内部的block
是在栈区的,使用copy
可以把它放到堆区
在ARC
中写不写都行: 对于block
使用copy
还是strong
效果是一样的, 但写上copy
也无伤大雅,还能时刻提醒我们编译器自动对block
进行了copy
操作。
19、objc中向一个nil对 象发送消息将会发生什么?
在Objective-C
中向nil
发送消息是完全有效的,只是在运行时不会有任何作用:
如果一个方法返回值是一个对象, 那么发送给nil
的消息将返回0(nil)
。
objc
是动态语言,每个方法在运行时会被动态转为消息发送,即:objc_ msgSend(receiver, selector)
。
20、objc中的类方法和实例方法有什么本质区别和联系?
类方法:
类方法是属于类对象的
类方法只能通过类对象调用
类方法中的self是类对象
类方法可以调用其他的类方法
类方法中不能访问成员变量
类方法中不能直接调用对象方法
实例方法:
实例方法是属于实例对象的
实例方法只能通过实例对象调用.
实例方法中的self是实例对象
实例方法中可以访问成员变量
实例方法中直接调用实例方法
实例方法中也可以调用类方法(通过类名)
21、使用nonatomic一定是线程安全的吗?
不是的。atormic
原子操作,系统会为setter方法加锁。具体使用@synchronized(self) {/code }
。nonatomic
不会为setter
方法加锁。atomic:
线程安全,需要消耗大量系统资源来为属性加锁。
22、什么是谓词?
谓词是通过NSPredicate
, 是通过给定的逻辑条件作为约束条件,完成对数据的筛选。
23、isEquel和hash的关系
isEquel
用于比较2个对象是否相等,与==
(地址比较)不一样, 可以重写isEquel
方法来进行2个对象的比较。
hash
是一个类方法,任何类都可以调用这个方法,返回的结果是一个NSInteger
值(如果两个对象相等,那么他们的hash
值一定相等,但是如果两个对象的哈希值相等是不能一定推出来这两个对象是相等的)
24、isEquel 和 isEquelToString
isEquel
比较的是2个NSObject
的方法,isEquelToString
是比较2个字符串值是否相等。isEquel
首先比较2个对象地址,如果相同就返回YES,如果不同就比较对象类型以及属性的值,一般重写isEquel
来比较2个对象。
七、Category
见下文 IOS面试:基础题库(下)