iOS面试及答案.docx
- 文档编号:23926716
- 上传时间:2023-05-22
- 格式:DOCX
- 页数:64
- 大小:214.40KB
iOS面试及答案.docx
《iOS面试及答案.docx》由会员分享,可在线阅读,更多相关《iOS面试及答案.docx(64页珍藏版)》请在冰豆网上搜索。
iOS面试及答案
史上最全的iOS面试题及答案
iOS面试小贴士
———————————————回答好下面的足够了-------------------------------------
多线程、特别是NSOperation和GCD的内部原理。
运行时机制的原理和运用场景。
SDWebImage的原理。
实现机制。
如何解决TableView卡的问题。
block和代理的,通知的区别。
block的用法需要注意些什么。
strong,weak,retain,assign,copynomatic等的区别。
设计模式,mvc,单利,工厂,代理等的应用场景。
单利的写法。
在单利中创建数组应该注意些什么。
NSString的时候用copy和strong的区别。
响应值链。
NSTimer在子线程中应该手动创建NSRunLoop,否则不能循环执行。
UIScrollView和NSTimer组合做循环广告图轮播的时候有一个属性可以控制当上下滚动tableview的时候广告轮播图依然正常滚动。
Xcode最新的自动布局。
。
。
这个很多公司都用。
尽量自学下。
git,和svn的用法。
。
。
git的几个命令简单的记下。
。
。
友盟报错可以查到具体某一行的错误,原理是什么。
Instrument 可以检测电池的耗电量、和内存的消耗。
的用法。
动画CABaseAnimationCAKeyAni…. CATrans….. CAGoup…. 等熟悉。
。
ARC的原理。
自己写过什么自定义控件就最好了。
。
———————————————回答好上面的足够了-------------------------------------
__block和__weak修饰符的区别其实是挺明显的:
1.__block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型。
2.__weak只能在ARC模式下使用,也只能修饰对象(NSString),不能修饰基本数据类型(int)。
3.__block对象可以在block中被重新赋值,__weak不可以。
tableView滑动卡的问题主要是因为:
从缓存中或者是从本地读取图片给UIImage的时候耗费的时间。
需要把下面的两句话放到子线程里面:
1.NSData *imgData = [NSData dataWithContentsOfURL:
[NSURL URLWithString:
app.icon]]; //得到图像数据
2. UIImage *image = [UIImage imageWithData:
imgData];
把UIImage赋值给图片的时候在主线程。
子线程不能更新UI所有的UI跟新都是主线程执行了。
手指滑动屏幕了。
或者屏幕的某个方法执行了。
子线程里面加入NSTimer的时候需要手动添加NSRunloop 否则不能循环。
单利里面添加NSMutableArray的时候,防止多个地方对它同时便利和修改的话,需要加原子属性。
并且用strong,,,并且写一个遍历和修改的方法。
加上锁。
Lock UnLock
__weakViewController* weakSelf=self;
GCD里面用__weak防止内存释放不了,循环引用。
二、SDWebImage内部实现过程
1.入口setImageWithURL:
placeholderImage:
options:
会先把placeholderImage显示,然后SDWebImageManager根据URL开始处理图片。
2.进入SDWebImageManager-downloadWithURL:
delegate:
options:
userInfo:
,交给SDImageCache从缓存查找图片是否已经下载queryDiskCacheForKey:
delegate:
userInfo:
.
3.先从内存图片缓存查找是否有图片,如果内存中已经有图片缓存,SDImageCacheDelegate回调imageCache:
didFindImage:
forKey:
userInfo:
到SDWebImageManager。
4.SDWebImageManagerDelegate回调webImageManager:
didFinishWithImage:
到UIImageView+WebCache等前端展示图片。
5.如果内存缓存中没有,生成NSInvocationOperation添加到队列开始从硬盘查找图片是否已经缓存。
6.根据URLKey在硬盘缓存目录下尝试读取图片文件。
这一步是在NSOperation进行的操作,所以回主线程进行结果回调notifyDelegate:
。
7.如果上一操作从硬盘读取到了图片,将图片添加到内存缓存中(如果空闲内存过小,会先清空内存缓存)。
SDImageCacheDelegate回调imageCache:
didFindImage:
forKey:
userInfo:
。
进而回调展示图片。
8.如果从硬盘缓存目录读取不到图片,说明所有缓存都不存在该图片,需要下载图片,回调imageCache:
didNotFindImageForKey:
userInfo:
。
9.共享或重新生成一个下载器SDWebImageDownloader开始下载图片。
10.图片下载由NSURLConnection来做,实现相关delegate来判断图片下载中、下载完成和下载失败。
11.connection:
didReceiveData:
中利用ImageIO做了按图片下载进度加载效果。
12.connectionDidFinishLoading:
数据下载完成后交给SDWebImageDecoder做图片解码处理。
13.图片解码处理在一个NSOperationQueue完成,不会拖慢主线程UI。
如果有需要对下载的图片进行二次处理,最好也在这里完成,效率会好很多。
14.在主线程notifyDelegateOnMainThreadWithInfo:
宣告解码完成,imageDecoder:
didFinishDecodingImage:
userInfo:
回调给SDWebImageDownloader。
15.imageDownloader:
didFinishWithImage:
回调给SDWebImageManager告知图片下载完成。
16.通知所有的downloadDelegates下载完成,回调给需要的地方展示图片。
17.将图片保存到SDImageCache中,内存缓存和硬盘缓存同时保存。
写文件到硬盘也在以单独NSInvocationOperation完成,避免拖慢主线程。
18.SDImageCache在初始化的时候会注册一些消息通知,在内存警告或退到后台的时候清理内存图片缓存,应用结束的时候清理过期图片。
19.SDWI也提供了UIButton+WebCache和MKAnnotationView+WebCache,方便使用。
20.SDWebImagePrefetcher可以预先下载图片,方便后续使用。
从上面流程可以看出,当你调用setImageWithURL:
方法的时候,他会自动去给你干这么多事,当你需要在某一具体时刻做事情的时候,你可以覆盖这些方法。
比如在下载某个图片的过程中要响应一个事件,就覆盖这个方法:
1
2
3
4
5
6
7
8
9
10
11
//覆盖方法,指哪打哪,这个方法是下载imagePath2的时候响应
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadImageWithURL:
imagePath2 options:
SDWebImageRetryFailed progress:
^(NSInteger receivedSize, NSInteger expectedSize) {
NSLog(@"显示当前进度");
} completed:
^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
NSLog(@"下载完成");
}];
对于初级来说,用sd_setImageWithURL:
的若干个方法就可以实现很好的图片缓存。
UIButton的父类是UIControl UIControl的父类是UIViewUIView的父类是UIResponder
http状态吗:
302是请求重定向。
500以上是服务器错误。
400以上是请求链接错误或者找不到服务器。
200以上是正确。
100以上是请求接受成功。
HTTPKeep-Alive详解[转]
HTTP是一个请求<->响应模式的典型范例,即客户端向服务器发送一个请求信息,服务器来响应这个信息。
在老的HTTP版本中,每个请求都将被创建一个新的客户端->服务器的连接,在这个连接上发送请求,然后接收请求。
这样的模式有一个很大的优点就是,它很简单,很容易理解和编程实现;它也有一个很大的缺点就是,它效率很低,因此Keep-Alive被提出用来解决效率低的问题。
Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接。
市场上的大部分Web服务器,包括iPlanet、IIS和Apache,都支持HTTP Keep-Alive。
对于提供静态内容的网站来说,这个功能通常很有用。
但是,对于负担较重的网站来说,这里存在另外一个问题:
虽然为客户保留打开的连接有一定的好处,但它同样影响了性能,因为在处理暂停期间,本来可以释放的资源仍旧被占用。
当Web服务器和应用服务器在同一台机器上运行时,Keep- Alive功能对资源利用的影响尤其突出。
此功能为HTTP1.1预设的功能,HTTP1.0加上Keep-Aliveheader也可以提供HTTP的持续作用功能。
Keep-Alive:
timeout=5,max=100
timeout:
过期时间5秒(对应httpd.conf里的参数是:
KeepAliveTimeout),max是最多一百次请求,强制断掉连接
就是在timeout时间内又有新的连接过来,同时max会自动减1,直到为0,强制断掉。
见下面的四个图,注意看Date的值(前后时间差都是在5秒之内)!
HTTP/1.0
在HTTP/1.0版本中,并没有官方的标准来规定Keep-Alive如何工作,因此实际上它是被附加到HTTP/1.0协议上,如果客户端浏览器支持Keep-Alive,那么就在HTTP请求头中添加一个字段 Connection:
Keep-Alive,当服务器收到附带有Connection:
Keep-Alive的请求时,它也会在响应头中添加一个同样的字段来使用Keep-Alive。
这样一来,客户端和服务器之间的HTTP连接就会被保持,不会断开(超过Keep-Alive规定的时间,意外断电等情况除外),当客户端发送另外一个请求时,就使用这条已经建立的连接
HTTP/1.1
在HTTP/1.1版本中,官方规定的Keep-Alive使用标准和在HTTP/1.0版本中有些不同,默认情况下所在HTTP1.1中所有连接都被保持,除非在请求头或响应头中指明要关闭:
Connection:
Close ,这也就是为什么Connection:
Keep-Alive字段再没有意义的原因。
另外,还添加了一个新的字段Keep-Alive:
,因为这个字段并没有详细描述用来做什么,可忽略它
Notreliable(不可靠)
HTTP是一个无状态协议,这意味着每个请求都是独立的,Keep-Alive没能改变这个结果。
另外,Keep-Alive也不能保证客户端和服务器之间的连接一定是活跃的,在HTTP1.1版本中也如此。
唯一能保证的就是当连接被关闭时你能得到一个通知,所以不应该让程序依赖于Keep-Alive的保持连接特性,否则会有意想不到的后果
Keep-Alive和POST
在HTTP1.1细则中规定了在一个POST消息体后面不能有任何字符,还指出了对于某一个特定的浏览器可能并不遵循这个标准(比如在POST消息体的后面放置一个CRLF符)。
而据我所知,大部分浏览器在POST消息体后都会自动跟一个CRLF符再发送,如何解决这个问题呢?
根据上面的说明在POST请求头中禁止使用Keep-Alive,或者由服务器自动忽略这个CRLF,大部分服务器都会自动忽略,但是在未经测试之前是不可能知道一个服务器是否会这样做。
1、常用的方法dispatch_async
为了避免界面在处理耗时的操作时卡死,比如读取网络数据,IO,数据库读写等,我们会在另外一个线程中处理这些操作,然后通知主线程更新界面。
用GCD实现这个流程的操作比前面介绍的NSThread NSOperation的方法都要简单。
代码框架结构如下:
1.dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
2. // 耗时的操作
3. dispatch_async(dispatch_get_main_queue(), ^{
4. // 更新界面
5. });
6.});
如果这样还不清晰的话,那我们还是用上两篇博客中的下载图片为例子,代码如下:
1.dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
2. NSURL * url = [NSURL URLWithString:
@"
3. NSData * data = [[NSData alloc]initWithContentsOfURL:
url];
4. UIImage *image = [[UIImage alloc]initWithData:
data];
5. if (data !
= nil) {
6. dispatch_async(dispatch_get_main_queue(), ^{
7. self.imageView.image = image;
8. });
9. }
10.});
运行显示:
是不是代码比NSThread NSOperation简洁很多,而且GCD会自动根据任务在多核处理器上分配资源,优化程序。
系统给每一个应用程序提供了三个concurrentdispatchqueues。
这三个并发调度队列是全局的,它们只有优先级的不同。
因为是全局的,我们不需要去创建。
我们只需要通过使用函数dispath_get_global_queue去得到队列,如下:
1.dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
这里也用到了系统默认就有一个串行队列main_queue
1.dispatch_queue_t mainQ = dispatch_get_main_queue();
虽然dispatchqueue是引用计数的对象,但是以上两个都是全局的队列,不用retain或release。
2、dispatch_group_async的使用
dispatch_group_async可以实现监听一组任务是否完成,完成后得到通知执行其他的操作。
这个方法很有用,比如你执行三个下载任务,当三个任务都下载完成后你才通知界面说完成的了。
下面是一段例子代码:
1.dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
2.dispatch_group_t group = dispatch_group_create();
3.dispatch_group_async(group, queue, ^{
4. [NSThread sleepForTimeInterval:
1];
5. NSLog(@"group1");
6.});
7.dispatch_group_async(group, queue, ^{
8. [NSThread sleepForTimeInterval:
2];
9. NSLog(@"group2");
10.});
11.dispatch_group_async(group, queue, ^{
12. [NSThread sleepForTimeInterval:
3];
13. NSLog(@"group3");
14.});
15.dispatch_group_notify(group, dispatch_get_main_queue(), ^{
16. NSLog(@"updateUi");
17.});
18.dispatch_release(group);
dispatch_group_async是异步的方法,运行后可以看到打印结果:
2012-09-2516:
04:
16.737gcdTest[43328:
11303]group1
2012-09-2516:
04:
17.738gcdTest[43328:
12a1b]group2
2012-09-2516:
04:
18.738gcdTest[43328:
13003]group3
2012-09-2516:
04:
18.739gcdTest[43328:
f803]updateUi
每个一秒打印一个,当第三个任务执行后,upadteUi被打印。
3、dispatch_barrier_async的使用
dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行
例子代码如下:
1.dispatch_queue_t queue = dispatch_queue_create("gcdtest.rongfzh.yc", DISPATCH_QUEUE_CONCURRENT);
2.dispatch_async(queue, ^{
3. [NSThread sleepForTimeInterval:
2];
4. NSLog(@"dispatch_async1");
5.});
6.dispatch_async(queue, ^{
7. [NSThread sleepForTimeInterval:
4];
8. NSLog(@"dispatch_async2");
9.});
10.dispatch_barrier_async(queue, ^{
11. NSLog(@"dispatch_barrier_async");
12. [NSThread sleepForTimeInterval:
4];
13.
14.});
15.dispatch_async(queue, ^{
16. [NSThread sleepForTimeInterval:
1];
17. NSLog(@"dispatch_async3");
18.});
打印结果:
2012-09-2516:
20:
33.967gcdTest[45547:
11203]dispatch_async1
2012-09-2516:
20:
35.967gcdTest[45547:
11303]dispatch_async2
2012-09-2516:
20:
35.967gcdTest[45547:
11303]dispatch_barrier_async
2012-09-2516:
20:
40.970gcdTest[45547:
11303]dispatch_async3
请注意执行的时间,可以看到执行的顺序如上所述。
4、dispatch_apply
执行某个代码片段N次。
dispatch_apply(5,globalQ,^(size_tindex){
//执行5次
});
copy与retain:
1、copy其实是建立了一个相同的对象,而retain不是;
2、copy是内容拷贝,retain是指针拷贝;
3、copy是内容的拷贝,对于像NSString,的确是这样,但是如果copy的是一个NSArray呢?
这时只是copy了指向array中相对应元素的指针.这便是所谓的"浅复制".
4、copy的情况:
NSString*newPt=[ptcopy];
此时会在堆上重新开辟一段内存存放@"abc"比如0X1122内容为@"abc同时会在栈上为newPt分配空间比如地址:
0Xaacc内容为0X1122因此retainCount增加1供newPt来管理0X1122这段内存;
assign与retain:
1、assign:
简单赋值,不更改索引计数;
2、assign的情况:
NSString*newPt=[ptassing];
此时newPt和pt完全相同地址都是0Xaaaa内容为0X1111即newPt只是pt的别名,对任何一个操作就等于对另一个操作,因此retainCount不需要增加;
3、assign就是直接赋值;
4、retain使用了引用计数,retain引起引用计数加1,release引起引用计数减1,当引用计数为0时,dealloc函数被调用,内存被回收;
5、retain的情况:
NSString*newPt=[ptretain];
此时newPt的地址不再为0Xaaaa,可能为0Xaabb但是内容依然为0X1111。
因此newPt和pt都可以管理"abc"所在的内存,因此retainCount需要增加1 ;
readonly:
1、属性是只读的,默认的标记是读写,如果你指定了只读,在@im
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- iOS 面试 答案