天天看点

iOS技术面试题

OC:分类(优点。和延展的差别)block(原理,底层,作用。)代理循环引用(原因,解决)、内存

分类 : 一般用于扩展一个类的方法,它可以不用创建一个新的类,可是不可以扩充成员变量,使用分类重写本类的方法后无法再调用原来的方法,使用分类还可以将一个类的定义写在不同的文件内,可以拆分业务逻辑,使一个分类的功能更专一

延展(extension)延展相当于匿名的分类。一般写在实现文件中面(.m文件)。它能够扩充私有变量和方法。可是变量和方法仅仅能在本文件内有效(私有的),其它文件不能够调用。(而且一般不会有人通过延展扩充方法)。

继承 使用继承扩充一个类。须要再创建一个子类,能够扩充成员变量和方法,能够重写父类的方法,并且能够通过super调用父类的方法。可是因为继承于父类.

block

1.保存代码。

一段代码在合适的时间运行就调用block(1、请求成功时弹出一个提示框 2、异步运行完之后回调)。

2block一般用来两个的类的数据逆传递(改动昵称,姓名。性别的时候) A-B  B往

A传数据。

3.block也能够将一个操作当做函数或方法的參数来传递

代理的循环引用    

Delegate使用weak来修饰?      循环引用 

比如在tableviewController其中,tableView的Delegate使用weak来修饰,假设使用strong或者copy修饰,delegate作为tableview的一个成员变量,tableViewController会有一个强指针指向tableView,而tableview会有一个强指针指向delegate,这个时候delegate的引用计数就会加1,普通情况下tableview的代理都是指向自己的控制器,由于delegate使用strong修饰,所以delegate会有一个强指针指向tableViewController。tableViewController的引用计数也会加1,tableviewController和delegate创建时引用计数初始化都是1。此时它们的引用计数都是2,再ARC机制下,当控制器移除时,它们的引用计数会自己主动减1,然后各自的引用计数都是1,就再也不会释放了,这个时候就会照成内存泄露

简单点说:

(在tableViewController中delegate使用strong修饰时,delegate会有一个强指针指向controller,而controller会对内部的delegate做一次retain操作。就会有一个强指针指向delegate,当内存释放是。controller要释放就要等delegate先被释放,而delegate释放要等controller先释放,这个时候谁都无法释放,就造成了循环引用)

内存

在OC其中没有垃圾回收机制(GC),而是使用引用计数 来管理内存的释放,OC中有手动引用计数(_MRC)和自己主动引用计数(ARC)当oc中的对象使用alloc new 创建时引用计数就会加1,被retain、copy一次引用计数也会加1,当被release 或 autorelease时 引用计数减1,当引用计数下降为0时,该对象的内存就会被释放,对象被销毁

在ARC中我们已经无需再手动管理内存的释放,ARC并非oc的特性。而是xcode编译器的特性,xcode会自己主动帮我们加上release 或autorelease等代码

内存优化: 1、懒载入(1、使用时再载入 2、保证对象仅仅创建一次 )

                      2、复用 轮播 两个imageView复用 或者用collectionView做无线轮播

                      3、使用CF开头的东西一定要记得释放

                      4、切图:背景仅仅须要切一小条即可 1K 2K    启动图片通常是10K 20K         

                      5、profile ->  leaks   检查内存泄露 

UItableView循环利用(原因,流程)    数据持久化(详细用哪一种)     手势    UIView动画  

在tableView中第一次显示cell时。会创建新的cell(cell会相应一个标识)而且仅仅显示当前tableView展现出来的数量,当cell从tableView中消失时。会被放入到tableView的缓存池其中,下一个cell出现时不会又一次创建新的cell ,而是先从缓存池中拿出相应标识的cell使用。可是缓存池的cell包括着上一次的图片,而我如今要显示的cell并没有图片,所以会出现利用有图片的cell。全部布局混乱

而想要解决问题,1、都有label,都要显示文字:就是当cell出现时使用数据给其赋值(覆盖掉原有的数据)。将数据和cell绑定,这样能够覆盖缓存池中cell的数据,当然也能够在其显示曾经将其数据清空   2、要显示的cell没有图片。而缓存池中的cell有图片:在setTopic里推断要显示的cell是否有图片,假设有就把传给cell的topic模型里的图片数据赋值给图片控件,假设没有图片,将图片控件hidden

数据持久化

经常使用的数据持久化方式有:

         属性列表(plist文件)

        归档(存储自己定义的类的对象时;存储用户的数据(昵称。uid))

        偏好设置(NSUserDefault(存储一些简单的数据(用户的设置)))

        sqlite3、core data、FMDB(大量数据的时候)  

        createtable student IF NOT EXISTS (id integer, name text, age text)

