iOS面试题收集

1.@property 后面可以有哪些修饰符?
2.什么情况使用 weak 关键字,相比 assign 有什么不同?比如?
3.怎么使用copy关键字?
4.@synthesize和@dynamic分别有什么作用?
5.在block内如何修改block外部变量?
6.产生死锁的必要条件?
7.解决死锁的基本办法?
8.Object-c的类可以多重继承么?可以实现多个接口么?Category是什么?重写一个类的方式用继承好还是分类好?为什么?
9.父类实现深拷贝时,子类如何实现深度拷贝。父类没有实现深拷贝时,子类如何实现深度拷贝?
10.KVO,NSNotification,delegate及block区别?
11.KVC如何实现,如何进行键值查找。KVO如何实现?
介绍一下观察者模式?
12.说一下http协议?
13.利用NSURLConnection进行断点续传?
14.SDWebImage内部实现原理?
15.简单介绍一下socket?
16.支付宝支付流程?
17.支付宝支付过程中遇到的问题?
18.CALayer 和 UIView 的区别?
19.常见的 Objective-C 的数据类型有那些,和C的基本数据类型有什么区别?如:NSInteger和int?
20.weak的实现原理?

考察一个面试者基础咋样,基本上问一个 @property 就够了:
1、@property 后面可以有哪些修饰符?

  • 线程安全的:
    • atomic,nonatomic
  • 访问权限的
    • readonly,readwrite
  • 内存管理(ARC)
    • assign,strong,weak,copy
  • 内存管理(MRC)
    • assign,retain,copy
  • 指定方法名称
    • setter=
    • getter=

2、什么情况使用 weak 关键字,相比 assign 有什么不同?比如?

  • 在ARC中,出现循环引用的时候,必须要有一端使用weak,比如:自定义View的代理属性.
  • 已经自身已经对它进行一次强应用,没有必要在强引用一次,此时也会使用weak,自定义View的子控件属性一般也使用weak,但是也可以使用strong
  • weak当对象销毁的时候,指针会被自动设置为nil,而assign不会, assigin 可以用于修饰非OC对象,而weak必须用于OC对象

3、怎么使用copy关键字?

  • 对于字符串和block的属性一般用copy修饰

字符串使用copy是为了防止外部把字符串内容改了,影响该属性(具体可参考这篇文章)

  • block使用copy是在MRC遗留下来的,在MRC中,方法内部的block是在在栈区的,使用copy可以把它放到堆区.在ACR中对于block使用copy还是strong效果是一样的

4、@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方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定

5、在block内如何修改block外部变量?

  • 通过 __bock修改的外部变量,可以在block内部修改
  • 想装B的话可以说一下__bock内部做了什么事(参考文章)

6、产生死锁的必要条件?

  • 互斥条件:进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占用。

  • 请求和保持条件:当进程因请求资源而阻塞时,对方获得的资源保持不放。

  • 不剥夺条件:进程已获得得资源在未使用完之前,不能剥夺,只能在使用完时由自己释放。

  • 环路等待条件:在发生死锁时,必然存在一个进程--资源的环形链。

7、解决死锁的基本办法

  • 预防死锁:
    • 资源一次性分配。
    • 可剥夺条件:即当某进程新的资源为满足时,释放已经占有的资源(破坏不可剥夺条件)
    • 资源有序分配法:系统给每类资源赋予一个编号,每个进程按编号递增的顺序请求资源,释放则相反(破坏环路等待条件)。
  • 避免死锁:
    预防死锁的几种策略,会严重的损坏系统性能。因此在避免死锁时,要施加较弱的限制,从而获得较满意的系统性能。由于在避免死锁的策略中,允许进程动态的申请资源。因而,系统在进行资源分配之前预先计算资源分配的安全性,若此次分配不会导致系统进入不安全状态,则将资源分配给进程,否则,进程等待。

  • 检测死锁:
    首先为每个进程和每个资源指定一个唯一的号码;然后建立资源分配表和进程等待表。

  • 解决死锁:
    当发现有进程死锁时,便应立即把它从死锁状态中解脱出来,常采用的方法有:

    • 剥夺资源:从其他进程剥夺足够数量的资源给死锁进程,以解决死锁状态。
    • 撤销进程:可以直接撤销死锁进程或者撤销代价最小的进程,直至有足够的资源可用,死锁状态消除为之;所谓的代价就是指优先级、运行代价,进程的重要性和价值等。

