iOS面试题总结

iOS面试总结

1,cocoa touch概念:cocoa是一个框架的集合,它是一种工具,为mac和iOS应用提供了大量的API和编程环境;

2,cocoa touch中常见的API有NSString,NSArray,NSDictionary等;

3,OC动态性表现:运行时确定对象类型,运行时响应已绑定好的消息,运行时加载工程资源;

4,OC动画常用几种类型:所有动画都基于CAAnimation,有view Animation,基本动画CABasicAnimation,关键帧动画CAKeyframeAnimation,转场动画CATransition,动画组CAAnimationGroup;

5,类别和扩展,类别只能添加方法,如想添加属性需runtime实现属性的get和set方法,扩展既可增加方法和属性;

6,引用计数,MRC需自己创建且自己销毁,等到retaincount为0时系统则释放内存;ARC则系统自动管理内存,系统会在适当的时候将引用计数清空并且释放内存,且要防止对象的强引用和循环引用;

isa:是一个Class 类型的指针. 每个实例对象有个isa的指针,他指向对象的类,而Class里也有个isa的指针, 指向meteClass(元类);

7,Runtime运行时,是C语言和汇编语言写的一套的API,运行时的消息转发机制,oc底层就是runtime机智,因为oc是动态运行时语言,在运行时确定当前对象类型和所要转发的消息;可通过底层的API获取对象的成员变量,转发且运行传递的消息;底层通过获取当前变量或者消息的内存地址进行转发;

关联对象(Objective-C Associated Objects)给分类增加属性

方法魔法(Method Swizzling)方法添加和替换和KVO实现,KVO底层就是runtime监听当前属性的新值和旧值,然后转发;

消息转发(热更新)解决Bug(JSPatch)

实现NSCoding的自动归档和自动解档

实现字典和模型的自动转换(MJExtension)

Model和字典之间的转换;

8,Runloop,整个程序中所有进程的运行池,开启程序时,系统自动会为主线程分配一个Runloop去执行进程;Runloop和线程是一一对应的,每一个线程中都会有一个Runloop,如果是手动创建线程则系统不会自动分配;Runloop生命周期为,对象接受消息-等待处理-处理消息-结束;

个人理解:当前线程中所有进程的运行池,runloop和线程是一一对应的关系,每一个线程都会有一个runloop对象。当程序打开时,进入main函数,系统会自动为主线程自动创建一个runloop,并且将runloop加到自动释放池中,以便没有事件的时候自动释放对象;子线程中的runloop必须用户手动去创建,那么子线程中runloop的生命周期为线程线束时销毁;每一个应用必须有有个runloop的存在;

runloop结构中,有两个重要的成员变量,currentMode,modes,第一个保存当前的runloop的运行状态,第二个是生成runloop所创建的所有运行状态,是一数组;

mode中有Source1/Source0/Timers/Observer;分别为基于内核的消息调度,用户主动触发的事件,NSTimer,监听runloop。

Source0为用户主动触发的事件,例如touch事件,PerformSelectors调用事件

其中model中的nstiemer也可通过GCD进行创建;

Observer是监听Runloop的状态,如果当前状态下没有相关的消息发送,那么runloop进行休眠,等待有消息时再运行;

Runloop作用:1,保持程序持续运行;2,处理app中的触摸事件,定时器,seleter事件;3,节省CPU资源,没什么操作的时候会释放cpu资源;

9,NSTimer其实就是创建了一个Runloop,通过传递的事件,让Runloop去精准的判断时间并且按照时间去循环直线当前的seletor;

10,KVO观察者模式,监听对象的属性;KVC获取对象的属性或者为对象的属性赋值,也属于特殊的KVO;

11,五大内存区:栈区,堆区,全局区,常量区,代码区;

栈区一般保存局部变量,函数的参数变量,系统基本变量;

堆区保存保存用户手动创建的对象,例如通过new,alloc等创建的对象;

全局区保存全局变量和静态变量,extern修饰的变量,此变量可进行修改,并且内存生存周期为程序结束;

常量区,保存常量,例如const创建的变量,不允许修改,内存生存周期为程序结束;

代码区,保存用户书写的代码,以二进制的形式保存在内存中;

12,block,匿名函数,属于OC的一个对象,它本身也是有isa指针的;外部的基本变量如果不加__block,如果在block里边引用了此变量,那么此变量在block内部属于值传递,作用域是block开始到结束,所以不能修改其值,只能进行引用(只读操作),内部实现其实是以block参数形式传递到内部,参数值是不能修改的;如果加了block,那么它变成了指针传递,可以修改其指针指向的值;

根据Block创建的位置不同,Block有三种类型,创建的Block对象分别会存储到栈、堆、全局数据区域。

Block内部如果没有截获变量,那么当前block存储在全局区,函数调用终止block会被释放;

如果截获了变量,块儿内引用了变量,那么此block对象存在栈内,随着block块结束后会释放;

如果直接调用了block而没有分配block变量,那么它存在于栈区,因为ARC下oc变量是strong类型,但是block系统会默认将strong用copy的作用域去修饰,所以在堆中;

为什么block要用copy去修饰:copy修饰的block存放在堆中,block本身也是OC的一个对象,如果不用copy去修饰,那么当前block对象保存在栈中,栈中的对象是系统自动去销毁,所以当销毁之后下次再去引用,会造成程序崩溃,所以需要copy将其拷贝到堆中,开发人员手动管理其内存;

用strong修饰也是默认copy的行为去实现的;

__block修饰的变量保存在栈内;

