美文网首页
ios理论知识普及

ios理论知识普及

作者: SunBoyXiao | 来源:发表于2017-06-21 17:40 被阅读20次

    1.为什么说Objective-C是一门动态的语言?
    objective-c是通过给对象发送消息,对象在接收到消息之后会去找匹配的方法来运行。对象是运行时类的一个实例。在类里声明了的实例变量和方法,它的每个实例都在内存中拥有同样的实例变量,以及指向那些方法的指针。在oc中对象永远是通过指针来引用的。objective-c具有动态特性:动态类型(比如id类型),动态绑定(代码在运行时才决定调用什么方法,而不是在编译时),动态加载(在需要是才加载,而不是在启动时就加载所有)。

    2.讲一下MVC和MVVM,MVP?
    MVC:模型、视图、控制器
    模型对象封装了应用程序的数据,并定义操控和处理该数据的逻辑和运算。视图对象是展示模型对象中的数据,并且可以对模型数据进行操作,在iOS应用程序开发中,所有的控件、窗口等都继承自 UIView,对应MVC中的V。UIView及其子类主要负责UI的实现,而UIView所产生的事件都可以采用委托的方式,交给UIViewController实现。控制器对象是视图对象和模型对象的中介,视图对象和模型对象是没有交集的,如下图:


    model_view_controller-670x192.png

    MVC缺点:控制器Controller会本笨重,太过于轻量级的Model,网络请求只能放在Controller中,可测试性差

    MVP:
    逻辑Model层、视图层、protocol协议层
    MVP模式的原则是,在service层提供一大堆不尽相同的业务场景之后,我们将这一系列数据全部抽象归纳,通过定制一套标准的protocol协议,让不同业务场景的都去实现这一协议,最终将数据全部装配、拼装成一套具有相同调度规则的统一编制话数据Model,之后我们采用id<protocol>的标准去操作数据。

    MVP除了将数据逻辑完全镇封的各自的Model,同时将那些Model需要绘制,哪些Model需要校验, 哪些Model需要接受处理点击Action这些逻辑全部由Model自己来决定,Controller只作为一个粘合性的模版,Controller只处理一批具有共性的范型类数据,至于具体的操作毫不关心。

    MVP面相的更多的是在MVC上层与service之间追加了一层协议层,我们认为通过协议层处理过的数据是暂时可以客户端场景使用的数据,在数据到达MVC我们针对数据进行再加工、再构造处理,这一切全部在容器内操作。这一点完全与别的设计模式相反。

    MVP并不是让用户在Model打上网络请求操作、在Model层执行[self.navigationController pushViewController:*]等这些操作,其实相对大多人来说对于部分对象生命周期长短问题还是很在乎,所以在处理TemplateActionProtocol协议的时间,MVP只是对准Action做了一层抽象封装。通过实现TemplateActionProtocol的Model会产生一个Action对象,最终通过block的调用链传回控制器中,我们在控制器中统一做handler处理。

    MVP我们最初设计目的就是为了强调一个装配概念,如果发生了业务场景的追加,控制器我不会改动其中的代码,只需要将新数据追加成相同批次的ViewModel,然后配置进容器,之后控制器不做任何修改就可以满足需求了。通过具体的剥离、抽取我们成功了的最大限度的剥离了控制器,满足了轻量级Controller这一概念。

    MVP与传统软件相比,在设计这一点的时间我们完全借鉴了传统软件的思维模式,Java平台的service设计模式、三层架构这些设计规范都相对做了一些对比分析,最终得出了MVP这一理念。

    MVVM(model-view-viewModel的简写):
    在MVVM里,view和view controller正式联系在一起,我们把它们视为一个组件。视图view仍然不能直接引用模型Model,当然controller也不能。相反,他们都可以引用视图模型view Model。

    view Model是一个放置用户输入验证逻辑,视图显示逻辑,发起网络请求和其他各种各样的代码的极好的地方。有一件事情不应归入view Model,那就是任何视图本身的引用。view Model的概念同时适用于于iOS和OS X。(换句话说,不要在view Model中使用 #import UIKit.h)

    由于展示逻辑(presentation logic)放在了view Model中(比如Model的值映射到一个格式化的字符串),视图控制器本身就会不再臃肿。

    3.为什么代理要用weak?代理的delegate和dataSource有什么区别?block和代理的区别?
    代理使用weak是避免循环引用而导致内存泄漏。
    weak:指明该对象并不负责保持delegate这个对象,delegate这个对象的销毁由外部控制
    strong:该对象强引用delegate,外界不能销毁delegate对象,会导致循环引用(Retain Cycles)

    代理的delegate和dataSource的区别:
    Delegate是委托的意思,在oc中则是一个类委托另一个类实现某个方法。当一个对象接受到某个事件或者通知的时候, 会向它的Delegate对象查询它是否能够响应这个事件或者通知,如果可以这个对象就会给它的Delegate对象发送一个消息(执行一个方法调用)。
    Datasource字面是数据源,一般和Delegate伴生,这时数据源处理的数据就是Delegate中发送委托的类中的数据,并通过Datasource发送给接受委托的类。

    block和代理的区别:
    delegate运行成本低。block成本很高的。
    block出栈需要将使用的数据从栈内存拷贝到堆内存,当然对象的话就是加计数,使用完或者block置nil后才消除;delegate只是保存了一个对象指针,直接回调,没有额外消耗。相对C的函数指针,只多做了一个查表动作
    delegate:
    “一对一”,对同一个协议,一个对象只能设置一个代理delegate,单例对象就不能用代理这是不对的,任何人,任何对象,只要接受,只要允许,只要遵守了相关的协议,TA就可以使用代理。
    代理更注重过程信息的传输:比如发起一个网络请求,可能想要知道此时请求是否已经开始、是否收到了数据、数据是否已经接受完成、数据接收失败。
    block:
    写法更简练,不需要写protocol、函数等等
    block注重结果的传输:比如对于一个事件,只想知道成功或者失败,并不需要知道进行了多少或者额外的一些信息
    block需要注意防止循环引用:

    公共接口,方法较多选择用delegate进行解耦,比如最常用tableViewDelegate,textViewDelegate。
    异步和简单的回调用block更好,比如常用的网络库AFNetwork,ASIHTTP库,UIAlertView类。

    4.属性的实质是什么?包括哪几个部分?属性默认的关键字都有哪些?@dynamic关键字和@synthesize关键字是用来做什么的?

    编译器遇到关键字@property,自动声明setter/getter方法。

    编译器遇到@synthesize,自动实现setter/getter方法。
    @synthesize myTitle = _myTitle;为属性myTitle生成了一个实例变量_myTitle,所以我们对属性的操作self.myTitle实质上都是在操作_myTitle变量。

    @dynamic仅仅是告诉编译器getter和setter方法这两个方法在运行期会有的,无需产生警告。

    属性、实例变量和成员变量的关系是:
    声明属性的时候编译器自动生成的实例变量,实例变量的本质就是成员变量,self.myTitle操作属性的时候实质上是在操作成员变量_myTitle(也就是实例变量)。

    属性的默认关键字:
    assign:修饰 ‘基本数据类型’、‘枚举’、‘结构体’ 等非OC对象类型;

    weak:修饰UI控件

    strong:修饰OC对象类型(NSArray、NSDate、NSNumber、模型类),一个对象只要有强指针引用着,就不会被销毁;

    copy:一般用在NSString*类型、block类型上,cope的作用是产生副本,copy返回的是不可变的副本,mutableCopy返回的是可变的副本,修改了副本并不会影响源对象,修改了源对象,并不会影响副本。
    注意:并不是所有情况下我们的string都必须使用copy,因为如果我们的需求是希望string是随着我的改变而改变的,那么这个时候应该使用strong。
    深拷贝和浅拷贝
    深拷贝:对象拷贝 - 直接拷贝内容。
    单层深拷贝:这种方式只能够提供一层内存拷贝(one-level-deep copy),并非真正的深拷贝。
    浅拷贝:指针拷贝 - 将指针中的地址值拷贝一份。
    对于非集合对象
    copy:因为copy默认返回的是不可变的,所以当我们对一个不可变的字符串进行copy的时候,我们只是拷贝了它的指针(浅拷贝)。当我们对一个可变的字符串进行拷贝的时候,因为类型转变了,我们需对其进行深拷贝。
    mutableCopy:默认返回的是一个可变的对象,适用于可变的对象,例如NSMutableString,NSMutableArray,NSMutableDictionary、etc。 无论对于可变的字符串还是不可变的字符串进行mutableCopy,系统都默认进行深拷贝,那么为什么对于相同类型的进行mutableCopy返回的仍然是新的对象呢,因为在这里系统要保证,旧的对象和新的对象都是可变的,切他们之前不会相互影响。
    对于集合对象
    对于不可变的集合对象,copy 是浅拷贝,mutableCopy 是单层深拷贝。
    对于可变的集合对象,无论 copy 或者 mutableCopy 都是单层深拷贝。

    retain:
    对其他NSObject和其子类对参数进行release旧值,再retain新值;
    指定retain会在赋值时唤醒传入值的retain消息。此属性只能用于Objective-C对象类型,而不能用于Core Foundation对象。(原因很明显,retain会增加对象的引用计数,而基本数据类型或者Core Foundation对象都没有引用计数——译者注)。
    注意: 把对象添加到数组中时,引用计数将增加对象的引用次数+1。

    atomic:
    指出访问器是原子操作,提供多线程安全。在多线程环境下,原子操作是必要的,否则有可能引起错误的结果。

    nonatomic:
    指出访问器不是原子操作,禁止多线程,变量保护,提高性能。

    readwrite:
    属性可读可写

    readonly:
    属性只读

    5.NSString为什么要用copy关键字,如果用strong会有什么问题?(注意:这里没有说用strong就一定不行。使用copy和strong是看情况而定的)
    copy是为了安全,防止NSMutableString赋值给NSString时,前者修改引起后者值变化而用的.

    strong仅仅进行强引用确保持有string的对象在生存期间这个string不会被释放,但使用strong后,加入把a变量赋值给b,那么变量a和b指向的是同一片内存,所以修改其中一个值后两个值就都变了。

    6.如何令自己所写的对象具有拷贝功能?
    想令自己所写的对象具有拷贝功能,则需实现 NSCopying 协议。如果自定义的对象分为可变版本与不可变版本,那么就要同时实现 NSCopying与 NSMutableCopying协议。

    7.为什么IBOutlet修饰的UIView也适用weak关键字?
    因为当我们将控件拖到Storyboard上,相当于新创建了一个对象,而这个对象是加到视图控制器的view上,view有一个subViews属性,这个属性是一个数组,里面是这个view的所有子view,而我们加的控件就位于这个数组中,那么说明,实际上我们的控件对象是属于view的,也就是说view对加到它上面的控件是强引用。当我们使用Outlet属性的时候,我们是在viewController里面使用,而这个Outlet属性是view来进行强引用的,我们在viewController里面仅仅是对其使用,并没有必要拥有它,所以是weak的。

    8.nonatomic和atomic的区别?atomic是绝对的线程安全么?为什么?如果不是,那应该如何实现?
    atomic 和 nonatomic 的区别在于,系统自动生成的 getter/setter 方法不一样。
    atomic不是绝对的线程安全。
    因为如果线程 A 调了 getter,与此同时线程 B 、线程 C 都调了 setter——那最后线程 A get 到的值,3种都有可能:可能是 B、C set 之前原始的值,也可能是 B set 的值,也可能是 C set 的值。同时,最终这个属性的值,可能是 B set 的值,也有可能是 C set 的值。
    保证线程安全,可以加锁,有@synchronized、NSLock、dispatch_semaphore、NSCondition、pthread_mutex、OSSpinLock等。

    9.用StoryBoard开发界面有什么弊端?如何避免?
    难以维护
    Storyboard在某些角度上,是难以维护的。我所遇到过的实际情况是,公司一个项目的2.0版本,设计师希望替换原有字体。然而原来项目的每一个Label都是采用Storyboard来定义字体的,因此替换新字体需要在Storyboard中更改每一个Label。
    幸亏我们知道Storyboard的源文件是XML,最终写了一个读取-解析-替换脚本来搞定这件事。

    性能瓶颈
    当项目达到一定的规模,即使是高性能的MacBook Pro,在打开Storyboard是也会有3-5秒的读取时间。无论是只有几个Scene的小东西,还是几十个Scene的庞然大物,都无法避免。Scene越多的文件,打开速度越慢(从另一个方面说明了分割大故事板的重要性)。
    让人沮丧的是,这个造成卡顿的项目规模并不是太难达到。
    我猜想是由于每一次打开都需要进行I/O操作造成的,Apple对这一块的缓存优化没有做到位。可能是由于Storyboard占用了太多内存,难以在内存中进行缓存。Whatever,这个问题总是让人困扰的。
    然而需要指出的是,采用Storyboard开发或采用纯代码开发的App,在真机的运行效率上,并没有太大的区别。

    错误定位困难

    10.进程和线程的区别?同步异步的区别?并行和并发的区别?
    线程是指进程内的一个执行单元,也是进程内的可调度实体。
    与进程的区别:
    (1)地址空间:进程内的一个执行单元,进程至少一个线程,他们共享进程的地址空间,而进程有自己独立的地址空间
    (2)资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程资源
    (3)线程是处理器调度的基本单位,但进程不是
    (4)二者皆可并发执行

    进程和线程都是操作系统的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性,进程和线程的区别在于:
    一个程序至少有一个进程,一个进程至少有一个线程。
    线程的划分尺度小于进程,使得多线程程序的并发性高
    进程在执行的过程中有独立的内存单元,而多个线程共享内存,从而极大地提升了程序的运行效率

    执行过程区别:每个独立的进程都有一个程序运行的入口,顺序执行序列和程序的入口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制

    由逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行,但操作系统并没有将多个线程看做多个独立的应用来实现进程的调度和管理,这就是线程和进程的重要区别。

    进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。

    线程是进程的一个实体,是CPU调度和分派的基本单位,他是比进程更小的能独立运行的基本单位,线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(寄存器,栈,程序计数器),但是它可与同一个进程的其他线程共享进程所拥有的全部资源

    一个线程可以创建和撤消另一个线程,同一个进程中的多线程之间可以并发执行。

    14.线程间通信?
    
    15.GCD的一些常用的函数?(group,barrier,信号量,线程同步)
    
    16.如何使用队列来避免资源抢夺?
    
    17.数据持久化的几个方案(fmdb用没用过)
    
    18.说一下AppDelegate的几个方法?从后台到前台调用了哪些方法?第一次启动调用了哪些方法?从前台到后台调用了哪些方法?
    
    19.NSCache优于NSDictionary的几点?
    
    20.知不知道Designated Initializer?使用它的时候有什么需要注意的问题?
    
    21.实现description方法能取到什么效果?
    
    22.objc使用什么机制管理对象内存?
    

    中级

    Block

    1.block的实质是什么?一共有几种block?都是什么情况下生成的?
    
    2.为什么在默认情况下无法修改被block捕获的变量? __block都做了什么?
    
    3.模拟一下循环引用的一个情况?block实现界面反向传值如何实现?
    

    Runtime

    1.objc在向一个对象发送消息时,发生了什么?
    
    2.什么时候会报unrecognized selector错误?iOS有哪些机制来避免走到这一步?
    
    3.能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?
    
    4.runtime如何实现weak变量的自动置nil?
    
    5.给类添加一个属性后,在类结构体里哪些元素会发生变化?
    

    RunLoop

    1.runloop是来做什么的?runloop和线程有什么关系?主线程默认开启了runloop么?子线程呢?
    
    2.runloop的mode是用来做什么的?有几种mode?
    
    3.为什么把NSTimer对象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主运行循环以后,滑动scrollview的时候NSTimer却不动了?
    
    4.苹果是如何实现Autorelease Pool的?
    

    类结构

    1.isa指针?(对象的isa,类对象的isa,元类的isa都要说)
    
    2.类方法和实例方法有什么区别?
    
    3.介绍一下分类,能用分类做什么?内部是如何实现的?它为什么会覆盖掉原来的方法?
    
    4.运行时能增加成员变量么?能增加属性么?如果能,如何增加?如果不能,为什么?
    
    5.objc中向一个nil对象发送消息将会发生什么?(返回值是对象,是标量,结构体)
    

    高级

    1.UITableview的优化方法(缓存高度,异步绘制,减少层级,hide,避免离屏渲染)
    
    2.有没有用过运行时,用它都能做什么?(交换方法,创建类,给新创建的类增加方法,改变isa指针)
    
    3.看过哪些第三方框架的源码?都是如何实现的?(如果没有,问一下多图下载的设计)
    
    4.SDWebImage的缓存策略?
    
    5.AFN为什么添加一条常驻线程?
    
    6.KVO的使用?实现原理?(为什么要创建子类来实现)
    
    7.KVC的使用?实现原理?(KVC拿到key以后,是如何赋值的?知不知道集合操作符,能不能访问私有属性,能不能直接访问_ivar)
    

    (未完,待续)

    相关文章

      网友评论

          本文标题:ios理论知识普及

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