iOS常见面试题总结

1.协议的原理和本质

protocol无论是在哪个领域都是一种约束,规范。在OC中的协议主要用于在各个类之间进行回调传值。协议有委托方,代理方,委托方是协议的制定者,需要声明协议的方法,实现协议的对象。代理方,是协议的遵守着,需要遵守协议,并实现协议中的必要方法。

2.ARC自动引用计数机制

cocoa采用了引用计数(reference counting)机制,每一个对象有一个关联的“整数retainCount”用于记录对象的使用情况。对象被引用时retaincount+1,外部环境结束对象的使用后retaincount-1.
当retaincount为0的时候,该对象被销毁。
当我们使用alloc、new或者copy的我们需要销毁这个对象。release函数,只是将对象的retaincount值减1,并不是删除对象。
当retaincount==0的时候,系统会发给对象一个dealloc消息,另外千万不要手动调用dealloc,因为我们不知道何时何地何人还会使用该对象。应该老老实实依赖引用计数机制完成内存管理。
释放对象所有权的函数除了release还有autorelease,这是一种延迟操作。

3.retain、copy、assign、release、auto release、dealloc 关键字

copy:建立一个索引计数为1的对象,然后释放旧对象,主要用于nsstring;
retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1对其他NSObject和其子类
assign:简单赋值,不更改索引计数
release:手动释放对象
dealloc:它的作用是,当对象的引用计数为0,系统会自动调用dealloc方法,回收内存。
autorelease原理:
a.先建立一个autorelease pool
b.对象从这个autorelease pool里面生成。
c.对象生成之后调用autorelease函数,这个函数的作用仅仅是在autorelease pool 中做个标记,让pool记得将来release一下这个对象。
d.程序结束时,pool本身也需要release,此时pool会把每一个标记为autorelease的对象release一次。如果某个对象此时retaincount大于1,这个对象还是没有被销毁。
(weak和strong)不同的是 当一个对象不再有strong类型的指针指向它的时候 它会被释放,即使还有weak型指针指向它。weak表示如果没有人指向它了,它就会被清除内存,同时被指向nil

4.self.name与_name的区别

1.首先通过self.xxx访问的方法的引用:包含了set和get方法。而通过下划线是获取自己的
2.self.xxx是对属性的访问;而下划线是对局部变量的访问。所有被声明为属性的成员,默认情况下编译器会帮助我们生成set和get方法。编译器在生成getter,setter方法时是有优先级的,他首先查找当前的类中用户是否定义了属性的getter,setter方法,如果有,则编译器会跳过,不会再生成,使用用户定义的方法。也就是说你在使用self.xxx时是调用一个getter方法。会使引用计数加1,而_xxx不会使用引用计数加1的。
所以使用self.xxx是更好的选择,因为这样可以兼容懒加载,同时也避免了使用下滑线的时候忽略了self这个指针,后者容易在block中造成循环引用。同时,使用 _ 是获取不到父类的属性,因为它只是对局部变量的访问。
最后总结:self方法实际上是用了get和set方法间接调用,下划线方法是直接对变量操作。

5.继承 与 类别 的联系与区别

联系:可以给一个类扩展新的方法,或修改已有的方法
区别:
1.继承修改的方法不会对父类原方法产生影响;类别修改的方法相当于替换了原有方法
2.以viewcontroller举例,继承一个viewcontroller相当于建立一个新的页面;而给一个viewcontroller添加类别用于增加或修改原viewcontroller上的方法
3.类别支持开发人员针对自己构建的类,把相关的方法分组到多个单独的文件中,对于大型而复杂的类,这有助于提高可维护性,并简化单个源文件的管理。
4.针对系统提供的一些类,例如:NSString,NSArray,NSNumber等类,系统本身不提倡使用继承去扩展方法,因为这些类内部实现对继承有所限制,所以最后使用类别来进行方法扩展。
5.理论上类别不能新增属性

6.Strong 与 Weak 的区别

weak和strong不同的是 当一个对象不再有strong类型的指针指向它的时候 它会被释放,即使还有weak型指针指向它。一旦最后一个strong型指针离去,这个对象将被释放,所有剩余的weak型指针都将被清除。可能有个例子形容是妥当的。想象我们的对象是一条狗,狗想要跑掉(被释放)。strong型指针就像是拴住的狗。只要你用纤绳挂住狗,狗就不会跑掉。如果有5个人牵着一条狗(5个strong型指针指向一个对象),除非5个纤绳都脱落,否则狗是不会跑掉的。weak型指针就像是一个小孩指着狗喊到:“看!一只狗在那”只要狗一直被拴着,小孩就能看到狗,(weak指针)会一直指向它。只要狗的纤绳脱落,狗就会跑掉,不管有多少小孩在看着它。
只要最后一个strong型指针不再指向对象,那么对象就会被释放,同时所有的weak型指针都将会被清除。

7.assign是指针赋值,不对引用计数操作,使用之后如果没有置为nil,可能就会产生野指针;而weak一旦不进行使用后,永远不会使用了,就不会产生野指针