__block发挥作用的原理:将栈上用__block修饰的自动变量封装成一个结构体,让其在堆上创建,以方便从栈上或堆上访问和修改同一份数据。

Delegate为什么会造成循环引用,因为两者相互持有了delegate,所以造成了循环引用,引用计数大于0,所以不能释放,必须用weak去修饰,因为weak修饰的对象引用的同时不会增加引用计数,weak是以链表的形式存在内存里边,当持有的类销毁之后,那么weak变量会自动销毁,并且清空内存置为nil。

Block为什么会造成循环引用:block也属于oc的一个对象,那么当它持有一个外部变量的时候,那么外部的对象也持有当前的block对象,所以造成了循环引用,必须有一方打破当前的循环,所以将对象变成弱引用;

防止block循环引用的方法,weak,__block修饰,然后block块结束的时候将变量置为空,或者将对象作为block函数的参数传到block里边。

Block和代理的优缺点和使用场景:block更轻量级,回调的时候可以访问当前对象的上下文,调用的类中也不需要去保存一些临时数据;

如果要回调多个方法,可以考虑用delegte,因为只需要设置一次代理,然后可以实现很多方法,如果用block的话,太多太麻烦;

如果长期调用block,导致不是栈中的block对象循环引用,所以用delegate比较合适;

NSDictionary NSArray NSString 类型的copy属于浅拷贝,当前的变量指向被拷贝变量指向的地址;mutableCopy属于深拷贝,重新开辟一段内存,然后指向新开辟的内存地址;

NSMutableArray的copy属于浅拷贝,被拷贝对象的元素发生变化,那么copy后的对象也发生变化,因为属于一个内存地址;

直接赋值属于浅拷贝,一个NSMutableArray赋值给一个NSArray对象,属于浅拷贝,那么NSMutableArray对象的元素发生变化后,NSArray对象元素也发生变化,虽说NSArray属于不可变数组,但是底层属于NSMutableArray修饰,最终将它指向的地址给了可变数组,因为oc是多态性,NSArray指向了子类NSMutableArray的对象地址了;

如果自定义对象要实现copy方法,则需遵循NSCopying协议,然后重写copyWithZone方法,重新分配zone去指向,zone属于地址的结构体;

属性一般用copy修饰,用copy为了保持数据唯一性,如果用strong,当前变量赋值给可变类型的对象,系统会将当前变量指向可变类型的对象地址,不能确保数据的安全性;

13,属性标识符,property修饰的属性作用域在interface内部,自动生成getter和setter方法,用户不能同时手动书写这两方法;

synthesize,自动生成get,set方法,用户可同时手动书写2方法;

dynamic,系统不会自动创建get,set方法,需用户手动创建且绑定;

14,属性变量的原子性和非原子性,nonatomic,atomic;

nonatomic可在不同的线程同事操作当前变量,且线程不会阻塞,但是在同时操作的同时,可能因为值的变换会造成崩溃;

atomic原子性,具有线程安全性,如果同时操作变量,则会将变量放在一个队列,等待第一次操作完成,后续的操作会顺序执行;

15,weak,弱引用,属于对象的一种”非拥有关系”,此关键字修饰的属性既不释放旧值,也不保留新值,当对象销毁的时候,属性会自动被系统清空为nil;和assign的不同为,此关键字是对象和对象之间的关系,assign则为基本数据类型的修饰;weak修饰的对象,在引用时,引用计数不变;

16,strong,ARC特有关键字,等同于MRC中的retain,强引用,引用计数加1,系统销毁时会判断retaincount,如果为0则进行清空,否则可能该属性进行了循环引用;

17,copy,一般修饰不可变类型的对象数据,例如NSString,NSArray,如果修饰修饰了可变的类型数据,则copy作用变成了strong,那么将会在内存中重新拷贝一份地址,用来对可变对象进行值的赋值或者改变;

18,__weak,和weak修饰属性等同,__weak修饰的变量,所引用当前变量的对象不会持有当前变量,变量弱引用,当对象释放后,系统会清空并且自动设置为nil,防止循环引用造成内存泄露;

weak表,也是一张哈希表。被weak 修饰的指针变量所指向的地址是 key ,所有指向这块内存地址的指针会被添加在一个数组里,这个数组是 Value。当内存地址销毁,数组里的所有对象被置为 nil。

19,__strong,想让某个变量或者对象使用强引用,防止调用该对象的时候被提前释放导致错误,例如block中进行引用;

20,MRC,ARC;

MRC,每个对象的销毁根据它自身的引用计数进行判断,每创建一个对象它的引用计数加1,那么在适当的时候需要手动release此对象,保证它的引用计数减1,直到该对象的引用计数为0 的时候,系统才会清空它的内存;MRC遵循的原则是,谁创建,谁释放;谁引用,谁去管理他的引用计数;MRC下常用的几个关键字retain、release、autorelease,分别是加1,减1,自动减1;

ARC,自动引用计数,iOS系统垃圾自动回收的一种机制,去掉了以上MRC所引用几个释放关键字,编译器会在适当的时候进行引用计数计算;引入了strong和weak关键字;

MRC和ARC混编:-fobjc-arc,-fno-objc-arc;ARC中引入了自动释放池,autoreleasepool在自动释放池作用域内,所创建的对象在执行结束后引用计数都会自动减一,一般用于循环创建多个对象的时候;

内存泄露第三方库:MLeaksFinder;

21,线程;pthread,NSThread,GCD,NSOperation;

线程,进程的基本执行单位,一个进程对应多个线程;

进程,是系统进行资源分配和调度的基本单位,是操作系统结构的基础,主要管理资源;

