IOS面试题

面试题一: ios声明变量的属性关键词

@property 

@property = ivar + getter + setter;

“属性” (property)有两大概念:ivar(实例变量)、存取方法(accessmethod = getter + setter)。

原子性:nonatomic、atomic

atomic

是默认的

会保证 CPU 能在别的线程来访问这个属性之前,先执行完当前流程

速度不快,因为要保证操作整体完成

nonatomic

不是默认的

更快

线程不安全

如有两个线程访问同一个属性,会出现无法预料的结果

如果该对象无需考虑多线程的情况,这个属性会让编译器少生成一些互斥代码,可以提高效率。

 

读写权限:readwrite(读写)、readonly (只读)              

readwrite 是可读可写特性;需要生成getter方法和setter方法时(补充:默认属性,将生成不带额外参数的getter和setter方法(setter方法只有一个参数))

readonly 是只读特性  只会生成getter方法 不会生成setter方法 ;不希望属性在类外改变

内存管理:assign、weak 、retain 、strong、copy、unsafe_unretained

assign与retain

1、assign: 简单赋值,不更改索引计数;

2、assign的情况:NSString*newPt = [pt assing]; 

此时newPt和pt完全相同地址都是0Xaaaa 内容为0X1111 即newPt只是pt的别名,对任何一个操作就等于对另一个操作,因此retainCount不需要增加;

3、assign就是直接赋值;

4、retain使用了引用计数,retain引起引用计数加1,release引起引用计数减1,当引用计数为0时,dealloc函数被调用,内存被回收;

 

weak and strong (强引用和弱引用的区别):

1、weak 和 strong 属性只有在你打开ARC时才会被要求使用,这时你是不能使用retain release autorelease 操作的,因为ARC会自动为你做好这些操作,但是你需要在对象属性上使用weak 和strong,其中strong就相当于retain属性,而weak相当于assign。

2、只有一种情况你需要使用weak(默认是strong),就是为了避免retaincycles(就是父类中含有子类{父类retain了子类},子类中又调用了父类{子类又retain了父类},这样都无法release)    

3、声明为weak的指针,指针指向的地址一旦被释放,这些指针都将被赋值为nil。这样的好处能有效的防止野指针。 

 

什么情况下用weak

1、ARC情况下有可能出现循环引用的时候 。可以使用weak 。比如delegate

2、IBoutlet:拖出来的控件属性一般也是weak。当然也可以用strong。

 

weak与assign 的不同

1、weak为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。然而在属性所指的对象遭到摧毁时,属性值也会清空。

assign基础数据的简单赋值。

2、assign 可以用非 OC 对象,而 weak 必须用于 OC 对象。

 

怎么用或者什么情况用copy关键字

1、NSString、NSArray、NSDictionary等等经常使用copy关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary;

2、block 也经常使用 copy 关键字。

注意 1:只有copy后的Block才会在堆中,栈中的Block的生命周期是和栈绑定的。

2、另一个需要注意的问题是关于线程安全。

    在声明Block属性时需要确认“在调用Block时另一个线程有没有可能去修改Block?如果确定不会有这种情况发生的话,那么Block属性声明可以用nonatomic。如果会有这种情况发生的话,那么你首先需要声明Block属性为atomic;在非ARC下则需要手动retain一下,否则如果属性被置空,本地变量就成了野指针了,也要记着release。


 copy 与 retain的区别

1、copy其实是建立了一个相同的对象,而retain不是

2、copy是内容拷贝,retain是指针拷贝;

3、copy是内容的拷贝 ,对于像NSString,的确是这样,但是如果copy的是一个NSArray呢?这时只是copy了指向array中相对应元素的指针.这便是所谓的"浅复制”.

 

@synthesize和@dynamic分别有什么作用?

@property有两个对应的词,一个是@synthesize,一个是 @dynamic。如果 @synthesize和 @dynamic都没写,那么默认的就是@syntheszie var = _var;

@synthesize 的语义是如果你没有手动实现 setter 方法和 getter 方法,那么编译器会自动为你加上这两个方法。