8、Object-c的类可以多重继承么?可以实现多个接口么?Category是什么?重写一个类的方式用继承好还是分类好?为什么?

  • Object-c的类不可以多重继承;可以实现多个接口,通过实现多个接口可以完成C++的多重继承;Category是类别,一般情况用分类好,用Category去重写类的方法,仅对本Category有效,不会影响到其他类与原有类的关系。

9、父类实现深拷贝时,子类如何实现深度拷贝。父类没有实现深拷贝时,子类如何实现深度拷贝

  • 深拷贝同浅拷贝的区别:浅拷贝是指针拷贝,对一个对象进行浅拷贝,相当于对指向对象的指针进行复制,产生一个新的指向这个对象的指针,那么就是有两个指针指向同一个对象,这个对象销毁后两个指针都应该置空。深拷贝是对一个对象进行拷贝,相当于对对象进行复制,产生一个新的对象,那么就有两个指针分别指向两个对象。当一个对象改变或者被销毁后拷贝出来的新的对象不受影响。
  • 实现深拷贝需要实现NSCoying协议,实现- (id)copyWithZone:(NSZone *)zone 方法。当对一个property属性含有copy修饰符的时候,在进行赋值操作的时候实际上就是调用这个方法。
  • 父类实现深拷贝之后,子类只要重写copyWithZone方法,在方法内部调用父类的copyWithZone方法,之后实现自己的属性的处理
  • 父类没有实现深拷贝,子类除了需要对自己的属性进行处理,还要对父类的属性进行处理。

10、KVO,NSNotification,delegate及block区别?

  • KVO就是cocoa框架实现的观察者模式,一般同KVC搭配使用,通过KVO可以监测一个值的变化,比如View的高度变化。是一对多的关系,一个值的变化会通知所有的观察者。
  • NSNotification是通知,也是一对多的使用场景。在某些情况下,KVO和NSNotification是一样的,都是状态变化之后告知对方。NSNotification的特点,就是需要被观察者先主动发出通知,然后观察者注册监听后再来进行响应,比KVO多了发送通知的一步,但是其优点是监听不局限于属性的变化,还可以对多种多样的状态变化进行监听,监听范围广,使用也更灵活。
  • delegate 是代理,就是我不想做的事情交给别人做。比如狗需要吃饭,就通过delegate通知主人,主人就会给他做饭、盛饭、倒水,这些操作,这些狗都不需要关心,只需要调用delegate(代理人)就可以了,由其他类完成所需要的操作。所以delegate是一对一关系。
  • block是delegate的另一种形式,是函数式编程的一种形式。使用场景跟delegate一样,相比delegate更灵活,而且代理的实现更直观。

11、KVC如何实现,如何进行键值查找。KVO如何实现
介绍一下观察者模式?

  • 观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。
  • 《设计模式》中提到在以下任一情况下可以使用观察者模式:
    • 1.当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
    • 2.当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。
    • 3.当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的

12、说一下http协议?

  • HTTP是一个属于应用层的面向对象的协议,客户端向服务器端经过Http协议发送一个Request,服务器端收到Request后经过一些处理返回客户端一个Response
  • HTTP协议的主要特点:
    • 支持C/S(客户/服务器)模式。
    • 简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST,每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
    • 无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
    • 无状态:HTTP协议是无状态协议,无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

13、利用NSURLConnection进行断点续传?
NSUrlConnection实现断点续传的关键是自定义http request的头部的range域属性
在ios中使用NSMutableURLRequest来定义头部域