@synchronized,将线程锁操作的代码块进行加锁,保证数据的唯一性;

主线程,所有的UI操作必须在主线程进行操作;

多线程,CPU通过提高资源使用率提高系统或应用的总体效率;

pthread,C语言的一套线程API,可跨平台使用;

NSThread,用户自行创建线程对象,此线程的生命周期由程序员自行结束;

GCD,可充分利用CPU的多个核数运行进程,在线程池内,系统自动管理线程的生命周期;

NSOperation,封装了GCD,系统自动管理线程的生命周期;

NSOperation,其操作主要是NSInvocationOperation和NSBlockOperation类,这两类是NSOperation线程主要表现形式,如果当前对象没有加入到NSOperationQueue队列里边,那么她们初始化的seletor和block属于主线程,而且要start才能执行;

NSOperationQueue,NSOperation里边的队列,配合以上两个类的对象实现和执行,当NSOperation加到队列queue里边后,不需要start,自动执行;

NSOperation主线程的获取方法:[NSOperationQueue mainQueue];

GCD,sync同步,async异步,多个线程之间存在串行和并发的关系,并发只能在异步函数下进行操作; 串行可异步可同步,依次有序的执行;

dispatch_get_global_queue,全局队列;

dispatch_get_main_queue,主队列;

dispatch_after,延时操作;

dispatch_once,线程安全且只调用一次,一般用户单例创建;

dispatch_barrier_async,文件读取锁,防止多个线程同时操作当前文件,此线程为加锁模式;

dispatch_group_t,线程组,记录其他所有异步线程执行结果,等待其他线程执行结束后阻碍当前线程,然后执行其他线程执行完的操作。

dispatch_semaphore_t,信号量,控制当前资源的访问线程数,一般用于多个线程访问一个资源,防止数据篡改或者执行后数据错误;

线程的死锁状态:第一个线程等待第二个线程操作完成再去操作,第二个线程等待第一个线程操作完成再去操作,所以谁都不去操作,这样是死锁状态。主线程队列用同步去执行函数时,会造成这种状态;

21,设计模式;

MVC,MVVM;MVVM是MVC的增强版,为了缓解控制器中的逻辑进行太多处理,增加了View+Model模块,用来处理视图和数据之间的逻辑;

工厂模式,单例,代理,通知,监听;

22,推送原理;

APNs,苹果推送通知服务,APNs 允许设备与苹果的推送通知服务器保持常连接状态。

流程:自身服务器向苹果APNs(苹果推送服务器)发送推送请求,APNs接收请求并且向每个目标设备发送对应的推送消息内容,然后每个设备接收到消息后于用户进行交互;在自身服务器发送消息之前,获取了每个设备的device token,然后带着device token,APNs服务器去判断并且分发;

23,图文混排;

图文混排主要基于CoreText框架;UILable,NSMutableAttributedString;UITextView,UITextfield,CGContextRef;

24,tcp,传输层的传输控制协议,http,socket都是基于tcp协议发送的请求;

tcp的三次握手:客户端向服务器发送请求等待服务器确认,服务器收到包之后确定当前客户端的链接同事发送包给客户端等待客户端确认,客户端收到包之后发送确认包给服务器,三次握手完成;

UDP,传输层,用户数据报协议,无连接的传输协议,不保证可靠性;

TCP是有链接的,但是UDP没有,TCP是一对一连接的,但是UDP是多对多的报文服务;

25,http,超文本传输协议,基于TCP/IP通信协议来传递数据,其中请求包括请求行(request line)、请求头部(header)、空行和请求数据(body)四个部分组成;

常见的请求头有:

HTTP_HOST: “127.0.0.1”,

HTTP_CONNECTION: “keep-alive”,

HTTP_CACHE_CONTROL: “max-age=0”,

HTTP_UPGRADE_INSECURE_REQUESTS: “1”,

HTTP_USER_AGENT: “Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36”,

HTTP_ACCEPT: “text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8”,

HTTP_ACCEPT_ENCODING: “gzip, deflate, br”,

HTTP_ACCEPT_LANGUAGE: “zh-CN,zh;q=0.9″,

http发送数据的封装格式为,头文件结束之后\r\n,然后是body体,body体如果没有传输文件,则按照顺序封装当前参数的格式,如果有文件传输,先封装传递的参数,然后封装文件传输格式,无文件上传的封装格式:

–AaB03x

Content-Disposition: form-data; name=”key1″

value1

–AaB03x

Content-Disposition: form-data; name=”key3″

value3

–AaB03x

Content-Disposition: form-data; name=”key2″

value2

–AaB03x为自定义的分隔符,然后分隔符下边为\r\n,每一个参数后边都封装\r\n;

以下为有文件上传时候请求的封装:

–AaB03x

Content-Disposition: form-data; name=”key1″

value1

–AaB03x

Content-Disposition: form-data; name=”key3″

value3

–AaB03x

Content-Disposition: form-data; name=”key2″

value2

–AaB03x

Content-Disposition: form-data; name=”uploadImage[]”; filename=”b6589fc6ab0dc82cf12099d1c2d40ab994e8410c.png”

Content-Type: image/png

–AaB03x

Content-Disposition: form-data; name=”uploadImage[]”; filename=”356a192b7913b04c54574d18c28d46e6395428ab.png”

Content-Type: image/png

–AaB03x

Content-Disposition: form-data; name=”uploadImage[]”; filename=”da4b9237bacccdf19c0760cab7aec4a8359010b0.png”

Content-Type: image/png

