面试中被面试官问到的问题答案(一)

如下问题的答案是以前写的一篇文章 面试中被面试官问到的问题 如今把问题的答案整理了一份出来给你们。但愿对你们有所帮助。若是整理的答案有问题,请联系我。shavekevin@gmail.comhtml

1.请你谈谈static和宏定义的区别。何时用static何时用宏定义。 让你声明的常量只在你声明的文件里有做用要不编译器会保存ios

宏定义:c++

1). 通常来讲咱们使用宏定义最多见的是定义一些常量 简单的”函数”(好比求两个数的最大小值) 例如:定义常量PI程序员

#define PI 3.1415926
复制代码

定义函数web

#define MIN(A,B) ((A) < (B) ? (A):(B))
复制代码

咱们不对宏定义进行修改面试

  1. . 使用宏定义能够在很大程度上能够简化咱们的代码 例如:咱们在写单例的时候 以前咱们写的是
#import "ShareSingleton.h"

@implementation ShareSingleton

+(instancetype)shareSingleton {

    static ShareSingleton *leader = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        leader = [[ShareSingleton alloc]init];
    });
    return leader;
}
@end
复制代码

//若是咱们使用宏定义的话咱们能够这样写:算法

#define DISPATCH_ONCE_BLOCK(onceBlock) static dispatch_once_t onceToken; dispatch_once(&onceToken, onceBlock);
#import "ShareSingleton.h"
@implementation ShareSingleton

+(instancetype)shareSingleton {

    static ShareSingleton *leader = nil;
    DISPATCH_ONCE_BLOCK(^{
        leader = [[ShareSingleton alloc]init];
    })
    return leader;
}
@end
复制代码

其实#define的原理就是无论三七二十一,直接作替换,因此咱们彻底能够利用这个特色,发挥本身的想象,简化代码~ 宏定义实质是一个预编译指令,在程序未运行以前将某些指令付给相应的变量。sql

小结一下: static标记的变量会存储到全局变量区,生命周期和程序相同。而宏定义所定义的生命周期与所在的载体的生命周期有关.数据库

static只在声明的类中可见。 在声明的类中结束后,再次使用仍是以前的值。编程

2.你是怎么看待代理 通知的 他们有什么区别? 首先,咱们把代理通知 放到一块儿来讨论第一反映是传值。 ok,下面慢慢来讲各个的用法和区别。

通知中心

经过NSNotification能够给多个对象传递数据和消息(多个传递) 代理 经过protocol(代理模式)只能给一个对象传递数据和消息(单一传递)“一对一”,对同一个协议,一个对象只能设置一个代理delegate,因此单例对象就不能用代理(能够用多点回调,下面看法)。

代理更注重过程信息的传输:好比发起一个网络请求,可能想要知道此时请求是否已经开始、是否收到了数据、数据是否已经接受完成、数据接收失败。

区别: 代理和通知的区别应该主要是一对一和一对多的关系。delegate的多点回调相对notification更加便捷,更多方便,让项目更好维护。

3.说说你对内存管理的理解。

内存管理原则

引用计数的增长和减小相等,当引用计数降为0以后,不该该再使用这块内存空间。 凡是用alloc retain 或者copy让内存的引用计数增长了。就须要使用release或者autorelease让内存的引用 计数减小。在一段代码内。增长和减小的次数要相等。

autoreleasepool的使用

经过autoreleasepool控制autorelease对象的释放 向一个对象发送autorelease消息。这个对象什么时候释放取决于autoreleasepool

copy方法 跟retain不一样,一个对象想要copy,生成本身的副本,须要实现NSCopying协议,定义copy的细节(如何copy)若是类没有接受NSCoping协议而给类发送copy消息,会引发crash 总结: OC借助引用计数机制去管理内存,凡是使用了alloc copy retain 等 方法,增长了引用计数,就要使用release 和autorelease 减小引用计数,引用计数为0的时候,对象所占的内存,被系统回收。