NSURL *url1=[NSURL URLWithString:@"下载地址";  
NSMutableURLRequest* request1=[NSMutableURLRequest requestWithURL:url1];  
[request1 setValue:@"bytes=20000-" forHTTPHeaderField:@"Range"];   
[request1 setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];  
NSData *returnData1 = [NSURLConnection sendSynchronousRequest:request1 returningResponse:nil error:nil];   
[self writeToFile:returnData1 fileName:@"SOMEPATH"];  

14、SDWebImage内部实现原理?
SDWebImage底层实现有沙盒缓存机制,主要由三块组成
1、内存图片缓存
2、内存操作缓存
3、磁盘沙盒缓存

 sd_setImageWithURL:  //图片缓存的基本代码,就是这么简单                   
 [self.image1 sd_setImageWithURL:imagePath1];
 
 sd_setImageWithURL:  completed:  //用block 可以在图片加载完成之后做些事情
 [self.image2 sd_setImageWithURL:imagePath2 completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {            
           NSLog(@"这里可以在图片加载完成之后做些事情");
}];

 sd_setImageWithURL:  placeholderImage: //给一张默认图片,先使用默认图片,当图片加载完成后再替换
 [self.image1 sd_setImageWithURL:imagePath1 placeholderImage:[UIImage imageNamed:@"default"]];
 
sd_setImageWithURL:  placeholderImage:  completed: //使用默认图片,而且用block 在完成后做一些事情
 [self.image1 sd_setImageWithURL:imagePath1 placeholderImage:[UIImage imageNamed:@"default"] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
         NSLog(@"图片加载完成后做的事情");
 }];

 sd_setImageWithURL:  placeholderImage:  options: //options 选择方式
 [self.image1 sd_setImageWithURL:imagePath1 placeholderImage:[UIImage imageNamed:@"default"] options:SDWebImageRetryFailed];

除了带options选项的方法,其他的方法都是综合存储,也就是内存缓存和磁盘缓存结合的方式,如果你只需要内存缓存,那么在options这里选择SDWebImageCacheMemoryOnly就可以了。

入口 setImageWithURL:placeholderImage:options:会先把 placeholderImage 显示,然后 SDWebImageManager根据 URL 开始处理图片。进入SDWebImageManager-downloadWithURL:delegate:options:userInfo:,交给 SDImageCache从缓存查找图片是否已经下载 .queryDiskCacheForKey:delegate:userInfo:
先从内存图片缓存查找是否有图片,如果内存中已经有图片缓存,SDImageCacheDelegate回调 imageCache:didFindImage:forKey:userInfo:SDWebImageManager SDWebImageManagerDelegate 回调 webImageManager:didFinishWithImage:UIImageView+WebCache 等前端展示图片。

如果内存缓存中没有,生成 NSInvocationOperation 添加到队列开始从硬盘查找图片是否已经缓存。
根据 URLKey 在硬盘缓存目录下尝试读取图片文件。这一步是在 NSOperation 进行的操作,所以回主线程进行结果回调 notifyDelegate:。如果上一操作从硬盘读取到了图片,将图片添加到内存缓存中(如果空闲内存过小,会先清空内存缓存)。SDImageCacheDelegate 回调 imageCache:didFindImage:forKey:userInfo :进而回调展示图片。如果从硬盘缓存目录读取不到图片,说明所有缓存都不存在该图片,需要下载图片,回调 imageCache:didNotFindImageForKey:userInfo:

共享或重新生成一个下载器 SDWebImageDownloader 开始下载图片。图片下载由 NSURLConnection 来做,实现相关 delegate 来判断图片下载中、下载完成和下载失败。

connection:didReceiveData:中利用 ImageIO 做了按图片下载进度加载效果。connectionDidFinishLoading:数据下载完成后交给 SDWebImageDecoder 做图片解码处理。

图片解码处理在一个NSOperationQueue完成,不会拖慢主线程 UI。如果有需要对下载的图片进行二次处理,最好也在这里完成,效率会好很多。