–AaB03x

Content-Disposition: form-data; name=”uploadImage[]”; filename=”77de68daecd823babbb58edb1c8e14d7106e83bb.png”

Content-Type: image/png

–AaB03x–

文件上传最后也得加入自定义的分隔符;

上传文件首先申明图片的处理机制:Content-Disposition: form-data; name=\”%@\”; filename=\”%@\”\r\n”然后申明当前附件的类型:Content-Type: %@\r\n\r\n”,@”image/png

https:加入了ssl加密的http请求;作用,保证数据的安全性,确认网站的真实性;

http1.x和http2.0区别,1.x头部信息是纯文本格式,2.0头部信息进行了压缩;

1.x阻塞了线程,等待一个请求结束后才能进行第二个请求,2.0做到了多路请求复用,不需要等待请求结束再去请求第二个;

https的默认端口为443;原理,客户端通过https开头去请求服务器,服务器要求简历ssl连接,服务器接收到请求之后判断当前连接是否是加密连接,然后同意客户端的安全请求,服务器会根据连接时的会话秘钥进行和客户端之间的通讯和文件传输;2.0增加了请求速度;

https的缺点:黑客攻击时不会主动防御,和客户端之间连接时浪费大量时间,一个ip只能绑定一个ssl证书;

26,socket;socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口(API),为服务端和客户端提供数据传输所封装的一个服务;

服务器规定了host和端口,客户端进行连接,大体流程为:服务器监听客户端连接状态,客户端通过指定的端口和host去请求服务器,服务端收到了请求之后将描述文件发送给客户端,这样一个完整的socket连接就完成了;

常用的socket第三方,socketIO;

创建Socket连接时,可以指定使用的传输层协议,Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接。

TCP:面向连接、传输可靠(保证数据正确性,保证数据顺序)、用于传输大量数据(流模式)、速度慢,建立连接需要开销较多(时间,系统资源)。

UDP:面向非连接、传输不可靠、用于传输少量数据(数据包模式)、速度快。

CFSocket是基于系统框架CoreFoundation封装的C底层的socket实现,主要是为了长连接进行数据传输,主要用到的场景是聊天等,其可以选择TCP连接和UDP连接,至于两者连接的不同就是TCP和UDP的不同;CFNetwork是依赖于Core Foundation框架中的两个API,一个CFSocket,另一个是CFStream;

27,websocket,是客户端与服务器进行通讯的一种协议,借助Http请求进行完成,websocket是应用层协议;

http模式是短连接,如果断开连接或者请求完成后,下次连接还是需要进行TCP的三次握手才能进行传输。那么websocket升级了http协议,只需要通过进行一次握手,通过通文件告诉服务器是Http升级版的协议,并且是长连接,然后可以无限的进行数据传输,如不发生网络等用户主动断开连接,则会一直进行连接,服务停止前断开连接即可;常用的websocket第三方库有WebsocketStompKit,RCTSRWebSocket;

HTTP 和 WebSocket 有什么关系?

Websocket 其实是一个新协议,跟 HTTP 协议基本没有关系,只是为了兼容现有浏览器的握手规范而已,也就是说它是 HTTP 协议上的一种补充。

Html 和 HTTP 有什么关系?

Html 是超文本标记语言,是一种用于创建网页的标准标记语言。它是一种技术标准。Html5 是它的最新版本。 Http 是一种网络通信协议。其本身和 Html 没有直接关系。

28,加密算法:

base64加密,6个bit为一组数据,如果不够则后边补零,那么两个0用一个=号进行标示;且可进行反向解密;加密后数据长度会增加;

MD5,哈希算法的一种,可加密任意长度的数据,那么加密后的MD5值长度是固定的,不会改变;且不能进行反向解密;

RSA非对称加密算法,常被用于加密数据传输;通过生成密钥对,对数据进行加密,首先生成公钥和私钥,公钥是公开的,放在客户端,私钥通过服务器传输给客户端进行数据解密,

DES对称加密;

AES对称加密,公认最安全的加密方式;

数据传输加密流程:每次打开应用都去请求加密公钥,然后通过公钥将自定义的私钥串进行RSA加密,然后通过加密后的私钥串再对数据进行AES加密,最后将加密后的私钥串和加密后的数据传递给服务器;

解密流程:请求获取加密的公钥,然后将数据中的加密私钥串通过公钥进行RSA解密,获取明文的私钥串之后,再对数据进行解密,然后将解密后的数据进行解析;

29,NSPredicate正则:

验证手机号1开头,356789为手机第二位数字,其他的可为0-9,@”^1+[356789]+\\d{9}”;

六位验证码:\\d{6},四位验证码\\d{4};

Email:[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4};

6-20位密码,数字字母混合,大小写混合:^(?![0-9]+$)(?![a-zA-Z]+$)[a-zA-Z]|[0-9]|[a-zA-Z0-9]{6,20};

30,UITableview优化:缓存cell高度;异步加载或渲染image,异步处理逻辑,然后主线程进行刷新;减少数据量的加载,减少view的复杂层级关系;

31,JS交互:JavaScriptCore.framework,JSContext,JS基础;

32,Sqlite,Userdefaults,coredata,plist,data缓存;

FMDB是基于sqlite封装的一第三方库,数据库文件后缀通常定义为.sqlite,一个文件代表一个数据库,其流程为:

sqlite3_open,打开数据库,如果当前数据库不存在则会创建,然后打开数据库句柄进行操作;

sqlite3_exec,然后创建数据表,其sql语句和一般mysql等相同,其三个参数;sqlite3 *db为数据库对象;