autorelease是将来某个时间(出autorelease)引用减一,不是即时的。

不是任何对象均可以接受copy消息。只有接受了NSCoping协议的对象才接受copy消息。

4.谈谈你对iOS性能优化的理解.

谈起iOS的性能优化咱们首先想到的是应该是tableview表视图的优化。关于表视图的优化咱们能够从如下几个方面来看:

1).tableviewcell渲染 绘制时要尽量的避免分配资源,好比UIFont,NSDateFormatter或者任何在绘制时 须要的对象,推荐使用类层级的初始化方法中执行分配,并将其存储为静态变量。

2).图层渲染的问题 透明图层对渲染性能会有必定的影响,系统必须将透明图层与下面的视图混合起来计算颜色,并 绘制出来。减小透明图层并使用不透明的图层来替代它们,能够极大地提升渲染速度。

3).为代理方法瘦身 咱们要尽可能避免在tableview的cellforrowatindexpath的代理方法里写那么多代码,这样作不只能够简化代码方便维护和管理,这对程序的运行也有帮助。

4).复杂视图尽可能采用纯代码的方式

当 UITableViewCell拥有多个子视图时,IOS的渲染机制会拖慢速度。重写drawRect直接绘制内容的方式可 以提升性能,而不是在类初始化的时候初始化一些label或者imageview等。

(如下来源于yykit做者ibireme这是源连接

下面就是些CPU 资源消耗缘由和解决方案 还有GPU资源消耗缘由和解决方案

对象的建立会分配内存、调整属性、甚至还有读取文件等操做,比较消耗 CPU 资源。尽可能用轻量的对象代替重量的对象,能够对性能有所优化。好比 CALayer 比 UIView 要轻量许多,那么不须要响应触摸事件的控件,用 CALayer 显示会更加合适。若是对象不涉及 UI 操做,则尽可能放到后台线程去建立,但惋惜的是包含有 CALayer 的控件,都只能在主线程建立和操做。经过 Storyboard 建立视图对象时,其资源消耗会比直接经过代码建立对象要大很是多,在性能敏感的界面里,Storyboard 并非一个好的技术选择。

1).对象的建立 尽可能推迟对象建立的时间,并把对象的建立分散到多个任务中去。尽管这实现起来比较麻烦,而且带来的优点并很少,但若是有能力作,仍是要尽可能尝试一下。若是对象能够复用,而且复用的代价比释放、建立新对象要小,那么这类对象应当尽可能放到一个缓存池里复用。

2).对象调整 对象的调整也常常是消耗 CPU 资源的地方。这里特别说一下 CALayer:CALayer 内部并无属性,当调用属性方法时,它内部是经过运行时 resolveInstanceMethod 为对象临时添加一个方法,并把对应属性值保存到内部的一个 Dictionary 里,同时还会通知 delegate、建立动画等等,很是消耗资源。UIView 的关于显示相关的属性(好比 frame/bounds/transform)等实际上都是 CALayer 属性映射来的,因此对 UIView 的这些属性进行调整时,消耗的资源要远大于通常的属性。对此你在应用中,应该尽可能减小没必要要的属性修改。 当视图层次调整时,UIView、CALayer 之间会出现不少方法调用与通知,因此在优化性能时,应该尽可能避免调整视图层次、添加和移除视图。 3). 对象销毁 对象的销毁虽然消耗资源很少,但累积起来也是不容忽视的。一般当容器类持有大量对象时,其销毁时的资源消耗就很是明显。一样的,若是对象能够放到后台线程去释放,那就挪到后台线程去。这里有个小 Tip:把对象捕获到 block 中,而后扔到后台队列去随便发送个消息以免编译器警告,就可让对象在后台线程销毁了。 例如:

NSArray *tmp = self.array;
self.array = nil;
dispatch_async(queue, ^{
    [tmp class];
});
复制代码

4).一些计算