@dynamic 告诉编译器:属性的 setter 与 getter 方法由用户自己实现,不自动生成。(当然对于 readonly 的属性只需提供 getter 即可)。假如一个属性被声明为 @dynamic var,然后你没有提供 @setter方法和 @getter 方法,编译的时候没问题,但是当程序运行到 instance.var = someVar,由于缺 setter 方法会导致程序崩溃;或者当运行到 someVar = var 时,由于缺 getter 方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。

 

__block和__weak修饰符的区别其实是挺明显的:

1.__block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型。 

2.__weak只能在ARC模式下使用,也只能修饰对象(NSString),不能修饰基本数据类型(int)。 

3.__block对象可以在block中被重新赋值,__weak不可以。 

 GCD里面用 __weak 防止内存释放不了,循环引用。


面试题二:IOS网络

一、底层实现

1、AFN的底层实现基于OC的NSURLConnection和NSURLSession

 2、ASI的底层实现基于纯C语言的CFNetwork框架

 3、因为NSURLConnection和NSURLSession是在CFNetwork之上的一层封装,因此ASI的运行性能高于AFN

二、对服务器返回的数据处理

1、ASI没有直接提供对服务器数据处理的方式,直接返回的是NSData/NSString

2、AFN提供了多种对服务器数据处理的方式

 (1)JSON处理-直接返回NSDictionary或者NSArray

 (2)XML处理-返回的是xml类型数据,需对其进行解析

 (3)其他类型数据处理

三、监听请求过程

1、AFN提供了success和failure两个block来监听请求的过程(只能监听成功和失败)

success : 请求成功后调用

failure : 请求失败后调用

2、ASI提供了3套方案,每一套方案都能监听请求的完整过程

(监听请求开始、接收到响应头信息、接受到具体数据、接受完毕、请求失败)

成为代理,遵守协议,实现协议中的代理方法

成为代理,不遵守协议,自定义代理方法

设置block

四、在文件下载和文件上传的使用难易度

1、AFN

 不容易实现监听下载进度和上传进度】 不容易实现断点续传、一般只用来下载不大的文件

2、ASI

非常容易实现下载和上传 非常容易监听下载进度和上传进度

非常容易实现断点续传 下载大文件或小文件均可

3、实现下载上传推荐使用ASI

 五、网络监控

1、AFN自己封装了网络监控类,易使用

2、ASI使用的是Reachability,因为使用CocoaPods下载ASI时,会同步下载Reachability,但Reachability作为网络监控使用较为复杂(相对于AFN的网络监控类来说)

3、推荐使用AFN做网络监控-AFNetworkReachabilityManager

六、ASI提供的其他实用功能

1、控制信号旁边的圈圈要不要在请求过程中转

2、可以轻松地设置请求之间的依赖:每一个请求都是一个NSOperation对象

3、可以统一管理所有请求(还专门提供了一个叫做ASINetworkQueue来管理所有的请求对象)

暂停/恢复/取消所有的请求

监听整个队列中所有请求的下载进度和上传进度

七、网络层级

第一部分:IOS关于网络请求的接口自下至上有如下几层:

· CFSocket 是最底层的接口,只负责 socket 通信。

· CFNetwork 是基于 CFSocket 等接口的上层封装,ASIHttpRequest 工作于这一层。

· NSURLConnection 是基于 CFNetwork 的更高层的封装,提供面向对象的接口,AFNetworking 工作于这一层。

· NSURLSession 是 iOS7 中新增的接口,表面上是和 NSURLConnection 并列的,但底层仍然用到了 NSURLConnection 的部分功能 (比如 com.apple.NSURLConnectionLoader 线程),AFNetworking2和 Alamofire 工作于这一层。

IOS面试题

第二部分:各协议的区别

1、网络七层由下往上分别为物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。

 2、其中物理层、数据链路层和网络层通常被称作媒体层,是网络工程师所研究的对象;

 3、传输层、会话层、表示层和应用层则被称作主机层,是用户所面向和关心的内容。

 http协议   对应于应用层 ,HTTP协议是基于TCP连接的。HTTP是应用层协议,主要解决如何包装数据。

 tcp协议    对应于传输层 , TCP/IP是传输层协议,主要解决数据如何在网络中传输;

 ip协议    对应于网络层 

 Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。

 建立起一个TCP连接需要经过“三次握手”:

1.TCP是有连接的,可靠的、可控制的、无边界的socket通信。

2.UDP是无连接的、不可靠的 数据报通信。但是效率高。