sqlite3_prepare_v2,插入对象,然后执行sql语句sqlite3_exec;

释放sqlite数据库sqlite3_finalize();

关闭sqlite,sqlite3_close;

plist是苹果封装xml文件的一种格式文件,其表现为归档,反归档,其中Userdefaults是系统级归档的一种特殊表现形式;

NSData直接写入文件;

Coredata是apple官方封装sqlite的API;

33,图片处理:

水印:UIGraphics绘制;

裁剪:CGContext,贝塞尔曲线等;

滤镜:CoreImage框架Filter类,此框架基于OpenGL封装,主要用到对象CIContext,CIImage去处理;

常用第三方框架,GPUImage,基于OpenGL;

34,视频处理:

录制:AVFoundation,创建捕捉会话capturesession,session设置视频的分辨率等值;然后获取视频输入设备,可设置视频的码率,帧率等;获取音频输入设备,设置将录制的视频数据和音频数据进行合成输出,有必要的时候还需要获取静态图像AVCaptureStillImageOutput;添加预览layer,AVCaptureVideoPreviewLayer,设置预览方向,大小等;AVAssetWriter封装音视频然后写入磁盘;

水印,通过输出视频的输出的URL,获取当前视频的Asset对象,然后创建一个可变媒体通道集合,此集合后期集成了视频,音频,各种layer等素材;

然后创建一可变视频通道AVMutableComposition,获取视频轨道中的视频数据:

AVAssetTrack *videoAssetTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] firstObject];

然后将视频轨道的数据插入到可变轨道中,[videoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration) ofTrack:videoAssetTrack atTime:kCMTimeZero error:nil];(截取视频也用的此方法;根据开始时间和播放时间;这里如果不获取音频通道插入到可变轨道,那么就是消音的功能,也可以通过此方法添加背景音乐;)然后获取视频上添加素材的指令对象,AVMutableVideoCompositionLayerInstruction,在此指令上的animationTool中添加layer,至于layer上的动画是根据animation之前就添加好了;

添加背景音乐:AVMutableAudioMix,音频通道添加音频资源;

视频裁切:AVMutableComposition,添加音视频资源,同时设置音视频资源的时间段和插入点;

35,Interface Builder,是xib和storyboard的一个集合,通过XML文件去存储应用UI部分,苹果提供了生成并且实现xib和sb的接口;

36,Instruments

Allocations,内存分配规则;

Cocoa Layout,constraint布局是否合理查询;

Leaks,内存泄露查询;

Core Animation,view绘制及view动画渲染查看;

37,第三方支付流程:

向服务器请求订单信息,然后将数据传递给服务器,请求商品支付的加密数据,然后调起第三方支付,返回App时候根据订单号请求当前支付产品的支付状态,此支付状态第三方支付平台会以异步的形式通知后台;

38,常用第三方库原理,SDWebimage,AFNetworking,Fmdb,CocoaAsyncSocket,ReactiveCocoa;

SDWebimage原理:首先每一张图片的下载都会开辟一个子线程,然后将此线程加载到队列里边,根据URL进行下载;下载之前判断当前内存中是否有此图片,如果有则直接使用,如果没有则检查当前设备硬盘中是否有当前图片,如果有,将图片加载到内存中,然后取出进行使用,如果没有则进行下载,下载完成之后再内存和硬盘中分别保存一份;

SDWebimage会在使用中判断当前缓存是否过大,如果过大,则清空内存中缓存的,然后取消当前队列中的操作重新进行加载;

AFNetworking,对其NSURLSession进行了封装,3.0以后版本增加了https证书认证机制;通过URLManager对其系统NSURLSession和其代理方法,及其NSURLSession配置进行了管理;内部通过了NSOperateGroup管理多线程并发,并且对请求完成的数据进行了解析配置以及缓存;也可能通修改config来配置当前最大并发操作数;

FMDB,以oc的形式封装了c的sqlite3 api,提供了数据库的增删改查操作,并且增加了数据库事物的操作;事物就是执行一系列sql操作的时候,保证数据唯一性,和事物操作的原子性一种并发操作的基本单位,也可提高sql查询效率;

CocoaAsyncSocket,封装apple CFNetwork框架下C的api的一套基于TCP和UDP的socket第三方网络框架;

其中包含了四个文件,2个是基于TCP的,两是基于UDP的,基于TCP的socket在连接成功之后,需要根据时间间隔发送心跳包,至于这个心跳包的数据一般都是和后台协商验证的一个心跳包,时间也可和后台商定好,这样服务器检测心跳的时候可检测当前连接的客户端是否在线;

socket连接的时候必须释放当前心跳发送的运行吃,也就是runloop,销毁socket代理等操作,至于三次握手,系统内部已经做好了;

39,单例创建:

@ synchronized 线程安全的互斥锁,创建单例时保证其他线程对当前self对象或者self所持有的对象进行修改,确保数据的唯一性;

其互斥锁锁住了对象和锁内的操作;

[[self alloc]init] 和 [[[self class]alloc]init]的的区别;

[[self alloc]init],如果父类派生了子类,当前父类以此方法创建对象,当前对象就是基类对象,子类不能根据当前对象调用子类方法和属性变量;

[[[self class]alloc]init],如果用当前方法创建,那么对象类型是相同的子类对象;[self class]指向元类的内存地址;

因为单例一般都是没有父类或者不会派生子类,那么用第一种去创建;

40,@import和@class的区别,import包含了引用了类的所有信息,包括实体变量和方法,而且在循环依赖关系里边,会自动排重,防止循环依赖所产生的编译错误;