视图布局的计算是 App 中最为常见的消耗 CPU 资源的地方。若是能在后台线程提早计算好视图布局、而且对视图布局进行缓存,那么这个地方基本就不会产生性能问题了。 不论经过何种技术对视图进行布局,其最终都会落到对 UIView.frame/bounds/center 等属性的调整上。上面也说过,对这些属性的调整很是消耗资源,因此尽可能提早计算好布局,在须要时一次性调整好对应属性,而不要屡次、频繁的计算和调整这些属性。 Autolayout 是苹果自己提倡的技术,在大部分状况下也能很好的提高开发效率,可是 Autolayout 对于复杂视图来讲经常会产生严重的性能问题。随着视图数量的增加,Autolayout 带来的 CPU 消耗会呈指数级上升。具体数据能够看这个文章:http://pilky.me/36/。 若是你不想手动调整 frame 等属性,你能够用一些工具方法替代(好比常见的 left/right/top/bottom/width/height 快捷属性),或者使用 ComponentKit、AsyncDisplayKit 等框架.

若是一个界面中包含大量文本(好比微博微信朋友圈等),文本的宽高计算会占用很大一部分资源,而且不可避免。若是你对文本显示没有特殊要求,能够参考下 UILabel 内部的实现方式:用 [NSAttributedString boundingRectWithSize:options:context:] 来计算文本宽高,用 -[NSAttributedString drawWithRect:options:context:] 来绘制文本。尽管这两个方法性能不错,但仍旧须要放到后台线程进行以免阻塞主线程。

5).文本的绘制

若是你用 CoreText 绘制文本,那就能够先生成 CoreText 排版对象,而后本身计算了,而且 CoreText 对象还能保留以供稍后绘制使用。 屏幕上能看到的全部文本内容控件,包括 UIWebView,在底层都是经过 CoreText 排版、绘制为 Bitmap 显示的。常见的文本控件 (UILabel、UITextView 等),其排版和绘制都是在主线程进行的,当显示大量文本时,CPU 的压力会很是大。对此解决方案只有一个,那就是自定义文本控件,用 TextKit 或最底层的 CoreText 对文本异步绘制。尽管这实现起来很是麻烦,但其带来的优点也很是大,CoreText 对象建立好后,能直接获取文本的宽高等信息,避免了屡次计算(调整 UILabel 大小时算一遍、UILabel 绘制时内部再算一遍);CoreText 对象占用内存较少,能够缓存下来以备稍后屡次渲染.

6).图片的解码

当你用 UIImage 或 CGImageSource 的那几个方法建立图片时,图片数据并不会马上解码。图片设置到 UIImageView 或者 CALayer.contents 中去,而且 CALayer 被提交到 GPU 前,CGImage 中的数据才会获得解码。这一步是发生在主线程的,而且不可避免。若是想要绕开这个机制,常见的作法是在后台线程先把图片绘制到 CGBitmapContext 中,而后从 Bitmap 直接建立图片。目前常见的网络图片库都自带这个功能。

7).图像的绘制

图像的绘制一般是指用那些以 CG 开头的方法把图像绘制到画布中,而后从画布建立图片并显示这样一个过程。这个最多见的地方就是 [UIView drawRect:] 里面了。因为 CoreGraphic 方法一般都是线程安全的,因此图像的绘制能够很容易的放到后台线程进行。一个简单异步绘制的过程大体以下(实际状况会比这个复杂得多,但原理基本一致)

dispatch_async(backgroundQueue, ^{
        CGContextRef ctx = CGBitmapContextCreate(...);
        // draw in context...
        CGImageRef img = CGBitmapContextCreateImage(ctx);
        CFRelease(ctx);
        dispatch_async(mainQueue, ^{
            layer.contents = img;
        });
    });
    
复制代码

GPU 资源消耗缘由和解决方案

1.纹理的渲染