当有少量基础数据类型的数据和NSArray、NSDictionary须要储存而且无需加密时,就以使用plist文件

储存少量的数据,并且须要加密,比方登录password、获取的accessToken时,或者须要储存对象。比方做收藏夹、近期訪问,都能够使用键值归档

偏好设置的话就是储存一些用户设置信息。比方程序中设置其中的一些开关的Bool值等版本等等

当须要储存大量的数据时,比方须要离线缓存一些数据。就须要使用数据库了,sqlit3是c语言的东西,使用起来不是特别方便,而FMDB是封装的sqlite3使用起来比較方便,所以一般开发其中都是使用FMDB

UIView动画 是对Coreanimation的封装

Core animation:

组动画:运行一组动画

属性动画:基础动画  关键帧动画

转场动画:能够自己定义

使用:

1.创建动画对象   CAKeyFrameAnimation * anim = [alloc] init];

2.设置属性  keyPath = @“layer 的属性”    而且支持KVC

3.加入到layer上自己主动运行。

注意:1、coreanimation动画并不会真正改变frame 仅仅是作用有layer

             2、core animation动画运行完会自己主动回复到原来的位置。假设不想让其恢复。fullModel complateXXX 

GCD  NSOperationQueue(底层、经常使用的函数,什么时候用)

在开发过程其中使用的多线程方式一般有三种。NSThread,NSOperation/NSOperationQueue,GCD

NSThread须要手动管理线程的生命周期,使用NSThread能够中途取消任务。也能够设置线程的优先级(0-1 越大优先级越高,默认都是0.5)在NSObject中苹果官方对其进行了封装

能够直接调用

-(void)performSelectorInBackGround:(SEL)aSelectorwithObject:(id)arg;

在后台直接调用一个方法运行。本质就是自己主动建一个线程,然后在当中运行一个操作

-(void)performSelector:(SEL)aSelectoronThread:(NSThread*)the withObject:(id)arg waitUntilDone:(BOOL)wait

在指定线程上运行一个操作。须要用户创建一个线程对象

-(void)performSelectorOnMainThread:(SEL)aSelectorwithObject:(id)arg waitUntilDone:(BOOL)wait;

在主线程运行一个操作

-(void)performSelector:(SEL)aSelectorwithObject:(id)arg afterDelay:(NSTimeInterval)time;

另开一个线程延迟指定时间后再运行这个操作

NSOperationQueue 是一个线程队列 能够创建一个NSOperation对象来放入队列中运行,通常是使用NSOperation的子类来创建一个任务,NSOperation有两个子类,一个是NSInvocationOperation 还有一个是NSBlockOperation,使用NSOperationQueue能够设置最大线程并发数量,而且能够使用[operation1addDependency:operation2】来_加入依赖,operation1须要等到operation2运行完成后再运行

GCD

GCD是一种基于C语言的一种多线程开发机制,

在GCD其中有两种队列  串行队列:在当前线程运行,加入在其中的任务依照顺序依次运行

                               并发队列:将加入进来的任务分配在可用的处理器上,同一时候运行。

在GCD中也有两种运行方法。dispatch_async 异步运行

                                      dispatch_sync  同步运行

能够通过dispatch_queue_t queue = dispatch_queue_creat(“你的队列名”,DISPATCH_QUEUE_SERIAL)

来创建一个串行队列

通过dispach_get_main_queue() 获得主队列 一般在主队列中运行更新UI的方法

而获取并发队列的方法类似 dispatch_queue_creat)(“你的队列名”,DISPATCH_QUEUE_CONCURRENT)

可是一般在开发中我们无需创建一个新的并发队列。我们能够通过

dispatch_get_global_queue 来获取一个全局并行队列:  

以下说一下GCD其中经常使用的方法

dispatch_apply():反复运行某个任务,只是这种方法没有办法异步运行(只是能够用dispatch_async包装一下就OK了)

dispatch_once() 这种方法仅仅会运行一次。从此以后在程序没有退出曾经就不会在运行,一般用来自己定义一个单例对象是使用

dispatch_after()能够延迟一定时间运行一个任务,而且是异步的。

尽管多线程可以提高程序的性能,可是有时候当多个线程抢夺同一个资源是就须要使用线程同步了 NSThread使用线程同步一般可以使用NSLock同步锁。还有NSCondition, 可是一般使用@synchronized(self){   }代码块,这样比較方便

@synchronized(self){

        // 改动

}