8.《1》尝试使用xcode的转换工具
《2》在编译选项中,为MRC的程序添加-fno-objc-arc标记,表明在编译时,该文件用MRC编译
《3》将MRC的第三方库直接编译成静态库使用

9.Object-c中没有多继承,Cocoa中所有的类都是NSObject的子类,多继承在这里是用protocol委托代理来实现的

10.objective c 中既有私有办法,也有私有变量

先说私有办法:
由于Objective-C的动态消息传递机制,OC中不存在真正意义上的私有办法。
但是如果你不在.h文件中声明,只在.m文件中实现,或在.m文件的Class Extension里声明,那么基本上和私有方法差不多。
至于私有变量是可以通过@private来声明的,例如:
@interface Sample:NSObject
{
@private NSString *aaa;
}
@property (nonatomic,strong) NSString *hoge;

  • (void)foo;
    @end
    则 aaa 变量是私有的。而属性hoge是默认公有。
    现在Apple官方文档里是用property比较多,直接定义instance variable (实例变量)少。将property定义到.m的Class Extension (类扩展) 也基本上和私有变量差不多。
    简而言之,将你希望公有的放到.h文件,私有的放到.m文件。在improt.h (.m文件也是可以improt的,但是我们一般不这么做)。

11.#import .h 和 @class+类名的区别

1.import会包含这个类的所有信息,包括实体变量和方法,而@class只是告诉编译器,其后面声明的名称是类的名称,至于这些类是如何定义的,暂时不用考虑,后面会再告诉你。
2.在头文件中,一般只需要知道被引用的类的名称就可以了。不需要知道其内部的实体变量和方法,所以在头文件中一般使用@class来声明这个名称是类的名称。而在实现类里面,因为会用到这个引用类的内部的实体变量和方法,所以需要使用#import来包含这个被引用类的头文件。
3.在编译效率方面考虑,如果你有100个头文件都#import了同一个头文件,或者这些文件是一次引用的,如A–>B,B–>C,C–>D这样的引用关系。当最开始的那个头文件有变化的话,后面所有引用它的类都需要重新编译,如果你的类有很多的话,这将耗费大量的时间。而用@class则不会。
4.如果有循环依赖关系,如A–>B,B–>A这样的相互依赖关系,如果使用#import来相互包含,那么就会出现编译错误,如果使用@class在两个类的头文件中相互声明,则不会有编译错误出现。
所以,一般来说,@class是放在interface中的,只是为了在interface中引用这个类,把这个类作为一个类型来用的。在实现这个接口的实现类中,如果需要引用这个类的实体变量或者方法之类的,还是需要import在@class中声明的类进来。

12.页面传值都有哪些实现方式
代理、block、通知、属性传值、单例传值、NSUserDefault

13.深拷贝和浅拷贝的区别
浅拷贝只复制对象的本身,对象里的属性、包含的对象不做复制,源对象和副本指向的是同一个对象,对象的引用计数器+1.其实相当于做了一次retain操作
深拷贝即复制对象本身,对象的属性也会复制一份。源对象和副本指向的是不同的两个对象,源对象引用计数器不变,副本计数器设置为1
只有不可变对象创建不可变副本才是浅拷贝,其它都是深拷贝

14、系统中有哪些对象是单例
UIApplication (应用程序实例)
NSNotificationCenter (消息中心)
NSFileManager (文件管理)
NSUserDefaults (应用程序设置)
NSURLCache (请求缓存)
NSHTTPCookieStorage (应用程序cookies池)

15.MVC设计模式
使用了MVC的应用程序被分为3个核心部件:视图(view)、模型(model)、控制器(controller)。他们各司其职,既分工明确又相互合作。
model:持有我们应用程序的数据,和定义怎么操纵它
view :处理用户的操作和展示model
controller :它的作用是协调view和model把数据展示到view上
controller可以直接和model通信,也可以直接和view通信。model和view永远不能直接通信。

16.iOS中哪些技术符合观察者模式
在iOS开发中,会接触到经典观察者模式的实现方法有NSNotificationCenter,KVO,Delegate等

17.什么是工厂方法?
在基类中定义创建对象的一个接口,让子类决定实例化哪个类,工厂方法让一个类的实例化延迟到子类中进行。工厂方法要解决的问题是对象的创建时机,它提供了一种拓展的策略,很好的复合了开放封闭原则,工厂方法也叫作虚构造器。

18.什么是代理模式,实现代理需要注意什么
在项目中我们经常会用到代理的设计模式,这是iOS的一种消息传递方式,也可以通过这种方式来传递一些参数,iOS中对代理支持的很好,有代理对象、委托者、协议三部分组成。
协议:用来指定代理双方可以做什么,必须做什么;
代理:根据指定的协议,完成委托方需要实现的功能;
委托:根据指定的协议,指定代理去完成什么功能;

19.请简述storyboard和xib的联系和区别
联系:都用来描述软件界面
都用interface builder工具来编辑
区别:xib是轻量级的,用来描述局部的UI界面
storyboard是重量级的,用来描述整个软件的多个界面,并且能展示多个界面之间的跳转关系

