一、某公司(one)
- 1.手写单例和通知和代理
- 2不用__block的可变数组,如何改变值?
答:
1.__加上__block,就可以修改外部变量。
2.要想修改一个外部不可变数组的值,可以先将不可变数组的值复制到一个可变数组中,
__并加上__block,在block中修改可变数组的值,最后存进不可变数组中。(用可变数组去截获)
-
3.通知不移除会产生什莫问题?
移除通知,由哪个控制器创建由那个控制器移除,谁创建谁移除,最好在dealloc方法中移除,如果通知不能及时的移除掉,
当下次进入该控制器时会重复创建NSNotificationCenter,在对应方法中发送通知给上一次创建的通知, 但是上一个通知
所在的控制器已被干掉,所以这时候就会报错。是因为, 再次发送通知的时候会因为找不到接收对象而崩溃。 -
4.四种回到主线程的方式?
NSThread
第一种
[self performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:NO];
GCD
第二种
dispatch_async(dispatch_get_main_queue(), ^{});
NSOperationQueue
第三种
[[NSOperationQueue mainQueue] addOperationWithBlock:^{}];}
第四种
dispatch_queue_create(mainThread.syc.concurrent.queue,DISPATCH_QUEUE_CONCURRENT) -
5如何刷新一个单元格?
# 一个section刷新
NSIndexSet *indexSet=[[NSIndexSet alloc]initWithIndex:2];
[tableview reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic];
# 一个cell刷新
NSIndexPath *indexPath=[NSIndexPath indexPathForRow:3 inSection:0];
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath,nil] withRowAnimation:UITableViewRowAnimationNone]; -
6.定时器创建的三种类型(大概看看就成,能说出点来)
iOS 中三种定时器的NSTimer、CADisplayLink、GCD。
用法:
1. NSTimer
1) 创建方法
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:
selfselector:@selector(action:) userInfo:nil repeats:NO];
TimerInterval : 执行之前等待的时间。比如设置成1.0,就代表1秒后执行方法
target : 需要执行方法的对象。
selector : 需要执行的方法
repeats : 是否需要循环
2) 释放方法
[timer invalidate];
注意 :调用创建方法后,target对象的计数器会加1,直到执行完毕,自动减1。如果是循环执行的话,
就必须手动关闭,否则可以不执行释放方法。
3). 特性
存在延迟 ,不管是一次性的还是周期性的timer的实际触发事件的时间,都会与所加入的RunLoop和
RunLoop Mode有关,如果此RunLoop正在执行一个连续性的运算,timer就会被延时出发。重复性的timer
遇到这种情况,如果延迟超过了一个周期,则会在延时结束后立刻执行,并按照之前指定的周期继续执行。
必须加入Runloop
使用上面的创建方式,会自动把timer加入MainRunloop的NSDefaultRunLoopMode中。
如果使用以下方式创建定时器,就必须手动加入Runloop:
NSTimer *timer = [NSTimer timerWithTimeInterval:5 target:self
selector:@selector(timerAction) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
2. CADisplayLink
1). 创建方法
self.displayLink = [CADisplayLink displayLinkWithTarget:self
selector:@selector(handleDisplayLink:)];
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
2). 停止方法
[self.displayLink invalidate];
self.displayLink = nil;
**当把CADisplayLink对象add到runloop中后,selector就能被周期性调用,类似于重复的NSTimer被启动了;
执行invalidate操作时,CADisplayLink对象就会从runloop中移除,selector调用也随即停止,类似于NSTimer的invalidate方法。**
3). 特性
屏幕刷新时调用
CADisplayLink是一个能让我们以和屏幕刷新率同步的频率将特定的内容画到屏幕上的定时器类。
CADisplayLink以特定模式注册到runloop后,每当屏幕显示内容刷新结束的时候,runloop就
会向CADisplayLink指定的target发送一次指定的selector消息, CADisplayLink类对应的
selector就会被调用一次。所以通常情况下,按照iOS设备屏幕的刷新率60次/秒
延迟
iOS设备的屏幕刷新频率是固定的,CADisplayLink在正常情况下会在每次刷新结束都被调用,精确度相当高。
但如果调用的方法比较耗时,超过了屏幕刷新周期,就会导致跳过若干次回调调用机会。
如果CPU过于繁忙,无法保证屏幕60次/秒的刷新率,就会导致跳过若干次调用回调方法的机会,跳过次数取决CPU的忙碌程度。
使用场景
从原理上可以看出,CADisplayLink适合做界面的不停重绘,比如视频播放的时候需要不停地获取下一帧用于界面渲染。
4). 重要属性
frameInterval
NSInteger类型的值,用来设置间隔多少帧调用一次selector方法,默认值是1,即每帧都调用一次。
duration
readOnly的CFTimeInterval值,表示两次屏幕刷新之间的时间间隔。
需要注意的是,该属性在target的selector被首次调用以后才会被赋值。
selector的调用间隔时间计算方式是:调用间隔时间 = duration × frameInterval。
3.GCD方式
执行一次
重复执行
-
7.GCD的优缺点(Operation、GCD)
优点:不需要关心线程管理,数据同步的事情。
两者区别:NSOperationQueue可以方便的管理并发、NSOperation之间的优先级。
GCD主要与block结合使用。代码简洁高效
1. 性能:GCD更接近底层,而NSOperationQueue则更高级抽象,所以GCD在追求性能的底层操作来说,是速度最快的。
这取决于使用Instruments进行代码性能分析,如有必要的话.
2. 从异步操作之间的事务性,顺序行,依赖关系。GCD需要自己写更多的代码来实现,
而NSOperationQueue已经内建了这些支持.
3.如果异步操作的过程需要更多的被交互和UI呈现出来,NSOperationQueue会是一个更好的选择。
底层代码中,任务之间不太互相依赖,而需要更高的并发能力,GCD则更有优势。 -
8.SDWebImage的原理?
- 入口 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: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 可以预先下载图片,方便后续使用。
- 如何解决tableView卡顿问题
前面也提了很多方案。通过设置最大并发数, 设置当前页的cell, 而不是把所有cell一次性设置完,
以及数据图片的三级缓存, 直接保存在内存中和沙盒缓存中进行读取. 降低网络请求的次数,
不仅节约用户流量. 也会保证tableView滑动的流畅性
推荐:http://www.jianshu.com/p/e00854ab5567 - 9.SDWebImage怎样实现图片的缓存机制?tableView里的图片是如何加载的?
- 图片的缓存, 内存缓存, 沙盒缓存, 操作缓存, 以tableViewController为例:
- 每次cell需要显示,都需要重新调用- (UITableViewCell )tableView:( UITableView )tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { }方法
- 每次调用tableView显示行的数据源方法时, 如果需要从网络加载图片, 就需要将加载图片这样的耗时操作放在子线程上执行,
从网络上下载的图片可以以键值对的形式保存在定义的可变字典中,将每张图片的唯一的路径作为键,
将从网络下载下来的图片作为值, 保存在内存缓存中, 这样每次滑动tableView cell重用时就直接判断内存缓存中有没有需要的图片,
如果有就不需要再次下载,在没有出现内存警告或者程序员手动清理内存缓存时, 就直接从内存缓存中获取图片.
- 为了每次退出程序,再次进入程序时,不浪费用户的流量, 需要将第一次进入程序时加载的图片保存在本地沙盒缓存文件中,
在沙盒中保存的图片数据没有被改变之前,下次开启程序就直接从沙盒的缓存文件中读取需要显示的图片, 并将沙盒缓存文件夹(Cache)
中保存的图片保存到内存缓存中, 这样用户每次滑动tableView cell重用时直接从内存缓存中读取而不是从沙盒中读取, 节约时间.
推荐:http://www.jianshu.com/p/328e503900d0 - 10.AFNetworking做过断点续传?
断点续传的主要思路:
1.检查服务器文件信息
2.检查本地文件
3.如果比服务器文件小, 断点续传, 利用 HTTP 请求头的 Range 实现断点续传
4.如果比服务器文件大,重新下载
5.如果和服务器文件一样,下载完成
推荐:http://www.open-open.com/lib/view/open1455547008651.html(断点续传) - 11.如何快速创建10个按钮?
for循环、谓词貌似也可以忘记了
推荐:http://www.jianshu.com/p/7111fe6d526c
12)如何自定义button上下排列?
1.自定义view
2.自定义button
3.按钮原生的写法改变titleEdgeInsets和imageEdgeInsets
4.storyboard调整EdgeInset
推荐:http://www.jianshu.com/p/3052a3b14a4e