全部的 Bitmap,包括图片、文本、栅格化的内容,最终都要由内存提交到显存,绑定为 GPU Texture。不管是提交到显存的过程,仍是 GPU 调整和渲染 Texture 的过程,都要消耗很多 GPU 资源。当在较短期显示大量图片时(好比 TableView 存在很是多的图片而且快速滑动时),CPU 占用率很低,GPU 占用很是高,界面仍然会掉帧。避免这种状况的方法只能是尽可能减小在短期内大量图片的显示,尽量将多张图片合成为一张进行显示。 当图片过大,超过 GPU 的最大纹理尺寸时,图片须要先由 CPU 进行预处理,这对 CPU 和 GPU 都会带来额外的资源消耗。目前来讲,iPhone 4S 以上机型,纹理尺寸上限都是 4096x4096,更详细的资料能够看这里:iosres.com。因此,尽可能不要让图片和视图的大小超过这个值。

2.视图的混合 当多个视图(或者说 CALayer)重叠在一块儿显示时,GPU 会首先把他们混合到一块儿。若是视图结构过于复杂,混合的过程也会消耗不少 GPU 资源。为了减轻这种状况的 GPU 消耗,应用应当尽可能减小视图数量和层次,并在不透明的视图里标明 opaque 属性以免无用的 Alpha 通道合成。固然,这也能够用上面的方法,把多个视图预先渲染为一张图片来显示

3.图像的生成

CALayer 的 border、圆角、阴影、遮罩(mask),CASharpLayer 的矢量图形显示,一般会触发离屏渲染(offscreen rendering),而离屏渲染一般发生在 GPU 中。当一个列表视图中出现大量圆角的 CALayer,而且快速滑动时,能够观察到 GPU 资源已经占满,而 CPU 资源消耗不多。这时界面仍然能正常滑动,但平均帧数会降到很低。为了不这种状况,能够尝试开启 CALayer.shouldRasterize 属性,但这会把本来离屏渲染的操做转嫁到 CPU 上去。对于只须要圆角的某些场合,也能够用一张已经绘制好的圆角图片覆盖到本来视图上面来模拟相同的视觉效果。最完全的解决办法,就是把须要显示的图形在后台线程绘制为图片,避免使用圆角、阴影、遮罩等属性。

如何检测应用的流畅度?
复制代码

“过早的优化是万恶之源”,在需求未定,性能问题不明显时,不必尝试作优化,而要尽可能正确的实现功能。作性能优化时,也最好是走修改代码 -> Profile -> 修改代码这样一个流程,优先解决最值得优化的地方。 若是你须要一个明确的 FPS 指示器,能够尝试一下 KMCGeigerCounter。对于 CPU 的卡顿,它能够经过内置的 CADisplayLink 检测出来;对于 GPU 带来的卡顿,它用了一个 1x1 的 SKView 来进行监视。这个项目有两个小问题:SKView 虽然能监视到 GPU 的卡顿,但引入 SKView 自己就会对 CPU/GPU 带来额外的一点的资源消耗;这个项目在 iOS 9 下有一些兼容问题,须要稍做调整。

5.你用过单元测试吗?怎么才能作好单元测试?

什么是单元测试?

单元测试:如下内容来自维基百科单元测试

在计算机编程中,单元测试(英语:Unit Testing)又称为模块测试, 是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工做。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。

一般来讲,程序员每修改一次程序就会进行最少一次单元测试,在编写程序的过程当中先后极可能要进行屡次单元测试,以证明程序达到软件规格书要求的工做目标,没有程序错误;虽然单元测试不是什么必须的,但也不坏,这牵涉到项目管理的政策决定。

每一个理想的测试案例独立于其它案例;为测试时隔离模块,常用stubs、mock[1]或fake等测试马甲程序。单元测试一般由软件开发人员编写,用于确保他们所写的代码符合软件需求和遵循开发目标。它的实施方式能够是很是手动的(经过纸笔),或者是作成构建自动化的一部分。
复制代码

单元测试有什么好处?

单元测试的一个好处就是咱们能够只测试单个模块,咱们能够测试 单一模块有没有问题。好比说咱们在开发中常常会写一些测试性的demo。咱们写的测试性demo运行正常达到了咱们须要的效果,那么咱们就能够把demo的效果运用到咱们的工程中进行调试。

  • 适应变动