{

NSlock  l = [NSLockalloc]init];

[l lock];

// 改动操作

[l unlock];

}

网络编程:AFN 和 ASI

AFN和ASI都是网络请求数据的框架 可是它们两个有非常大的差别

1.AFN直接操作的对象是AFHTTPClient 它是一个实现了NSCoping协议的NSObject子类,AFHTTPClient是一个封装了一系列操作方法的工具类,处理请求的操作类是一系列单独的。基于NSOperation封装的。AFURLConnectionOperation的子类

ASI的直接操作对象是ASIHTTPRequest,是一个实现了NSCoping协议的NSOperation子类initialize和initwithURL:方法中初始化相关属性并配置一系列请求相关參数默认值,此外ASIHTTPRequest还提供了一系列方法用来配置请求对象

2.AFN对JSON,XML。Plist,Image四种数据进行了处理。开发人员能够直接得到想要的数据类型

ASI没有针对数据做不论什么处理。仅仅是预留了接口共开发人员使用

3.AFN是基于NSURL框架。而且仅仅提供异步调用方法,回调时使用block

ASI是基于CFNetwork框架,提供了同步异步两种方法,回调是能够使用代理。也能够使用block

4,ASI的底层是CFNetwork,而AFN的底层NSURL也是基于CFNetwork开发的,所以ASI比AFN更加底层

5,当项目网络逻辑不是特别复杂的时候能够使用AFN更加方便,当项目比較大。网络定制型要求高时。就能够考虑使用ASI

SDWebImage的底层

SDWebImage是使用NSOperation/NSOperationQueue进行异步载入图片,当它载入图片后会在程序沙盒下的缓存目录中创建一个目录。将下载的图片资源储存在目录其中,图片名就是图片的下载路径,当下次再次须要载入图片时,它会先在缓存目录中依据路径名进行查找假设找到就直接使用,假设没有再从网络上下载

项目:

自适应Cell(流程)  

1、自己定义Cell

2、最好对控件进行分层设计,这种设计方式能够添加代码的复用性。看起来也比較清晰,更改需求时,代码的变动也比較小

3、计算每一个控件的frame。创建frame模型 。里面计算每一个控件的frame

4、通过VC拿到frameModel   1、返回每一个cell的行高 2 把frame模型传给cell,给相应的控件frame赋值

程序构架

1、观察分析原型图

2、设计架构:是tabBarVC包括 多个navigationVC还是其它的情况

3、多控制器切换的话:假设4、5个VC,不须要考虑VC复用,假设20多个VC,考虑控制器的复用:1、3个tableView的循环利用 2、collectionView的cell中放tableView

1、写框架前 要细致分析各个模块及控制器之间的跳转和依赖的关系,比方分析一下看看这几个控制之间有没有什么样的view是能够重用的。假设有的话。能够自己定义一个view。以备以后重用时简单

自己定义控件(流程)

自己定义控件常常使用,普通情况下。自己定义一个控件首先你要知道这个控件是干嘛用得。它需不须要显示图片,文字,需不须要点击。需不须要变动frame等,然后依据相应的需求留下相应的接口。比方点击一个自己定义控件,那这个控件须要通知控制它被点击了,简单情况下假设仅仅有一个button。仅仅须要通知一个控制器,就能够通过外部定义一个 add_Target方法连接内部的button的addTarget方法

假设view处理的逻辑比較复杂须要使用代理协议来传递很多其它的信息,參数。假设一处点击须要通知多个控制器进行响应,就须要用到KVO。保证自己定义控件与其它控件或控制器之间尽量没有不论什么关系。调用时就是通过控件在.h中留下的方法(接口)进行操作的,减少耦合性。

适配:

适配原来使用的是autoResizeing。如今在storyboard和xib中通常是使用autolayout

适配时使用的第三方有    masonry

基于iOS SDK 的布局分类 UIView+AutoLayout

高寿东:SDAutoLayout

masonry的代码十分简洁。使用链式语法,使用起来也十分方便。以下说一下主要使用方法,比方布局一个view让它在显示居中。宽高都是100

[viewmas_makeConstraints:^(MASConstraintMaker *make) {

       make.center.equalTo(self.view);

       make.size.mas_equalTo(CGSizeMake(100, 100));

}];

这样就完毕了一个居中view的布局。这里面可用的属性有top,bottom,left,right,width,height,leading,trailing,centerX,centerY,baseline事实上还能够直接使用center,edges内边距

masonry一共同拥有3种布局方法

mas_makeConstraints:创建一个新的约束,在autoLayout中对同一个对象设置多个反复约束会报错