20.请简述UITableView对Cell的重用机制
UITableView维护了一个复用队列,当Cell从屏幕上消失时,就会进入复用队列。下一个Cell要显示的时候通过复用ID查询在复用队列是否有同一类型的Cell,若有取出来复用,若没有就会重新创建一个Cell。重用机制通过对Cell的重复使用,来减少内存的使用。

21.如何用UIScrollView实现无线加载多张图片?
创建一个UIScrollViwe,高度为屏幕的高度,宽度为三倍的屏幕宽度,设置为按屏幕滑动,设置偏移量(屏幕宽度,0)。第一个屏幕宽度和第三个屏幕宽度贴一个UIImageView显示图片的前一张和后一张,中间贴一个UIScrollView,大小为屏幕的大小,在上面贴一个UIImageViw显示要显示的图片。当向左滑动,通过UIScrollView的代理方法,检测到之后将第一个屏幕宽度和第三个屏幕宽度上的UIImageView改为图片的前一张和后一张,中间scrollview上的UIimageview上的图片改为当前图片,同时设置最外部的UIscrollview的偏移量为(屏幕宽度,0);向右滑动与向左滑动同理。

22.请简述视图控制器的生命周期
1.alloc 创建对象,分配空间
2.init 初始化对象
3.loadview 从xib中载入视图
4.viewDidLoad 载入完成,可以自定义数据和控件了
5.viewWillAppear 视图将要出现在屏幕上
6.viewDidAppear 视图已经出现在屏幕上
7.viewWillDisappear 视图将要消失
8.viewDidDisappear 视图已经消失
9.销毁

23.UITableView有哪些优化方式
1.提前计算并缓存好高度(布局),因为heightForRowAtlndexPath:是调用最频繁的方法;
2.异步绘制,遇到复杂界面,遇到性能瓶颈时,可能就是突破口
3.滑动时按需加载,这个在大量图片展示,网络加载的时候很管用
4.Cell的复用
5.尽量少使用或者不用透明的图层
6.用异步加载数据,缓存请求结果
7.减少subview 的数量
8.异步刷新
9.提前注册

24.请简述iOS中的时间传递机制
点击一个UIView或产生一个触摸事件A,这个触摸事件A会被添加到由UIApplication管理的事件队列中(即,首先接收到事件的是UIApplication)。
UIApplication 会从事件队列中取出最前面的事件(此处假设为触摸事件A),把事件A传递给应用程序的主窗口(keywindow)。
窗口会在视图层次结构中找到一个最适合的视图来处理触摸事件。
事件交由第一响应者对象处理,如果第一响应者不处理,事件被沿着响应链向上传递,交给下一个响应者,直到事件被丢弃。

25.UITableView中有哪些必须要实现的数据源的方法
1.每组的行数 -(NSInteger)tableview:(UITableview )tableview numberOfRowsInSection:(NSInteger)section
2.每行的cell -(UITableViewCell
)tableview:(UITableView )tableview cellForRowAtIndexPath:(NSIndexPath)indexPath

26.请简述HTTP协议中get请求和post请求的区别
get和post的主要区别表现在数据传递上

get:
1.在请求URL后面以 ? 的形式跟上发给服务器的参数,多个参数之间用 & 隔开,比如http://www.test.com/login?username=123&pwd=234&type=JSON
2.由于浏览器和服务器对URL长度有限制,因此在URL后面附带的参数是限制的,通常不能超过1kb
post:
1.发给服务器的参数全部放在请求体中
2.理论上,post传递的数据量没有限制(具体还得看服务器的处理能力)
选择:
1.如果要传递大量数据,比如文件上传,只能用post请求
2.get的安全性比post要差些,如果包含机密、敏感信息,建议用post
3.如果仅仅是索取数据(数据查询),建议用get
4.如果是增加、修改、删除数据,建议使用post

27.请简述你对异步请求数据的理解
异步请求:通过两个线程调用服务器,一个线程发送,一个线程接收
请求行为在后台,不会导致页面假死

28.iOS中哪些技术可以实现开辟线程,他们之间的联系和区别是什么?
答:创建方式:NSThread,NSOperation,GCD.
联系:
三种编程方式都是针对线程操作来讲的,从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单
区别:
*NSThread:
优点:NSThread比其他两个轻量级,使用简单
缺点:需要自己管理线程的生命周期、线程同步、加锁、睡眠以及唤醒等。线程同步对数据的加锁会有一定的系统开销
*NSOperation:
不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上
NSOperation是面向对象的,基于OC语言实现的API。两种默认实现:NSInvocationOperation 和 NSBlockOperation.
*GCD:
Grand Central Dispatch 是由苹果开发的一个多核编程的解决方案。iOS4.0+才能使用,是替代NSThread,NSOperation的高效和强大的技术
GCD是基于C语言的API,提供了非常多强大的函数。GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)。程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码。我们在编写GCD相关代码的时候,面对的是函数,而不是方法。GCD中的函数大多数都以dispatch开头。

29.NThread中线程是如何进行通信的?
答:线程间通信:在1个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信。
线程间通信的体现:
1个线程传递数据给另1个线程
在1个线程中执行完特定任务后,转到另1个线程继续执行任务

猜你喜欢

转载自blog.csdn.net/weixin_39487291/article/details/88549389