首页 > 技术文章 > iOS核心面试题

sundaysgarden 2016-06-17 20:21 原文


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/autor 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本身也需要rerlease, 此时pool会把每一个标记为autorelease的对象release一次。如果某个对象此时retain count大于1,这个对象还是没有被销毁。
    (weak和strong)不同的是 当一个对象不再有strong类型的指针指向它的时候 它会被释放 ,即使还有weak型指针指向它。weak表示如果还没有人指向它了,它就会被清除内存,同时被指向nil

4 self.name与_name的区别

    1.首先通过self.xxx 通过访问的方法的引用:包含了set和get方法。而通过下划线是获取自己的实例变量,不包含set和get的方法。

    2.self.xxx是对属性的访问;而xxx是对局部变量的访问。所有被声明为属性的成员,再ios5之前需要使用编译指令@synthesize 来告诉编译器帮助生成属性的getter和setter方法,之后这个指令可以不用认为的指定了,默认情况下编译器会帮助我们生成。编译器在生成getter,setter方法时是有优先级的,他首先查找当前的类中用户是否定义属性的getter,setter方法,如果有,则编译器会跳过,不会再生成,使用用户定义的方法。也就是说你在使用self.xxx时是调用一个getter方法。会使引用计数加一,而xxx不会使用引用技术加一的。

    所有使用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型指针指向1个对象),除非5个牵绳都脱落 ,否着狗是不会跑掉的。  weak型指针就像是一个小孩指着狗喊到:“看!一只狗在那” 只要狗一直被栓着,小孩就能看到狗,(weak指针)会一直指向它。只要狗的牵绳脱落,狗就会跑掉,不管有多少小孩在看着它。

  只要最后一个strong型指针不再指向对象,那么对象就会被释放,同时所有的weak型指针都将会被清除。
///////////////////////////////////////////////////////////////////////////////////////////////
100.私有api与 公开api的区别
        iPhone中的API除了公开的API:Published API外(或者叫文档中记录的API:Documented API),还有两类API:私有API:Private API和未公开的API:UnPublished API(或者叫文档中未记录的API:Undocumented API)。其中私有API是指放在PrivateFrameworks框架中的API,未公开的API是指虽然放在Frameworks框架中,但是却没 有在苹果的官方文档中有使用说明、代码介绍等记录的API。后两种API是有区别的,按苹果的说法,未公开的API是还不够成熟,可能还会变动的API, 等完全成型了后会变成公开的API,但是目前不对其提供承诺,就是系统版本升级后可能会失效。而私有API是苹果明确不能使用的API。虽然两者有所区 别,但是在具体使用方法上是类似的。

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

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

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

10:objective c中既有私有方法,也有私有变量。

先说私有方法,
由于Objective-C的动态消息传递机制,OC中不存在真正意义上的私有方法。
但是如果你不在.h文件中声明,只在.m文件中实现,或在.m文件的Class Extension里声明,那么基本上和私有方法差不多。

至于私有变量是可以通过@private来声明的,例如:



@interface Sample : NSObject{
@private
    NSString *tteesstt;
}
@property (nonatomic,strong) NSString *hoge;
- (void)foo;
@end

则tteesstt变量是私有的。而属性hoge是默认公有。

现在Apple官方文档里是用property比较多,直接定义instance variable(实例变量)少。将property定义到.m的Class Extension(类扩展)也基本上和私有变量差不多。

简而言之,将你希望公有的放到.h文件,私有的放到.m文件。在import时只import .h文件(.m文件也是可以import的,但是我们一般不这么做)。


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实现无限加载多张图片

创建一个UIScrollView,高度为屏幕的高度,宽度为三倍的屏幕宽度,设置为按屏幕滑动,设置偏移量(屏幕宽度,0)。第一个屏幕宽度和第三个屏幕宽度贴一个UIImageView显示图片的前一张和后一张,中间贴一个UIScrollView,大小为屏幕的大小,在上面贴一个UIImageView显示要显示的图片。当向左滑动,通过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、    提前计算并缓存好高度(布局),因为heightForRowAtIndexPath:是调用最频繁的方法;
   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中线程是如何进行通信的?

推荐阅读