面试题三 :ios消息传递

iOS通讯模式(KVO、Notification、Delegate、Block、Target-Action的区别)

KVO

 一、delegate(委托):

代理更注重过程信息的传输:比如发起一个网络请求,可能想要知道此时请求是否已经开始、是否收到了数据、数据是否已经接受完成、数据接收失败1,“一对一”,对同一个协议,一个对象只能设置一个代理delegate,所以单例对象就不能用代理;

 二、block 

block 常见的几种场景:回调、传参。

1:写法更简练,不需要写protocol、函数等等

2,block注重结果的传输:比如对于一个事件,只想知道成功或者失败,并不需要知道进行了多少或者额外的一些信息

3,block需要注意防止循环引用:

4、block出栈需要将使用的数据从栈内存拷贝到堆内存,当然对象的话就是加计数,使用完或者block置nil后才消除;delegate只是保存了一个对象指针,直接回调,没有额外消耗。相对C的函数指针,只多做了一个查表动作

 第三:notification(通知)

 “一对多”,在APP中,很多控制器都需要知道一个事件,应该用通知

 面试题四:runloop

简介:runloop 其实就是一个一直运行的循环。用于等等和 处理 各种事件。一个线程一次只能执行一个任务,执行完成后线程就会退出。如果我们需要一个机制,让线程能随时处理事件但并不退出,通常的代码逻辑是这样的。

 function loop() {

    initialize();

    do {

        varmessage = get_next_message();

        process_message(message);

    } while (message !=quit);

}

 IOS面试题

面试题五:多线程

 (一)NSThread

优点:NSThread 比其他两个轻量级

缺点:需要自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销.

 (二)Cocoa NSOperation

简介:NSOperation

NSOperationQueue

NSOperation是个抽象类,使用它必须用它的子类,可以实现它或者使用它定义好的两个子类:NSInvocationOperation 和 NSBlockOperation。

 优点:1、不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上。

2、设置线程执行的优先级。

3、可以控制线程 的状态。比如(开始start)、(取消 clean)

4、添加依赖关系。(但是要)

 添加依赖关系要注意一下3点:

1.不要建立循环依赖,会造成死锁,原因同循环引用

2.使用依赖建议只使用NSInvocationOperation,NSInvocationOperation和NSBlockOperation混用会导致依赖关系无法正常实现。

3.依赖关系不光在同队列中生效,不同队列的NSOperation对象之前设置的依赖关系一样会生效
(三)GCD(全称:Grand Central Dispatch)

 Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。在iOS4.0开始之后才能使用。GCD是一个替代诸如NSThread, NSOperationQueue, NSInvocationOperation等技术的很高效和强大的技术。现在的iOS系统都升级到7了,所以不用担心该技术不能使用。

 GCD会自动根据任务在多核处理器上分配资源,优化程序。系统给每一个应用程序提供了三个concurrent dispatch queues。这三个并发调度队列是全局的,它们只有优先级的不同。因为是全局的,我们不需要去创建。我们只需要通过使用函数dispath_get_global_queue去得到队列,如下: 

dispatch_group_async

dispatch_group_async可以实现监听一组任务是否完成,完成后得到通知执行其他的操作。这个方法很有用,比如你执行三个下载任务,当三个任务都下载完成后你才通知界面说完成的了dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行

 runtime

1、objective_c 是一门动态语言,在编译是不能决定调用哪个函数。只有在运行时才能决定调用那些函数。

2、runTime 基本上是C和汇编写的。

3、与runtime 系统交互:1、objectIve _c源代码。2、Foundation 框架的NSObject 定义方法 3、runTime函数直接调用。

4、进行消息发送和转发。

面试题七:项目实战

问题一:tableView 滑动卡的问题主要是因为。

原因:tableView 滑动卡的问题主要是因为:从缓存中或者是从本地读取图片给UIImage的时候耗费的时间。

把UIImage赋值给图片的时候在主线程。
子线程不能更新UI 所有的UI跟新都是主线程执行了.

问题二:在单利中创建数组应该注意些什么。

单利里面添加 NSMutableArray 的时候,防止多个地方对它同时便利和修改的话,需要加原子属性。并且用strong,,,并且写一个遍历和修改的方法。加上锁。   Lock   UnLock