1.请简述你对工厂方法的理解?mysql
工厂Mycontrol,设计控件是用到工厂设计模式。类簇相似于工厂设计模式;工厂模式就是定义建立对象的接口,让子类决定实例化哪个类。这样,类的实例化就推迟到了子类程序员
2.UITableView有哪些优化方式?web
UITableView的优化主要从三个方面入手:面试
• 提早计算并缓存好高度(布局),由于heightForRowAtIndexPath:是调用最频繁的方法;sql
• 异步绘制,遇到复杂界面,遇到性能瓶颈时,可能就是突破口;数据库
• 滑动时按需加载,这个在大量图片展现,网络加载的时候很管用!(SDWebImage已经实现异步加载,配合这条性能杠杠的)。设计模式
3.你如何理解block,block有什么用途?数组
• 咱们能够把Block当作Objective-C的匿名函数。Block容许开发者在两个对象之间将任意的语句当作数据进行传递,每每这要比引用定义在别处的函数直观。另外,block的实现具备封闭性(closure),而又可以很容易获取上下文的相关状态信息。缓存
• block是代码块,其本质和变量相似。不一样的是代码块存储的数据是一个函数体。使用Block,就能够像其余标准函数同样,传入参数,并获得返回值。网络
做为OC对象的属性,实现对象之间的传值 • Block能够看作是一个变量,所以能够做为OC对象的属性
4.请问怎样可以保证定位更省电?
1.开启开始定位以后,不关闭,让其持续定位
2.设置距离筛选器:坐标移动到指定距离才会调用代理方法
3.设置精准度:经过下降计算的过程(GPS),来达到省电的目的
5.请简述NSUserDefaults的使用场景和 使用注意事项?
SUserDefaults适合存储轻量级的数据,他不只能够存储基本数据类型,还能够存储NSNumber(Integer、Float、Double),NSString,NSDate,NSArray,NSDictionary,BOOL类型。
可是NSUserDefaults不能存储自定义的类对象,若把一个对象存储到NSUserDefaults会报错。聪明的人会把对象放进数组,再把数组存入NSUserDefaults,不过这样作事错误的,由于数组中包含了自定义对象。
若要在NSUserDefaults中存入自定义对象,则对象须要遵循NSCoding协议,并实现encodeWithCoder方法和initWithCoder方法。具体参考http://my.oschina.NET/u/1245365/blog/294449
值得一提的是,我发现类型为NSNull的空数据也是没法存入NSUserDefaults的。若数据中有NSNull类型空数据,把它置nil便可存入NSUserDefaults。
总之,NSUserDefaults是一种操做简单的数据库。
6.iOS中数据库使用什么技术实现的 ?
使用Sqlite和CoreData实现的
7.iOS中如何实现数据模型的存储?
归档也是iOS提供给开发者的一种数据存储的方式,事实上,几乎全部的数据类型均可以经过归档来进行存取。其存储与读取的过程,主要封装在两个类中:NSKeyedArchiver和NSKeyedUnarchiver
8.为何说Objective-C是一门动态的语言?
Objective-C是动态语言,它并不是经过调用类的方法来执行功能,而是给对象发送消息,
对象在接收到消息以后会去找匹配的方法来运行。
9.讲一下MVC和MVVM,MVP?
1.MVC做为老牌架构, 优势在于将业务场景按展现数据类型划分出多个模块, 每一个模块中的C层负责业务逻辑和业务展现, 而M和V应该是互相隔离的以作重用, 另外每一个模块处理得当也能够做为重用单元. 拆分在于解耦, 顺便作了减负, 隔离在于重用, 提高开发效率. 缺点是没有区分业务逻辑和业务展现, 对单元测试不友好.
2.MVP做为MVC的进阶版, 提出区分业务逻辑和业务展现, 将全部的业务逻辑转移到P层, V层接受P层的数据更新通知进行页面展现. 优势在于良好的分层带来了友好的单元测试, 缺点在于分层会让代码逻辑优势绕, 同时也带来了大量的代码工做, 对程序员不够友好.
3.MVVM做为集大成者, 经过数据绑定作数据更新, 减小了大量的代码工做, 同时优化了代码逻辑, 只是学习成本有点高, 对新手不够友好.
4.MVP和MVVM由于分层因此会创建MVC两倍以上的文件类, 须要良好的代码管理方式.
5.在MVP和MVVM中, V和P或者VM之间理论上是多对多的关系, 不一样的布局在相同的逻辑下只须要替换V层, 而相同的布局不一样的逻辑只须要替换P或者VM层. 但实际开发中P或者VM每每由于耦合了V层的展现逻辑退化成了一对一关系(好比SceneA中须要显示"xxx+Name", VM就将Name格式化为"xxx + Name". 某一天SceneB也用到这个模块, 全部的点击事件和页面展现都同样, 只是Name展现为"yyy + Name", 此时的VM由于耦合SceneA的展现逻辑, 就显得比较尴尬), 针对此类状况, 一般有两种办法, 一种是在VM层加状态进而判断输出状态, 一种是在VM层外再加一层FormatHelper. 前者可能由于状态过多显得代码难看, 后者虽然比较优雅且拓展性高, 可是过多的分层在数据还原时就略显笨拙, 你们应该按需选择.
这里随便瞎扯一句, 有些文章上来就说MVVM是为了解决C层臃肿, MVC难以测试的问题, 其实并非这样的. 按照架构演进顺序来看, C层臃肿大部分是没有拆分好MVC模块, 好好拆分就好了, 用不着MVVM. 而MVC难以测试也能够用MVP来解决, 只是MVP也并不是完美, 在VP之间的数据交互太繁琐, 因此才引出了MVVM. 当MVVM这个彻底体出现之后, 咱们从结果看起源, 发现它作了好多事情, 其实并非, 它的前辈们付出的努力也并很多!
10.为何在默认状况下没法修改被block捕获的变量? __block都作了什么?
若是是用block(用static也能够)修饰的局部变量,在block内部访问的话,而是把这个局部变量的地址传递过去了,因此会跟踪这个局部变量的变化,而且能够修改,
若是block内部引用的变量是全局变量的话,那么在block内部访问,他也是把这个变量的地址传递过去了.。
11.模拟一下循环引用的一个状况?block实现界面反向传值如何实现?
ClassA和ClassB分属两个不一样的线程,ClassB一般由ClassA发起请求建立,并由ClassA使用,ClassB则会在必要时通知ClassA一些事件。二者中各保留了对方的一个引用计数指针RefPtr。
若是在析构时释放成员变量的话,就会发生循环引用的问题,致使两个对象释放失败。
block的回调的使用步骤
1.声明 : 在谁那里调用就在谁那里声明
实现代码
typedef void(^MyBlock)(NSString *name);//block的重命名
@property (nonatomic,copy) MyBlock block;//block的声明
2.实现 : 谁要装值就在谁那里实现
实现代码
SecondViewController *secondVC = [[SecondViewController alloc] init];
[self presentViewController:secondVC animated:YES completion:nil];//在这里没用导航控制器,用presentViewController来进入下一个视图
//block实现
secondVC.block = ^void(NSString *name)
{
_label.text = name;
};//block的位置摆放很做用的,由于它是一个函数,不过必定不能放在使用它的对象的外面和前面就行了
3.调用 : 谁要传值就在谁那里调用
self.block(@"呵呵");//block的调用
总结一句话:block用在不一样视图控制器之间的值回传,回传还有代理、单例,在回传中最简单的就是用block了
*/
12.objc在向一个对象发送消息时,发生了什么?
SomeClass * someObject; someObject = nil; [someObject doSomething];
就像这样,向nil发送了doSomething;OC中nil是被当作0定义的。也就是说runtime要去获取这个nil的信息,会去读取内存中0的位置,这确定是不容许的,会返回nil,0,0.0等数据,根据返回值类型。
比较让你混淆的是,僵尸对象。僵尸对象并非nil,僵尸对象是你的object被销毁或者用于其余地方了,可是指向它的指针还在。会发生向一个object发送一个它没有的方法。
13.何时会报unrecognized selector错误?iOS有哪些机制来避免走到这一步?
对象未实现该方法。
对象已经被释放。
使用[id respondsToSelector:]进行判断。
Method resolution
objc运行时会调用+resolveInstanceMethod:或者 +resolveClassMethod:,让你有机会提供一个函数实现。若是你添加了函数,那运行时系统就会从新启动一次消息发送的过程,不然 ,运行时就会移到下一步,消息转发(Message Forwarding)。
返回Nil和self,去调用第三步methodSignatureForSelector和forwarInvocation;返回receiver,若是receiver有响应就直接处理,若是没有就去对应的对象内去调用第三步;调用子类的函数,子类没有进行这几个方法的重载,在父类处理时返回子类,会死循环。
Fast forwarding
若是目标对象实现了-forwardingTargetForSelector:,Runtime 这时就会调用这个方法,给你把这个消息转发给其余对象的机会。 只要这个方法返回的不是nil和self,整个消息发送的过程就会被重启,固然发送的对象会变成你返回的那个对象。不然,就会继续Normal Fowarding。 这里叫Fast,只是为了区别下一步的转发机制。由于这一步不会建立任何新的对象,但下一步转发会建立一个NSInvocation对象,因此相对更快点。
Normal forwarding
这一步是Runtime最后一次给你挽救的机会。首先它会发送-methodSignatureForSelector:消息得到函数的参数和返回值类型。若是-methodSignatureForSelector:返回nil,Runtime则会发出-doesNotRecognizeSelector:消息,程序这时也就挂掉了。若是返回了一个函数签名,Runtime就会建立一个NSInvocation对象并发送-forwardInvocation:消息给目标对象。
14.可否向编译后获得的类中增长实例变量?可否向运行时建立的类中添加实例变量?为何?
解释:
2.运行时建立的类是能够添加实例变量,调用class_addIvar函数.可是的在调用objc_allocateClassPair以后,objc_registerClassPair以前,缘由同上.
15.runtime如何实现weak变量的自动置nil?
runtime 对注册的类, 会进行布局,对于 weak 对象会放入一个 hash 表中。 用 weak 指向的对象内存地址做为 key,当此对象的引用计数为0的时候会 dealloc,假如 weak 指向的对象内存地址是a,那么就会以a为键, 在这个 weak 表中搜索,找到全部以a为键的 weak 对象,从而设置为 nil。
16.给类添加一个属性后,在类结构体里哪些元素会发生变化?
定义结构体会
17.runloop是来作什么的?runloop和线程有什么关系?主线程默认开启了runloop么?子线程呢?
用来控制一些特殊操做只能在指定模式下运行,通常能够经过指定操做的运行mode 来控制执行时机,以提升用户体验
系统默认注册了 5 个 Mode
kCFRunLoopDefaultMode:App 的默认 Mode,一般主线程是在这个 Mode
下运行,对应 OC 中的:NSDefaultRunLoopMode
UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑
动,保证界面滑动时不受其余 Mode 影响
kCFRunLoopCommonModes:这是一个标记 Mode,不是一种真正的 Mode,事件
能够运行在全部标有 common modes 标记的模式中,对应 OC 中的
NSRunLoopCommonModes , 带 有 common modes 标 记 的 模 式 有 :UITrackingRunLoopMode 和 kCFRunLoopDefaultMode
UIInitializationRunLoopMode:在启动 App 时进入的第一个 Mode,启动完成后
就再也不使用
GSEventReceiveRunLoopMode:接受系统事件的内部 Mode,一般用不到
RunLoop只能运行在一种mode下,若是要换mode,当前的loop也须要停下重启成新的。利用这个机制,ScrollView滚动过程当中NSDefaultRunLoopMode(kCFRunLoopDefaultMode)的mode会切换到UITrackingRunLoopMode来保证ScrollView的流畅滑动:只能在NSDefaultRunLoopMode模式下处理的事件会影响scrllView的滑动。
若是咱们把一个NSTimer对象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主运行循环中的时候, ScrollView滚动过程当中会由于mode的切换,而致使NSTimer将再也不被调度。
同时由于mode仍是可定制的,因此:
Timer计时会被scrollView的滑动影响的问题能够经过将timer添加到NSRunLoopCommonModes(kCFRunLoopCommonModes)来解决。
20.苹果是如何实现Autorelease Pool的?每个线程的 autoreleasepool 其实就是一个指针的堆栈;
每个指针表明一个须要 release 的对象或者 POOL_SENTINEL(哨兵对象,表明一个 autoreleasepool 的边界);
一个 pool token 就是这个 pool 所对应的 POOL_SENTINEL 的内存地址。当这个 pool 被 pop 的时候,全部内存地址在 pool token 以后的对象都会被 release ;
这个堆栈被划分红了一个以 page 为结点的双向链表。pages 会在必要的时候动态地增长或删除;
Thread-local storage(线程局部存储)指向 hot page ,即最新添加的 autoreleased 对象所在的那个 page 。
21.isa指针?(对象的isa,类对象的isa,元类的isa都要说)
1、类的基本概念:
一、类其实也是一个对象, 这个对象会在这个类第一次被使用的时候建立
二、只要有了类对象, 未来就能够经过类对象来建立实例对象
三、实例对象中有一个isa指针, 指向建立本身的类对象
四、类对象中保存了当前对象全部的对象方法
五、当给一个实例对象发送消息的时候, 会根据实例对象中的isa指针去对应的类对象中查找
六、全部类对象的继承关系就是元类对象的继承关系
2、isa指针
1.每个对象都包含一个isa指针.这个指针指向当前对象所属的类。
2.[d bark];表示给d所指向的对象发送一条bark消息,调用对象的bark方法,此时对象会顺着内部的isa指针找到存储于类中的方法并执行。
3.isa是对象中的隐藏指针,指向建立这个对象的类。
4.经过isa指针咱们能够在运行的时候知道当前对象是属于那个类。
3、元类
一、元类的定义:元类是类对象的类,每一个类都有本身独一无二的元类,即
(1)当你给对象发送消息时,消息是在寻找这个对象的类的方法列表。
(2)当你给类发消息时,消息是在寻找这个类的元类的方法列表。
元类是必不可少的,由于它存储了类的类方法。每一个类都必须有独一无二的元类,由于每一个类都有独一无二的类方法。
二、元类的类:
(1)元类,就像类同样,它也是一个对象,也能够调用它的方法。这就意味着他必须也有一个类。
(2)全部的元类都使用根元类(继承体系中处于顶端的类的元类)做为他们的类。即全部NSObject的子类的元类都会以NSObject的元类做为他们的类。
(3)全部的元类使用根元类做为他们的类,根元类的元类则就是它本身。也就是说基类的元类的isa指针指向他本身。
22.介绍一下分类,能用分类作什么?内部是如何实现的?它为何会覆盖掉原来的方法?
由于分类方法加入类中这一操做是在运行期系统加载分类时完成的,运行期系统会把分类中所实现的每个方法都加入类的方法列表中,具体步骤以下:
category的实例方法、协议以及属性添加到类上
category的类方法和协议添加到类的metaclass上
category的方法被放到了新方法列表的前面,而原来类的方法被放到了新方法列表的后面,因此category的方法会“覆盖”掉原来类的同名方法。
23.运行时能增长成员变量么?能增长属性么?若是能,如何增长?若是不能,为何?
不少人在面试的时候都会被问到Category,既然容许用Category给类增长方法和属性,那为何不容许增长成员变量?
在Objective-C提供的runtime函数中,确实有一个class_addIvar()函数用于给类添加成员变量,可是阅读过苹果的官方文档的人应该会看到:
This function may only be called after objc_allocateClassPair and before objc_registerClassPair. Adding an instance variable to an existing class is not supported.
大概的意思说,这个函数只能在“构建一个类的过程当中”调用。一旦完成类定义,就不能再添加成员变量了。通过编译的类在程序启动后就被runtime加载,没有机会调用addIvar。程序在运行时动态构建的类须要在调用objc_registerClassPair以后才能够被使用,一样没有机会再添加成员变量。
在 Objective-C 中向 nil 发送消息是彻底有效的——只是在运行时不会有任何做用:
Person * motherInlaw = [[aPerson spouse] mother];
若是 spouse 对象为 nil,那么发送给 nil 的消息 mother 也将返回 nil。