美文网首页
记一次阿里的电话面试

记一次阿里的电话面试

作者: homosum | 来源:发表于2017-05-13 18:31 被阅读0次

    星期四预约的面试,今天上午十点正式的电话面试的,没发挥好,感觉面试的很糟(真的是不擅长面试= =)。发帖纪录一样,作经验积累。

    上来先要求作了自我介绍,面试官对经验没有细问,直接奔现在做的App,问上架版本做了几个月,然后是现在的做的版本有哪些技术亮点。说了一个音乐播放的进度管理,然后问了 两个App如何做到音频同时播放 的问题。自己开发版本的音频是听书之类的,使用时默认顶到音乐播放之类的app播放。对这种情况没有研究,坦言不知道了。后来查了一下是可以通过 AVAudioSessionCategory对播放模式进行控制的。

    在其他App音乐在播放的时候,自己的APP播放开启 AVAudioSessionAVAudioSessionCategoryAmbient(混音模式)可以让两个App的音频同时播放。而这里有个问题是,AVAudioSessionCategoryAmbient模式下App无法后台播放。解决方法是在App进入后台的- (void)applicationWillResignActive:(UIApplication *)application方法中,将AVAudioSession的模式改为AVAudioSessionCategoryPlayback(独占模式)即可APP后台播放同时APP前台播放音频时也不会顶到其他App音频。

    接着是一个类朋友圈功能是tableView的绘制,自己是重写layoutSubviews的方法进行异步绘制。(虽然没问,这里解释下为什么不使用drawRect方法进行cell绘制)在14年的WWDC中Kevin Cathey的demo在绘制view时,用的是layoutSubviews,并做了以下阐述:
    If I were to implement drawRect, that's not going to get us the best performance; whereas, using sublayers and subviews is going to get us really good performance.
    layoutSubviews默认未做任何事,先于drawRect执行,需要根据需求重写,执行时机如下:
    1、init初始化不会触发layoutSubviews
    但是是用initWithFrame 进行初始化时,当rect的值不为CGRectZero时,也会触发
    2、addSubview会触发layoutSubviews
    3、设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化
    4、滚动一个UIScrollView会触发layoutSubviews
    5、旋转Screen会触发父UIView上的layoutSubviews事件
    6、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件

    通过设置-layoutIfNeedflag调用,-drawRect则是通过 -displayIfNeededflag调用。
    使用layoutSubviews而不是drawRect原因如下:
    1、默认在bounds改变时并不会自动调用-setNeedsDisplay方法
    2、绘制很消耗性能,而相对来说移动subView性能消耗就少很多
    3、在layoutSubviews中,CA可以决定哪些subview需要绘制,而忽略掉一些不需要绘制的view(如:被不透明view挡住的view,不在屏幕内的view,和clipsToBounds=YES的view中不在视图内的子view,或只绘制一个大视图的一部分)。
    当然这里的麻烦是,在一些特许异常下layoutSubviews有时会绘制不正确,该绘制出的视图没有绘制出来(在做朋友圈的时候遇到过第一个cell偶尔绘制不出来的情况,手动调用layoutSubviews解决)。

    这些不是面试问的,拉回正题。关于绘制面试的问题是,绘制内存的控制对应的是滑动速度的干涉控制。

    这个问题没有回答好,面试完了解了一下。iOS的CA层是对openGL的封装,绘制时首先CPU会给layer分配内存来绘制bitmap,叫做backing store。而这块bitmap缓冲区的指针,叫做CGContextRef。layer的content指向bitmap(在做画板时,使用CAShapeLayer这个类绘制,内存会得到大大优化,原因是CAShapeLayer是一个通过矢量图形而不是用bitmap来绘制得的图层子类,孙源的一篇博客里有介绍)。对于图片绘制的优化,借用一个大触的解释:
    当你用 UIImage 或 CGImageSource 的那几个方法创建图片时,图片数据并不会立刻解码。图片设置到 UIImageView 或者 CALayer.contents 中去,并且 CALayer 被提交到 GPU 前,CGImage 中的数据才会得到解码。这一步是发生在主线程的,并且不可避免。如果想要绕开这个机制,常见的做法是在后台线程先把图片绘制到 CGBitmapContext 中,然后从 Bitmap 直接创建图片。目前常见的网络图片库都自带这个功能。

    我当时并没有回答出这些,后来仔细看了SDWebImage的源码,确实在- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data异步接收数据时使用 CGBitmapContextCreateImage()对图片数据进行了处理。

    另一个需要优化的地方就是速度控制了。TableView 快速滑动时,大量异步绘制任务提交到后台线程去执行。可能绘制任务还没有完成就可能已经被取消了。如果这时仍然继续绘制,就会造成大量的 CPU 资源浪费,甚至阻塞线程并造成后续的绘制任务迟迟无法完成。需要提前判断当前绘制任务是否已经被取消;在绘制每一行文本前,isCancelled() 来进行判断,保证被取消的任务能及时退出,不至于影响后续操作。
    - (void)layoutSubviews { [super layoutSubviews]; [self.layer cleanUp];//设置isCancelled [self.layer drawContent]; }

    然后还问了一个runloop的问题,runloop的原理和有哪些使用。因为平常使用不多,就简单说了下,runloop是对CFRunloop的封装,主线程默认开启,其他线程对应的runloop需要手动开启。作用是可使线程保活,AFNetworking中线程异步任务需要开启runloop防止任务没完成,线程被系统回收。还有NSTimer的使用这些,需要timer所在线程的runloop保持timer运行这些(感觉自己的回答对方并不满意)。

    最后是网络请求里的GCD和NSOperation。说了一些常用的函数,async,sync,once,main_queue,global_queue,NSOperationQueue这些。GCD多线程控制使用起来都是系统帮你处理好的,比较方便。需要灵活性的话,优先级队列之类的就使用NSOperation了。

    这次面试的基本内容就这些了,作为自己学习路上的一个警示吧,路漫漫还需跨大步子继续赶。

    相关文章

      网友评论

          本文标题:记一次阿里的电话面试

          本文链接:https://www.haomeiwen.com/subject/htjxxxtx.html