class只包含了引用类的名称,至于类的方法,变量等信息都不会包含进来,class一般是为了引用这个类,将此类作为一个变量或者参数;

41,alloc的时候,只是给当前对象分配了内存,但是并没有实例化,init才是实例化当前类;new内部不仅对该对象分配了内存,而且以init方法对该对象进行了实例化;new创建对象和alloc是一样的,但是如果采用其他定制化的实例化方法,则用new不能去完成,例如initWithFrame;

42,离屏渲染,指在当前缓存区GPU重新开辟一个缓冲区对屏幕中UI层进行渲染,如果不开辟新的一个缓冲区,那么当前缓冲区对UI渲染会耗费GPU性能,界面也会卡顿,用户体验不好;离屏渲染也是对view下层的CALayer层可以触发离屏渲染,主要操作有,遮罩,阴影,opacity透明度,圆角,渐变等;

43,List卡顿优化:

1),当请求的数据量巨大的时,Json转换成Model的效率会下降,所以解析数据时尽量减少循环和利用Runtime,优化解析逻辑;

2),网络请求或者缓存的存取用异步去完成,至于UI的刷新再移步到主线程;

3),Cell中有大量的逻辑计算,尽量对计算后的数据进行缓存;计算时可用异步线程,刷新时再移步主线程;

4),尽量减少不必要的UI刷新事件;调整代码逻辑,调整UI的渲染方式,尤其是离屏渲染会带来性能上的损耗,造成卡顿;针对大量UI渲染的业务,可以对其业务进行拆分,分布或者延时进行处理;

5),利用好线程的并行和串行;把握好对象的生命周期,即时进行释放;

6),提高代码的健壮性,规范性,稳定性,开发完毕通过instrumens进行性能查找,测试,优化;

数据结构:堆,栈,队列;

堆,是一个完全二叉树,是在程序运行时候动态分配的内存结构,在运行时请求操作系统分配给自己所持有的对象内存,一般是申请/给予的过程;由开发人员分配和释放;

栈,栈只是堆的一种使用方法,也就是结构的插入和删除操作;栈只允许在表的一端进行运算,所以为先进后出;栈是程序启动的时候,操作系统为当前程序的主线程分配了指定需要的大小,也是操作系统自动去释放;

队列:一种特殊的线性表,允许在表的前端进行删除操作,表的后端进行插入操作,如果队列中没有元素,则成为空队列;队列有两指针,第一个指向队头,第二个指向下一个进入队列元素的存储位置,读取队列的时候先读取队头的元素,每读取一个元素,系统自动释放一个元素,所以是动态释放。每次从队尾插入一个元素,进行动态分配,所以是先进先出,因为是动态分配和释放,所以不存在内存溢出;__weak变量就是存在队列里边,引用完当前对象之后,系统自动释放;

列表,列表是一种数据项构成的有限序列,即按照一定的线性顺序,排列而成的数据项的集合,在这种数据结构上进行的基本操作包括对元素的的查找,插入,和删除列表的两种主要表现是数组和链表,栈和队列是两种特殊类型的列表;

数组,创建时分配一块连续的内存,然后将数据存储在连续的内存中,根据数组的索引将内存中的数据取出来然后读取,这就是数组的寻址读取,读取速度快;其操作不仅可以读取,还可以进行删除和插入;删除和插入操作在底层是比较耗时,如果删除一个元素,那么后边所有内存中的数据都要向后移动一个位置,如果是插入则需要插入索引以后的所有数据向后移动一个位置;数组在内存中的空间是连续的,所以对空间的要求比较高;

链表:分为单向链表,双向链表,循环链表。链表是一个特殊的结构体,单向链表结构体中保存数据,指向下一个链表节点的指针。头结点的数据为空,指针指向第一个链表节点,尾节点指针为空,因为没有下一个节点再去指向;单向链表删除插入操作速度快,只需要修改其指针指向;但是查找速度慢,不能随机进行查找,必须根据遍历去查找;

双向链表结构体中不仅保存了数值,下一个节点的指针,也保存了上一个节点的指针,可以查找前一个节点;

单向链表只能单向读取,双向链表是双向读取;

循环链表和单向链表结构体相同,只不过最后一个节点指针指向第一个节点的地址,形成一个循环链路。它和单向链表的区别是,单向链表只能循环进行查找读取,读取时候只能从头节点开始,但是循环链表可以从任意一个节点开始,然后循环一圈进行读取某一个想要的节点;

二分法:二分法分为,二分查找算法,二分排序算法,二分合并算法;

二分查找法,查找一个序列中某一个数,1-100,查找70的话,那么首先确定一个自然数,例如50,进行判断当前要查找的数是不是大于50,如果大于50,则查询50以后的所有序列元素,如果小于50,则查询50之前的元素,每次查询都将可能性数字分为一半,这样减少了查询的效率;二分法也属于特殊的一种循环查询法;

45,二叉树,堆其实就是完全二叉树的完整表现形式,二叉树有左子树,右子树,根节点;二叉树的所有查询思想也就是递归的思想,二叉树的遍历查询有三种方式:1,先序遍历,先访问根,再遍历左子树,再遍历右子树。典型的递归思想。2,中序遍历先遍历左子树,再访问根,再遍历右子树。对于二叉排序树来说,中序遍历得到的序列是一个从小到大排序好的序列。3,后序遍历先遍历左子树,再遍历右子树,再访问根。

46,算法,穷举法,对于简单的形式一一将所有的可能性列举出来,解决一些简单的算法形式,如果太过复杂的数据,效率不会那么快;