单元测试容许程序员在将来重构代码,而且确保模块依然工做正确(复合测试)。这个过程就是为全部函数和方法编写单元测试,一旦变动致使错误发生,借助于单元测试能够快速定位并修复错误。

可读性强的单元测试可使程序员方便地检查代码片段是否依然正常工做。良好设计的单元测试案例覆盖程序单元分支和循环条件的全部路径。

在连续的单元测试环境,经过其固有的持续维护工做,单元测试能够延续用于准确反映当任何变动发生时可执行程序和代码的表现。借助于上述开发实践和单元测试的覆盖,能够分分秒秒维持准确性。

  • 简化集成

单元测试消除程序单元的不可靠,采用自底向上的测试路径。经过先测试程序部件再测试部件组装,使集成测试变得更加简单。

业界对于人工集成测试的必要性存在较大争议。尽管精心设计的单元测试体系看上去实现了集成测试,由于集成测试须要人为评估一些人为因素才能证明的方面,单元测试替代集成测试不可信。一些人认为在足够的自动化测试系统的条件下,人力集成测试组再也不是必需的。事实上,真实的需求最终取决于开发产品的特色和使用目标。另外,人工或手动测试很大程度上依赖于组织的可用资源。[来源请求]

  • 文档记录

单元测试提供了系统的一种文档记录。借助于查看单元测试提供的功能和单元测试中如何使用程序单元,开发人员能够直观的理解程序单元的基础API。

单元测试具体表现了程序单元成功的关键特色。这些特色能够指出正确使用和非正确使用程序单元,也能指出须要捕获的程序单元的负面表现(译注:异常和错误)。尽管不少软件开发环境不只依赖于代码作为产品文档,在单元测试中和单元测试自己确实文档化了程序单元的上述关键特色。

另外一方面,传统文档易受程序自己实现的影响,而且时效性难以保证(如设计变动、功能扩展等在不太严格时常常不能保持文档同步更新)。

  • 表达设计

    在测试驱动开发的软件实践中,单元测试能够取代正式的设计。每个单元测试案例都可以视为一项类、方法和待观察行为等设计元素。下面的Java例能够帮助说明这一点。 固然,单元测试缺少图的可读性,但UML图能够在自由工具(一般可从IDE扩展获取)中为大多数现代程序语言生成UML图,很难要求采购昂贵的UML设计套装软件。自由工具,相似于基于xUnit框架的工具,测试结果输出到一些可生成供人工识读的图形化工具系统中去。

  • 分离接口和实现

由于不少类会引用其它类,对这个类的测试常常会要求测试其它的类。一个最广泛的例子是依赖于数据库的类:为了测试它,测试人员一般编写代码去操做数据库。这是不对的,由于单元测试不该超出待测试的类边界。

做为替代,软件开发人员应建立一个数据库链接的抽象接口,而后实现这个接口的模拟对象。经过对代码所需附件的抽象(临时下降了网状的耦合效应),这些独立程序单元较前者更能被完整测试。高质量的代码单元也可提供更好的可维护性。
复制代码
  • 局限

测试不可能发现全部的程序错误,单元测试也不例外。按定义,单元测试只测试程序单元自身的功能。所以,它不能发现集成错误、性能问题、或者其余系统级别的问题。单元测试结合其余软件测试活动更为有效。与其它形式的软件测试相似,单元测试只能代表测到的问题,不能代表不存在未测试到的错误。