在主线程notifyDelegateOnMainThreadWithInfo: 宣告解码完成,imageDecoder:didFinishDecodingImage:userInfo: 回调给SDWebImageDownloader`。

imageDownloader:didFinishWithImage: 回调给 SDWebImageManager 告知图片下载完成。

通知所有的 downloadDelegates 下载完成,回调给需要的地方展示图片。

将图片保存到 SDImageCache 中,内存缓存和硬盘缓存同时保存。写文件到硬盘也在以单独 NSInvocationOperation 完成,避免拖慢主线程。

SDImageCache 在初始化的时候会注册一些消息通知,在内存警告或退到后台的时候清理内存图片缓存,应用结束的时候清理过期图片。

SDWI 也提供了 UIButton+WebCache 和 MKAnnotationView+WebCache,方便使用。

SDWebImagePrefetcher 可以预先下载图片,方便后续使用。

15、简单介绍一下socket

  • socket()函数:int socket(int domain, int type, int protocol);
    socket函数对应于普通文件的打开操作。普通文件的打开操作返回一个文件描述字,而socket()用于创建一个socket描述符(socket descriptor),它唯一标识一个socket。这个socket描述字跟文件描述字一样,后续的操作都有用到它,把它作为参数,通过它来进行一些读写操作。
    正如可以给fopen的传入不同参数值,以打开不同的文件。创建socket的时候,也可以指定不同的参数创建不同的socket描述符,socket函数的三个参数分别为:

    • domain:即协议域,又称为协议族(family)。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。
    • type:指定socket类型。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等(socket的类型有哪些?)。
    • protocol:故名思意,就是指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议(这个协议我将会单独开篇讨论!)。
  • bind()函数:int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    正如上面所说bind()函数把一个地址族中的特定地址赋给socket。例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket。
    函数的三个参数分别为:

    • sockfd:即socket描述字,它是通过socket()函数创建了,唯一标识一个socket。bind()函数就是将给这个描述字绑定一个名字。
    • addr:一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址
    • addrlen:对应的是地址的长度
  • listen()、connect()函数:
    int listen(int sockfd, int backlog);
    int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    如果作为一个服务器,在调用socket()、bind()之后就会调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。
    listen函数的第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数。socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。
    connect函数的第一个参数即为客户端的socket描述字,第二参数为服务器的socket地址,第三个参数为socket地址的长度。客户端通过调用connect函数来建立与TCP服务器的连接。

16、支付宝支付流程?

  • 1.与支付宝签约,获得商户ID和账号ID
  • 2.下载相应的公钥私钥文件,加密签名的时候要用
  • 3.下载集成支付宝SDK
  • 4.生成订单信息
  • 5.调用支付宝客户端,由支付宝客户端跟支付宝安全服务器打交道
  • 6.支付完毕后返回支付结果给商户客户端和服务器

17、支付宝支付过程中遇到的问题?

  • 1、编译的时候出现can't find interface declaration for 'NSObject"'superClass of 'Base64'原因是缺少
    #import#import 这两个头文件
  • 2、找不到头文件,解决:Build Settings --> Search Paths --> Header Search paths : $(SRCROOT)/支付宝的文件路径
  • 3、 显示系统繁忙,请稍后再试(ALI10)配置的秘钥有问题
  • 4、交易订单处理失败,请稍后再试。(ALI59)是因为我们生成的订单有问题

18、CALayer 和 UIView 的区别?

  • 每个 UIView 内部都有一个 CALayer 在背后提供内容的绘制和显示,并且 UIView 的尺寸样式都由内部的 Layer 所提供。两者都有树状层级结构,layer 内部有 SubLayers,View 内部有 SubViews.但是 Layer 比 View 多了个AnchorPoint
  • 在 View显示的时候,UIView 做为 Layer 的 CALayerDelegate,View 的显示内容由内部的 CALayer 的 display
  • CALayer 是默认修改属性支持隐式动画的,在给 UIView 的 Layer 做动画的时候,View 作为 Layer 的代理,Layer 通过 actionForLayer:forKey:向 View请求相应的 action(动画行为)
  • layer 内部维护着三分 layer tree,分别是 presentLayer Tree(动画树),modeLayer Tree(模型树), Render Tree (渲染树),在做 iOS动画的时候,我们修改动画的属性,在动画的其实是 Layer 的 presentLayer的属性值,而最终展示在界面上的其实是提供 View的modelLayer
  • 两者最明显的区别是 View可以接受并处理事件,而 Layer 不可以

19、常见的 Objective-C 的数据类型有那些,和C的基本数据类型有什么区别?如:NSInteger和int?
Objective-C的数据类型有NSString,NSNumber,NSArray,NSMutableArray,NSData等等,这些都是class,创建后便是对象,而C语言的基本数据类型int,只是一定字节的内存空间,用于存放数值;NSInteger是基本数据类型,并不是NSNumber的子类,当然也不是NSObject的子类。NSInteger是基本数据类型Int或者Long的别名(NSInteger的定义typedef long NSInteger),它的区别在于,NSInteger会根据系统是32位还是64位来决定是本身是int还是long。

20、weak的实现原理

你可能感兴趣的:(iOS面试题收集)