冒泡,每次对相邻的两个元素进行比较,若前者大于后者则进行交换,如果小于或者等于则位置不变,如此一趟下来最后一趟的就是最大元素,重复以上的步骤则进行了冒泡排序;

排序:快速排序,从第一个元素或者最后一个元素开始遍历,遍历次数为n-1次,每次遍历完将大于自己的数进行交换,直到所有的树遍历结束;

时间复杂度:算法的时间复杂度是一个函数,它定性描述了该算法的运行时间。这是一个关于代表算法输入值的字符串的长度的函数。时间复杂度是指执行算法所需要的计算工作量。时间复杂度跟算法的效率有关系,算法的效率越高,时间复杂度越低;

44,iOS事件响应机制:三大事件类型,触摸事件,加速器事件,远程控制事件;在iOS中继承于UIResponder的控件才有响应事件,其分别有UIApplication,UIViewController,UIView;

事件的传递是通过父类控件传到子类控件,UIApplication->window->拥有事件的view;通过遍历,找到当前适合事件的view,遍历通过子控件数组从后往前遍历;

一个拥有响应事件的控件不能够接受触摸事件的三种可能性,1,userInteractionEnabled = NO;2,hindden = YES;3,控件的透明度<0.01;

UIView所添加的触摸事件,这个事件会被添加到由UIApplication管理的事件队列中,UIApplication会从事件对列中取出最前面的事件进行判断和寻找当前事件适合的view;循环通过底层hitTest:withEvent:方法判断当前合适的view是哪个,流程:

产生触摸事件->UIApplication事件队列->[UIWindow hitTest:withEvent:]->返回更合适的view->[子控件 hitTest:withEvent:]->返回最合适的view;

[self.view pointInside:curP withEvent:event];判断当前触摸点是不是在当前view上。

一个事件多个控件处理,调用父类的super touches…方法;

45,xcode的编译过程:1,预处理(Pre-process):把宏替换,删除注释,展开头文件,产生 .i 文件。

2,编译(Compliling):把之前的 .i 文件转换成汇编语言,产生 .s文件。 3,汇编(Asembly):把汇编语言文件转换为机器码文件,产生 .o 文件。

4,链接(Link):对.o文件中的对于其他的库的引用的地方进行引用,生成最后的可执行文件(同时也包括多个 .o 文件进行 link)。 然后通过解析 xcode 编译 log,可以发现 xcode 是根据 target 分开进行编译的。 编译过程的控制,在 xcode 中可以通过 Build phases,Build settings以及 Build rules来进行控制。

46,dSYM,dSYM 是保存 16 进制函数地址映射信息的中转文件,保存了crash下出错的文件名,函数,行号;保存crash信息的文件,只有release版本才会生成,一般用atos,dSYMTools工具进行地址转换,然后查找出有问题的地方;

47,git:在库文件夹下,创建当前文件夹问git库,git init;

添加文件到当前的git库中,git add MsgDemo;提交:git commit -m “init project file by git”,-m是msg,本次提交的消息内容,以便后期阅读;

git log (git reflog)查看提交日志,提交日志里边有commit id(3ef7945497233fcf2295d23f22c41c804a980a65),记录这个id用户回退到之前的版本或者跳到以后的版本:git reset –hard [commit id]; reset其实就是让git当前的版本节点指向所需的commit;

回退到上一个版本:git reset –hard HEAD^;

查看分支树形提交信息:git log –graph –pretty=oneline –abbrev-commit;

当前仓库的根文件夹属于工作区;

.git目录属于版本库,版本库中有自动分支master,还有暂存区,分支有一个指针head;

git status,查看当前库中文件的修改和提交状态,如果有以修改的必须提交到暂存区然后在提交到分支;git add 属于添加到暂存区,git commit –m属于推送到分支;没有添加到暂存区的文件不会提交到分支,所以git跟踪的是修改,不是文件;

将没有添加到暂存区的已经修改的文件回退到修改之前:git checkout – filename

git reset命令既可以回退版本,也可以把暂存区的修改回退到工作区,这个撤回的标准是最后一次提交到分支的文件。如果将文件fileName已经放在了暂存区,那么可以用git reset HEAD finaName将文件退回到工作区,如果想撤回修改,那么用checkout将文件撤回。如果已经将文件commit到了分支,就不能再去reset到工作区了;

添加一个新文件:git add filename;git commit -m “msg”;

删除一个文件:git rm filename;不仅删除了工作区的文件,而且添加了暂存区的修改操作;如果想恢复,必须将节点中的文件操作退回到工作区,然后再将文件退回到操作区,git reset HEAD filename,git checkout – filename;

如果是rm fileName,那么直需要checkout;

远程仓库:

生成私钥公钥,ssh-keygen -t rsa -C youremail@example.com

其生成在Users/username/.ssh下

添加指定的远程项目:git remote add origin git@gitee.com:iashes/MsgDemo.git

删除指定的远程项目:git remote rm origin;

然后将本地库和远程库合并:

先从远程库拉下来,git pull –rebase origin master,然后合并:git push -u origin master

当远程库和本地库第一次进行合并之后,每次本地add,commit之后,运行git push origin master推送到远程就ok;

远程克隆仓库:git clone git@gitee.com:xxx/MsgDemo.git 或者https://

分支,master属于主分支,也称为自动分支;

创建分支:git branch newMas;

切换当前修改分支master为新创建的分支newMas:git checkout newMas;也就是将提交指针指向newMas分支;

(同时创建且切换分支:git checkout -b newMas);