mas_updateConstraints:更新在block中出现的约束。不会出现反复的约束

mas_remakeConstraints:清除之前的全部约束。仅保留block中的新的约束

设置约束的方法也是三种

mas_equalTo()等于

mas_greaterThanOrEqualTo()

 大于等于mas_lessThanOrEqualTo()

小于等于

UIView+AutoLayout的使用

更接近autoLayout的底层,有三种设置方式,

第一种以autoSetDimension开头的,约束size类(就是设置宽高)

另外一种以autoPin开头。约束位置的(就是设置距离上下左右的距离)

第三种以autoAlign开头,约束对齐(就是设置XY轴对齐的)

语法简单一看就知道了

百度地图。及友盟分享

百度地图:

百度地图的集成过程并不复杂,下面是集成时须要注意的几点

1.在官网注冊应用。获取appkey.

2.下载SDK并导入项目中。

3.加入必要的框架。

4.注冊appkey。

遇到的问题:

0.百度地图的静态库使用c++编写的,所以项目中至少有一个.mm文件,不然会报错。

1.在appDelegate中启动百度地图引擎时,设置代理。在回调方法中提示错误參数230(假设正确的话是0)   解决的方法:这个时候你须要注意你的info.plist文件里的Bundle identifier 还有project里面的Bundle identifier 应该和你申请appkey 的时候填写的sdk 安全码不一致

2.提示引擎启动失败,这个通常是由于你拉入忘记拉入mapapi.bundle了

由于以后迅雷就不再更新.a 静态库了,所以在此使用的是BaiduMapAPI.framework,可是上述问题是两种类型都会遇到的问题

收藏、近期

收藏和近期主要就是封装一个业务类对数据进行添加和删除,保存数据时要重写数据的equalto方法(由于计算机是依据内存地址比較的,而有时候内存地址尽管不同,可是储存的数据确实一样的,所以一般依据数据的位置标识(比如id值)比較)

假设是做近期,就须要将上一次的数据删除,加入新的数据进来,假设在收藏时须要记录控件的编辑和选中状态,就须要在数据模型中加入对应的属性,利用数据来控制控件的状态

常出现的问题就是使用tableview时会出现循环利用的问题,这个问题就能够使用数据的值来避免,每次载入cell时,他的状态是受数据控制的,数据不会发生循环利用的问题。这个问题也就不会出现了

FMDB

使用FMDB的流程

1创建一个库 

2建一个表(表里面要定义你要储存的数据类型,就是字段())——》

3然后就是插入数据,改动,删除,查询数据

创表语句:create table  if  not exists t_student (id ingtger autoincrement primary key, name text, age integer)

增删改查必须记住

推送流程

本地推送一般能够用来提示长时间未进入应用的用户,也能够用来做闹铃。

(一个程序能够推送,首先你要配置推送证书)

以下具体说一下远程推送的流程:

1.当你的程序须要推送时,通过UIApplication中的registerUserNotification注冊远程推送,注冊后。你的程序会通过iOS系统向APNsserver请求,APNsserver接到请求后会将请求设备的device token(设备令牌)发送回你的应用,在UIApplication的代理方法中能够接收到device token,假设请求失败也会通过代理方法返回错误信息

2.当应用程序拿到device token后。就能够将device token传给应用提供商server。server就知道了这台设备能够推送消息了。然后将device token储存在server内部,device token的生成算法仅仅有苹果公司才知道,所以为了防止苹果改动算法造成推送失败,最好每次启动程序时都请求一次device token。在device token发生改变时。告诉server新的device token

(推送普通情况下是程序提供商向用户推送一些最新的消息或者资讯,只是比方QQ,微信等能够在离线的情况下进行消息的提醒,以下以qq推送离线消息为例。相比从server推送,qq离线消息的推送是由client编辑信息的)

3.如今假设程序要推送消息了,就能够将消息和要发送的对象的账号发送给程序提供商server,server会通过你要推送的对象的账号信息找到相应绑定的device token,然后将推送消息内容和device token传给APNsserver

4.APNsserver在接收到消息内容和device token后会查找已注冊的设备然后将相应的信息和device token推送到指定的设备上,设备通过device token中的app id找到要推送的app。然后信息会依照app的推送设置显示信息

二维码

做二维码的话,能够使用的第三发库有ZBar和ZXing 详细用法能够去网上查看文档

可是如今iOS中的AVFoundation框架中也集成了二维码扫描。用起来也十分方便,而且扫描速度也更快,性能更好。还能够使用AVFoundation框架生成二维码

iOS技术面试题