软件测试是一个组合问题。例如,每个布尔型的决断语句须要至少两种测试:一个返回真,一个返回假。所以,针对每行书写的代码,程序员一般须要写3至5行的测试代码。[3]这很明显地很花时间并且对此的投入可能并不值得。也有些问题是根本不能简单地检测出来的——例如具不肯定性的或牵扯到多线程的问题。此外,替单元测试写的代码可能就像要测试的代码同样有程序错误。佛瑞德·布鲁克斯在人月神话一书中举例说明:“绝对不要带两个计时器去海边。最好老是带一或三个”。意味着,若是两个计时器互相冲突的话,你该怎么知道哪一个是对的?为了得到单元测试的好处,在软件开发过程当中应造成一套严格纪律意识。仔细保留记录是必要的,不只仅只保留执行的测试,也包括保留对应的源码和其它软件单元的变动历史。即,使用版本控制系统是必要的。若是后续版本不能经过一个之前测试经过的单元测试,版本控制系统能够提供对应时间段对源代码所作的变动清单。

天天养成查看单元测试案例失败测试并及时肯定错误缘由的习惯是必要的。若是没有这样的流程,没有在团队工做流程中体现,单元测试系列将走向不一样步,形成愈来愈多的错误和愈来愈低效的单元测试案例系列。
复制代码

iOS中的单元测试

   在开发中,常常用到的单元测试一是测试某个模块的功能,也就是说把这个模块独立起来,单独进行测试。用到最多的应该是测试模块功能和接口调试功能。固然单元测试还有一些高级的用法自动测试和自动发布等。

   OCUnit(即用XCTest进行测试)其实就是苹果自带的测试框架,咱们主要讲的就是这个。GHUnit是一个可视化的测试框架。(有了它,你能够点击APP来决定测试哪一个方法,而且能够点击查看测试结果等。)OCMock就是模拟某个方法或者属性的返回值,你可能会疑惑为何要这样作?使用用模型生成的模型对象,再传进去不就能够了?答案是能够的,可是有特殊的状况。好比你测试的是方法A,方法A里面调用到了方法B,并且方法B是有参数传入,但又不是方法A所提供。这时候,你可使用OCMock来模拟方法B返回的值。(在不影响测试的状况下,就能够这样去模拟。)除了这些,在没有网络的状况下,也能够经过OCMock模拟返回的数据。UITests就是经过代码化来实现自动点击界面,输入文字等功能。靠人工操做的方式来覆盖全部测试用例是很是困难的,尤为是加入新功能之后,旧的功能也要从新测试一遍,这致使了测试须要花很是多的时间来进行回归测试,这里产生了大量重复的工做,而这些重复的工做有些是能够自动完成的,这时候UITests就能够帮助解决这个问题了。

6. 你知道的的本地数据持久化都有哪些。你比较喜欢用哪些 为何?

采用的数据存储的方式有如下几种:

一、 FMDB(经常使用) 二、 Sqlite(次之) 三、 Coredata(次之) 四、 NSUserdefaults(最多使用) 五、 序列化反序列化(归档和解档) 六、 MongoDB(小众型的)

  你们讨论用的最多的是FMDB,缘由很简单,关系型数据库,使用方便(相对于没通过封装和加工的Sqlite来讲)。其次就是sqlite和coredata 固然使用者三种主要是为了缓存。由于咱们在开发中为了给用户更好的体验,就采用缓存的形式。通常状况下要作的操做就是在本地创建一个数据库(本地后台)。

7.谈谈MVC设计模式的优缺点

编程以来就一直被灌输MVC设计模式,具体MVC使用到底好在哪里 又有那些不足之处,能够经过下面的介绍得以了解。

1、mvc原理

mvc是一种程序开发设计模式,它实现了显示模块与功能模块的分离。提升了程序的可维护性、可移植性、可扩展性与可重用性,下降了程序的开发难度。它主要分模型、视图、控制器三层。

  1. 模型(model)它是应用程序的主体部分,主要包括业务逻辑模块(web项目中的Action,dao类)和数据模块(pojo类)。模型与数据格式无关,这样一个模型能为多个视图提供数据。因为应用于模型的代码只需写一次就能够被多个视图重用,因此减小了代码的重复性

  2. 视图(view) 用户与之交互的界面、在web中视图通常由jsp,html组成

  3. 控制器(controller)接收来自界面的请求 并交给模型进行处理 在这个过程当中控制器不作任何处理只是起到了一个链接的作用.