切换到主分支:git checkout master;

查看当前分支:git branch;

将newMas分支合并到主分支master:git merge newMas;

删除分支:git branch –d newMas;

合并冲突:

Auto-merging readme.txt CONFLICT (content): Merge conflict in readme.txt Automatic merge failed; fix conflicts and then commit the result.

提示有文件内容冲突,git status查看当前冲突文件,

xxxxxxxxMBP:MsgDemo Ashes$ git status
 
On branch master
 
Your branch is ahead of 'origin/master' by 2 commits.
 
(use "git push" to publish your local commits)
 
You have unmerged paths.
 
(fix conflicts and run "git commit")
 
(use "git merge --abort" to abort the merge)
 
Unmerged paths:
 
(use "git add <file>..." to mark resolution)
 
both modified:   readme.txt
 
no changes added to commit (use "git add" and/or "git commit -a")

readme.txt文件冲突了,重新编辑时看见冲突内容<<<<<  =======  >>>>>>>由这些字符分割,解决完冲突之后,add,然后commit即可;解决完冲突,再次提交,这次合并就算完成了,不需要重新合并了。

Git merge命令合并的分支,当删除次分支之后,不会保留合并的信息,那么用以下方法:

git merge –no-ff -m “merge with no-ff” newMas; 禁用了快速合并,然后在合并的同时创建了一个新的commit,通过-m可以查出历史记录;

暂存操作,暂存当前文件的修改操作,然后就可以去别的分支干别的事情,回头接着干:

git stash 暂存当前修改

git stash apply 恢复最近的一次暂存

git stash pop 恢复暂存并删除暂存记录

git stash list 查看暂存列表

git stash drop 暂存名(例:stash@{0}) 移除某次暂存

git stash clear 清除暂存

强制删除一个没有合并的分支:git branch –D newMas;

远程分支:

查看远程仓库的信息:git remote –v

推送其他分支到远程仓库:git push origin newMas;

备注,master分支是主分支,因此要时刻与远程同步;dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;至于其他分支,可推也可不推;

标签管理,发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。

为当前最新的commit打标签:git tag v1.0,为某个commit打标签:git tag v0.9 b1d93ec,查看当前分支下所有的标签,git tag;

创建有msg(说明信息)的标签,git tag -a v0.1 -m “version 0.1 released” 1094adb;

查看指定标签信息,git show v0.1

删除本地标签:git tag -d v0.1

推送当前标签到远程:git push origin v1.0

推送所有的本地标签到远程: git push origin –tags

删除远程标签,首先删除本地标签:git tag -d v0.9,然后删除远程标签,git push origin :refs/tags/v0.9

多人协作,首先git pull 远程的修改,然后add,commit本地库,最后push origin到远程;

48,iOS单元测试:单元测试是系统自带的一种模块化测试方案;可对一个控件,或者一个函数,一个逻辑进行模块和程序分离测试;一般的测试得开发人员运行了整个项目之后再去测试,但是单元测试只需要运行当前测试的部分;

单元测试还可以测试当前模块的性能和资源消耗程度,为程序员前期实现功能更模块提供了更加便捷的测试;

49,App做完的后续工作:性能优化,代码逻辑不严密进行重构,配合产品做好交互,用户体验等,迭代更新,上线后的bug收集(tencent bugly ,dSYM);

50,Cacoapods常用的几个命令:

sudo gem install cocoapods 安装;

pod –version 查看版本;

pod setup 设置pods仓库

vim Podfile 创建pods文件;

pod install 下载库;

pod update 更新库

pod search FmName 搜索库

51,ipad开发iphone开发中的不同点;
1,屏幕尺寸,分辨率不同,资源文件和适配也不同;

2,UI元素的排版也有差异,考虑pad容纳更多的内容,iphone可单手操作等;

3,键盘;

4,Api有所不同,在控件中,ipad有一些独有的控件;

5,屏幕方向的支持,ipad支持四个方向,iphone支持三个方向;

6,功能不能,例如iPhone可以进行电话拨打,pad就不能,有些iphone支持NFC功能,但有些pad不支持;

52,iOS网络数据解析结构:xml,json,protobuf(google 的一种轻便高效的数据存储格式);

53,手机性能优化,输入输出操作,当操作数据比较大时,尽量用异步去执行,dispatch_barrier;读取也用异步,读取不需要考虑数据的安全性,但是写入一定要考虑数据的唯一性;

当缓存数据过大时,尽量不要再沙河中读取,尽量用数据库或者coredata,因为数据库里边已经对并发进行了处理;

网络传输,最好能够断点续传或者下载文件设置超时时间,一定要在网络良好的情况下进行传输;

尽量不要去让用户后台进行定位,这样耗电量很大,除非是导航应用;因为定位不仅用到了GPS模块,而且用到了网络模块;

视频,图片渲染,对手机的功耗很大;

设计模式,MVC,MVVM,组件化,RAC(ReactiveCocoa);

MVC:将View和Model分离出来,逻辑处理交给Controller去做,如果项目逻辑处理比较繁琐,数据量比较大,控制器比较臃肿繁琐,后期重构代码也比较复杂;

MVVM:分为四个层级,View,Model,ViewModel逻辑数据处理层,Controller层;在MVC的基础上加了ViewModel层,主要是将一些数据,业务,网络请求的处理放在了ViewModel里边,减少了Controller层的业务逻辑,使得Controller层不那么臃肿繁琐;

MVVM缺点:更多的类文件造成了程序的冗余度增加;

Leave a Reply

Required fields are marked *