2、MVC的优势

  1. 能够为一个模型在运行时同时创建和使用多个视图。变化-传播机制能够确保全部相关的视图及时获得模型数据变化,从而使全部关联的视图和控制器作到行为同步。

  2. 视图与控制器的可接插性,容许更换视图和控制器对象,并且能够根据需求动态的打开或关闭、甚至在运行期间进行对象替换。

  3. 模型的可移植性。由于模型是独立于视图的,因此能够把一个模型独立地移植到新的平台工做。须要作的只是在新平台上对视图和控制器进行新的修改。

  4. 潜在的框架结构。能够基于此模型创建应用程序框架,不只仅是用在设计界面的设计中。

3、MVC的不足之处

  1. 增长了系统结构和实现的复杂性。对于简单的界面,严格遵循MVC,使模型、视图与控制器分离,会增长结构的复杂性,并可能产生过多的更新操做,下降运行效率。

  2. 视图与控制器间的过于紧密的链接。视图与控制器是相互分离,但确实联系紧密的部件,视图没有控制器的存在,其应用是颇有限的,反之亦然,这样就妨碍了他们的独立重用。

  3. 视图对模型数据的低效率访问。依据模型操做接口的不一样,视图可能须要屡次调用才能得到足够的显示数据。对未变化数据的没必要要的频繁访问,也将损害操做性能。

  4. 目前,通常高级的界面工具或构造器不支持模式。改造这些工具以适应MVC须要和创建分离的部件的代价是很高的,从而形成MVC使用的困难。

8.谈谈你对多线程的理解,你常常用的多线程有哪些实现方式,谈谈他们优缺点。

使用NSOperationQueue用来管理子类化的NSOperation对象,控制其线程并发数目。GCD和NSOperation均可以实现对线程的管理,区别是 NSOperation和NSOperationQueue是多线程的面向对象抽象。项目中使用NSOperation的优势是NSOperation是对线程的高度抽象,在项目中使用它,会使项目的程序结构更好,子类化NSOperation的设计思路,是具备面向对象的优势(复用、封装),使得实现是多线程支持,而接口简单,建议在复杂项目中使用。

项目中使用GCD的优势是GCD自己很是简单、易用,对于不复杂的多线程操做,会节省代码量,而Block参数的使用,会是代码更为易读,建议在简单项目中使用。

何时用多线程?

大多状况下,要用到多线程的主要是须要处理大量的IO操做时或处理的状况须要花大量的时间等等,好比:读写文 件、视频图像的采集、处理、显示、保存等。

多线程的做用?

能够解决负载均衡问题,充分利用cpu资源 。为了提升CPU的使用率,采用多线程的方式去同时完 成几件事情而互不干扰.

iOS实现多线程有哪几种方式?

主要有三种主要方法。

一、NSThread。

二、NSOperation。

三、GCD。

多线程安全问题的几种解决方案?

使用锁。锁是线程编程同步工具的基础。锁可让你很容易保护代码中一大块区域以便你能够确保代码的正 确性。使用POSIX互斥锁;使用NSLock类;使用@synchronized指令等。

分线程回调主线程方法是什么?有什么做用呢?

回到主线程的方法:

(1). performSelectorOnMainThrea

[self performSelectorOnMainThread:<#(SEL)#>withObject:<#(id)#>waitUntilDone:<#(BOOL)#>];
复制代码

(2). GCD

dispatch_async(dispatch_get_main_queue(), ^{ 
});
复制代码

(3). NSOperationQueue

[[NSOperationQueue mainQueue]addOperationWithBlock:^{
}]
复制代码

做用:主线程是显示UI界面,子线程多数是进行数据处理.

PS:最高境界是异步单线程,江湖上称协程。 能够参考 boost 中的 asio 用户级的任务调度

9.谈谈你对面向对象和面向过程的认识。

简单对比

面向过程就像是一个细心的管家,事无具细的都要考虑到。而面向对象就像是个家用电器,你只须要知道他的功能,不须要知道它的工做原理。“面向过程”是一种是事件为中心的编程思想。就是分析出解决问题所需的步骤,而后用函数把这写步骤实现,并按顺序调用。面向对象是以“对象”为中心的编程思想。

简单的举个例子:汽车发动、汽车到站

这对于“面向过程”来讲,是两个事件,汽车启动是一个事件,汽车到站是另外一个事件,面向过程编程的过程当中咱们关心的是事件,而不是汽车自己。针对上述两个事件,造成两个函数,以后依次调用。然而这对于面向对象来讲,咱们关心的是汽车这类对象,两个事件只是这类对象所具备的行为。并且对于这两个行为的顺序没有强制要求。

两种思想的对比

面向过程其实最为实际的一种思考方式,由于咱们老是一向一步一步的解决问题。(举个简单的事情,在初学面向对象的语言例如c++时,咱们也老是不经意的面向过程了!)。其实就算是面向对象思想也是包含有面向过程思想的,面向过程需造成事件、也就是函数,面向对象需抽象出类,而且也会定义出这类对象的“行为”及方法。可是不管是面向过程的函数,仍是面向对象的方法,二者所完成目的都是一致的。能够说面向过程是一种基础的方法,它考虑的是实际的实现,通常状况下,面向过程是自顶向下逐步求精,其最重要的是模块化的思想方法。面向对象的方法主要是把事物给对象化,包括其属性和行为。这里在程序较小的时候,面向过程就会体现出一种优点,其程序流程十分清楚。如同上述汽车发动、到站这一过程,面向过程能够很清晰的将这一过程体现出来。而面向对像仅仅是抽象出一个Bus类,包括发动、到站之两个行为,具体的执行顺序不能体现出来。

面向过程和面向对象的本质理解

面向过程就是分析出解决问题所需的步骤,面向对象则是把构成问题的事物分解成对象,抽象出对象的目的并不在于完成某个步骤,而是描述其再整个解决问题的步骤中的行为。面向过程的思惟方式是分析综合,面向对象的思惟方式是构造。 例如c语言解决问题时,通常是先定义数据结构,而后在构造算法。而是面向对象求解时则是先抽象出对象,构造一个“封闭”的环境,这个环境中有定义的数据和解决问题的算法。面向过程的设计更具挑战性,技巧性,面向对象主要在于对象抽象的技术性,一旦完成抽象,任何人均可以作后面的工做了。从代码层结构上来讲的话,面向对象和面向过程的主要区别就是数据是单独存数仍是与操做存储在一块儿。面向对象提供了数据的封装后,是的对某一操做而言,数据的访问变得可靠了。

面向过程就是将coding当作一件事,一步一步完成,面向对象就是将coding当作一件事物,须要作什么的时候由事物(对象)自己的行为去完成。

总的来讲:

  • 面向对象是将事物高度抽象化。
  • 面向过程是一种自顶向下的编程。
  • 面向对象必须先创建抽象模型,以后直接使用模型就好了。

面向过程就是说把作事情的步骤一步一步要干啥清楚明了的告诉咱们。就是说咱们知道具体是经过什么方式来实现的。

面向对象说白了就是咱们只须要知道咱们所使用的对象有什么功能,而后咱们让对象去作事情。咱们关心的不是实现的过程,而是可否实现和实现的结果。是事物抽象化的一种体现。

附:

  1. 答案部分摘自yykit做者ibireme: iOS 保持界面流畅的技巧

  2. 单元测试参考文章:iOS单元测试(做用及入门提高)

  3. 多线程能够参考文章:iOS开发全面解析多线程

  4. 面向对象面向过程本质参考文章:面向过程与面向对象的本质区别思考

(未完待续)

我的博客 http://shavekevin.com/#blog

QQ交流群:214541576 欢迎你们进群交流。

相关文章
相关标签/搜索