iOS常见面试题汇总

iOS常会师试题汇总

1. 哪些是 ARC? (ARC 是为了然决哪些难题而诞生的?)

ARC 是 Automatic Reference Counting 的缩写, 即自动引用计数. 那是苹果在
iOS5 中引入的内存管理机制. Objective-C 和 Swift 使用 ARC
追踪和管制选用的内存使用. 这一编制使得开发者无需键入retain
release , 那不仅可以下落程序崩溃和内存走漏的风险,
而且可以减去开发者的工作量,
可以大幅度进步程序的流畅性可预测性. 不过 ARC 不适用于 Core
Foundation 框架中, 依旧要求手动管理内存.

2. 以下 keywords 有啥样差别: assign vs weak , __block vs __weak

  • assignweak 是用于在宣称属性时, 为属性指定内存管理的语义.
    assign 用于简单的赋值, 不转移属性的引用计数, 用于 Objective-C 中的
    NSInteger , CGFloat以及 C 语言中 int , float , double
    等数码类型.

  • assign看起来跟weak无异于,其实无法混用的,assign的变量在出狱后并不设置为nil(和weak差异),
    当你再去引用时候就会发出错误,崩溃,EXC_BAD_ACCESS.

Has an assign attribute, AND Has been deallocated. Thus when you attempt to call the respondsToSelector method on delegate, you get a EXC_BAD_ACCESS. This is because objects that use the assign property will not be set to nil when they are deallocated. (Hence why doing a !self.delegate before the respondsToSelector does not prevent the responseToSelector from being called on a deallocated object, and still crashes your code) The solution is to use the weak attribute, because when the object deallocates, the pointer WILL be set the nil . So when your code calls respondsToSelector on a nil, Objective C will ignore the call, and not crash.
  • weak 用于对象类型, 由于 weak
    同样不改动目的的引用计数且不有所对象实例,
    当该对象扬弃时,该弱引用自动失效并且被赋值为 nil ,
    所以它可以用于防止多个强引用暴发的 循环引用导致内存无法自由的难题.

__block__weak 之间的区分确实极大的, 不过它们都用来修饰变量.

  • 前者用于指明当前注脚的变量在被 block 捕获之后, 可以在 block
    中改变变量的值. 因为在 block 评释的同时会收获该 block
    所使用的整整自行变量的值, 而那几个值只在 block 中
    只具有”使用权”而不有所”修改权” . 而 __block 表明符就为 block
    提供了变量的修改权.

  • 后来人是 所有权修饰符 , 什么是所有权修饰符? 那里提到到另一个题材,
    因为在 ARC 有效时, id 类型和对象类型同 C 语言中的其余系列不一致,
    必须叠加所有权修饰符. 所有权修饰符一种有 4 种:
    1、**__strong
    2、
    __weak
    3、
    __unsafe_unretained
    4、
    __autorelease**

  • block无法改改部分变量,倘使急需修改必要加上__block.

  • block会对目的强引用,引起retain-cycle,要求利用weak

__weak __typeof(&*self)weakSelf =self;

注意:在block种使用weakSelf可防止那种强引用。(七个指针,指向同一块地点(self));

  • __weakweak 的区分只在乎, 前者用于变量的宣示,
    而后者用于属性的表明.

3. __block 在 ARC 和非 ARC 下含义一样吗?

__block 在 ARC 下捕获的变量会被 block retain , 这样或许造成循环引用,
所以必需求选拔弱引用才能化解该难题. 而在非 ARC 下, 可以一贯利用
__block 表明符修饰变量, 因为在非 ARC 下, block 不会 retain 捕获的变量.

4. 使用 nonatomic 一定是线程安全的吗

nonatomic 的内存管理语义是 非原子 的, 非原子的操作本来就是线程不安全的,
而 atomic 的操作是原子的, 可是 并不代表它是线程安全的 ,
它会大增正确的几率, 可以更好的避免线程的荒唐, 可是它依然是线程不安全的.

当使用 nonatomic 的时候, 属性的 setter 和 getter 操作是非原子的,
所以当多个线程同时对某一性质举办读和写的操作,
属性的最终结果是无法预测的.

当使用 atomic 时, 就算对品质的读和写是原子的, 然而照旧可能出现线程错误:
当线程 A 举行写操作, 那时其他线程的读或写操作会因为该操作的开展而等待.
当 A 线程的写操作停止后, B 线程举行写操作, 然后当 A 线程举办读操作时,
却取得了在 B 线程中的值, 那就破坏了线程安全, 如若有线程 C 在 A
线程读操作前 release 了该属性, 那么还会造成程序崩溃. 所以仅仅使用 atomic
并不会使得线程安全, 大家还亟需为线程添加 lock 来确保线程的安全.

atomic 都不是毫无疑问线程安全的, nonatomic 就更不要多说了.

5. + (void)load;+ (void)initialize; 有怎样用处?

当类对象被引入项目时, runtime 会向每一个类对象发送 load 信息. load
方法或者非常的神奇的, 因为它会在 每一个类依然分类 被引入时仅调用一遍,
调用的各种是父类优先于子类, 子类优先于分类. 而且 load
方法不会被类活动再而三, 每一个类中的 load 方法都不要求像 viewDidLoad
方法一致调用父类的方法.

initialize 方法和 load 方法有部分分裂, 它固然也会在全体 runtime
进度中调用四回, 然则它是在 该类的首先个方法执行以前 调用, 也就是说
initialize 的调用是 惰性 的,
它的落成也与大家在经常使用的惰性伊始化属性时中央相同. 在该措施中根本做
静态变量的安装 并用于保证在实例起先化前某些原则必须餍足.

+(void)load
方法只要参预了工程种,举行了编译,且.m中达成了那几个办法,都会调用一回,值得注意的时没兑现的子类是不会调用的,即便父类已毕了也极度。categories,都落到实处了这几个措施,只会调用其中一个,具有不强烈。
+(void)initialize
在殡葬第一条音信给类的时候举行调用,跟load方法的分歧之处在于,相比迟,可完毕懒加载,且父类.m完毕了该方式,子类不落到实处也会调用父类,跟正规的不二法门一致。

6.为啥其余语言里叫函数调用, Objective-C 中是给目的发送信息 (谈下对 runtime 的了然)

俺们在其余语言中诸如: C, Python, Java, C++, Haskell …
中涉及函数调用或者措施调用(面向对象).
函数调用是在编译期就已经决定了会调用哪个函数(方法),
编译器在编译期就能检查出函数的实践是还是不是正确.

但是 Objective-C(ObjC) 是一门动态的言语, 整个 ObjC
语言都是尽量的将装有的工作推迟到运行时才决定. 它根据 runtime 来干活,
runtime 就是 ObjC 的神魄, 其主导就是音信发送 objc_msgSend .

What makes Objective-C truly powerful is its runtime.

装有的信息都会在运转时才会确定, [obj message] 在运转时会被转正为
objc_msgSend(id self, SEL cmd, ...) 来执行, 它会在运转时从
接纳子表中查找对应的精选子 并将拔取子与落到实处进行绑定.
而倘若没有找到相应的兑现, 就会进去类似黑魔法的新闻转载流程. 调用
+ (BOOL)resolveInstanceMethod:(SEL)aSelector 方法,
我们可以在那一个办法中 为类动态地生成方法 .

咱俩差不离可以使用 runtime 魔改 Objective-C 中的一切:
class property object ivar method protocol , 而上边就是它的重大选拔:

  • 内省
  • 为分类动态的添加属性
  • 应用办法调剂修改原有的艺术完毕

7.什么是 Method Swizzling?

method swizzling 实际上就是一种在运作时动态修改原有艺术的技巧,
它其实是依据 ObjC runtime 的表征, 而 method swizzling 的主导措施就是
method_exchangeImplementations(SEL origin, SEL swizzle) .
使用这么些办法就足以在运作时动态地改变原有的措施完成.

8. UIView 和 CALayer 有何样关联?

每一个 UIView 的身后对应一个 Core Animation 框架中的 CALayer .

sqlite,Many of the methods you call on UIView simply delegate to the layer

在 iOS 上 当你处理一个一个有一个的 UIView 时实际上是在操作 CALayer .
即便部分时候你并不知道 (间接操作 CALayer 并不会在对效能具有强烈的升迁).

UIView 实际上就是对 CALayer 的轻量级的封装. UIView 继承自 UIResponder
处理来自用户的风云; CALayer 继承自 NSObject 首要用来图层的渲染和动画.
这么设计有以下多少个原因:

  • 您可以透过操作 UIView 在一个更高的层级上处理与用户的竞相, 触摸,
    点击, 拖拽等事件, 这么些都是在 UIKit 那一个层级上完成的.
  • UIView 和 NSView(AppKit) 的贯彻极其不相同, 而使用 Core Animation
    可以兑现底层代码地拔取, 因为在 Mac 和 iOS 平台上都利用着近乎一致的
    Core Animation 代码, 那样我们得以对这一个层级举办抽象在三种平台上发出
    UIKit 和 AppKit 用于不一样平台的框架.

采取 CALayer 的唯一原因大致是福利移植到不一样的阳台, 借使仅仅使用 Core
Animation 层级, 处理用户的互动时间须求写更加多的代码.

9. 怎么高品质的给 UIImageView 加个圆角? (不准说 layer.cornerRadius !)

诚如境况下给 UIImageView 或者说 UIKit 的控件添加圆角都是改变
clipsToBoundslayer.cornerRadius , 这样大体两行代码就可以解决.
可是, 那样使用那样的法子会 强制 Core Animation 提前渲染屏幕的离屏绘制 ,
而离屏绘制就会为品质带来负面影响.

咱俩也得以运用另一种比较复杂的章程来为图片添加圆角,
那里就用到了贝塞尔曲线.

UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];  
imageView.center = CGPointMake(200, 300);  
UIImage *anotherImage = [UIImage imageNamed:@"image"];  
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0);  
[[UIBezierPath bezierPathWithRoundedRect:imageView.bounds
  cornerRadius:50] addClip];
[anotherImage drawInRect:imageView.bounds];
imageView.image = UIGraphicsGetImageFromCurrentImageContext();  
UIGraphicsEndImageContext();  
[self.view addSubview:imageView];

在此地运用了贝塞尔曲线”切割”个这一个图形, 给 UIImageView 添加了的圆角.

10. 利用 drawRect: 有哪些影响?

本条方式的第一成效是按照传入的 rect 来绘制图像.
那一个方法的默许完成没有做其余工作, 我们 可以 在这么些方法中使用 Core
Graphics 和 UIKit 来绘制视图的内容.

那些措施的调用机制也是老大尤其. 当你调用 setNeedsDisplay 方法时, UIKit将会把近年来图层标记为 dirty, 但依旧会浮现原来的情节,
直到下一遍的视图渲染周期, 才会重复创立 Core Graphics 上下文,
然后将内存中的数据恢复生机出来, 使用 CGContextRef 举办绘制.

用来画图,那个方法会在intiWithRect时候调用。
以此办法的熏陶在于有touch
event的时候之后,会另行绘制,很多那样的按钮的话就会比较影响成效。以下都会被调用
1、若是在UIView开始化时从没安装rect大小,将直接导致drawRect不被活动调用。drawRect
掉用是在Controller->loadView, Controller->viewDidLoad
两方法之后掉用的.所以不用操心在
控制器中,这一个View的drawRect就开始画了.那样可以在控制器中装置有些值给View(倘若这个View
draw的时候必要选用某些变量 值).
2、该格局在调用sizeToFit后被调用,所以可以先调用sizeToFit算算出size。然后系统活动调用drawRect:方法。
3、通过安装contentMode属性值为UIViewContentModeRedraw。那么将在每一次设置或转移frame的时候自动调用drawRect:。
4、直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:,可是有个前提条件是rect不能为0。

11. ASIHttpRequest 如故 SDWebImage 里面给 UIImageView 加载图片的逻辑是怎么样的?

SDWebImage 中为 UIView 提供了一个分拣叫做 WebCache,
那些分类中有一个最常用的接口, sd_setImageWithURL:placeholderImage: ,
那些分类同时提供了不少接近的措施, 这么些主意最后会调用一个还要具备
option progressBlock completionBlock 的情势,
而在这么些类最终被调用的方法首先会检讨是否传入了 placeholderImage
以及相应的参数, 并设置 placeholderImage .

接下来会赢得 SDWebImageManager 中的单例调用一个 downloadImageWithURL:...
的艺术来获得图片, 而那些 manager 获取图片的历程有大体上分为两片段,
它首先会在 SDWebImageCache 中搜索图片是否有对应的缓存, 它会以 url
作为数据的索引先在内存中追寻是或不是有照应的缓存,
如若缓存未命中就会在磁盘中运用 MD5 处理过的 key 来持续查询相应的数目,
假若找到了, 就会把磁盘中的缓存备份到内存中.

唯独, 即使大家在内存和磁盘缓存中都尚未命中, 那么 manager
就会调用它有着的一个 SDWebImageDownloader 对象的不二法门
downloadImageWithURL:... 来下载图片,
这么些方法会在执行的进度中调用另一个艺术
addProgressCallback:andCompletedBlock:fotURL:createCallback:
来存储下载进程中和下载完毕的回调, 当回调块是率先次添加的时候,
方法会实例化一个 NSMutableURLRequest
SDWebImageDownloaderOperation , 并将后者到场 downloader
持有的下载队列开端图片的异步下载.

而在图片下载达成将来, 就会在主线程设置 image,
已毕全体图像的异步下载和配置.

12. loadView 的成效是怎么?

loadView 是 UIViewController 的实例方法, 大家永远不要间接调用这一个措施
[self loadView] . 那在苹果的 官方文档 中早就尽人皆知的写出了. loadView
会在赢得视图控制器的 view 可是却得到 nil 时被调用.

loadView的有血有肉落到实处会做上边两件工作中的一件:

1、借使您的视图控制器关联了一个 storyboard, 那么它就会加载
storyboard 中的视图.

2、尽管打算控制器没有涉嫌的 storyboard, 那么就会成立一个空的视图,
并分配给 view 属性

假定您要求覆写 loadView 方法:

1、你要求成立一个根视图.
2、创立并初步化 view 的子视图, 调用 addSubview:
方法将它们增加到父视图上.
3、倘若您使用了活动布局, 提供丰裕的封锁来保管视图的位置.
4、将根视图分配给 view 属性.
5、永远不要在那几个方法中调用 [super loadView] .

13. view威尔LayoutSubviews 的效用是怎么着?

viewWillLayoutSubviews 方法会在视图的 bounds 改变时,
视图会调整子视图的地点,
大家可以在视图控制器中覆写那么些点子在视图放置子视图前做出改变,
当显示屏的大势改变时, 这些措施会被调用.

layoutSubviews在以下情形下会被调用:
1、init开首化不会触发layoutSubviews
2、addSubview会触发layoutSubviews
3、设置view的Frame会触发layoutSubviews,当然前提是frame的值设置内外发生了转变
4、滚动一个UIScrollView会触发layoutSubviews
5、旋转Screen会触发父UIView上的layoutSubviews事件
6、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件

14. GCD 里面有哪二种 Queue? 背后的线程模型是怎么着的?

GCD 中 Queue 的类型还要看大家怎么开展分拣,
倘若根据同一时间内处理的操作数分类的话, GCD 中的 Queue 分为两类

1、Serial Dispatch Queue
2、Concurrent Dispatch Queue
一类是串行派发队列, 它只利用一个线程,
会等待眼前执行的操作停止后才会实施下一个操作, 它根据追加的依次举行处理.
另一类是并行派发队列, 它同时利用五个线程, 如若当前的线程数丰富,
那么就不会等待正在执行的操作, 使用七个线程同时施行七个处理.

其余的一种分类方法如下:

1、Main Dispatch Queue
2、Global Dispatch Queue
3、Custom Dispatch Queue
主线程唯有一个, 它是一个串行的进度. 所有追加到 Main Dispatch Queue
中的处理都会在 RunLoop 在执行. Global Dispatch Queue
是所有应用程序都能动用的并行派发队列, 它有 4 个实施优先级
High, Default, Low, Background. 当然我们也可以利用
dispatch_queue_create 成立派发队列.

15. Core Data 或者 sqlite 的读写是分线程的吧? 死锁怎样化解?

数据库读取操作一般都是二十四线程的, 在对数据开展读取的时候,
我们要保障当前的图景不会被修改, 所以加锁, 避免由于线程竞争而产出的错误.
Core Data 中使用并行的最重大的条条框框是: 每一个
NSManagedObjectContext 必须只从成立它的进度中做客 .

16. http 的 POST 和 GET 有哪些界别?

基于 HTTP 协议的概念 GET 类型的伸手是幂等的, 而 POST 请求是有副效率的,
也就是说 GET 用于获取一些资源, 而 POST 用于转移部分资源,
那或者会创制新的资源或更新已部分资源.

POST 请求比 GET 请求越发的平安, 因为您不会把音信添加到 URL
上的查询字符串上. 所以使用 GET
来收集密码依旧部分机敏新闻并不是怎么好主意.

最终, POST 请求比 GET 请求也得以传输越多的音信.

17. 哪些是 Binary search tree, 它的时间复杂度是多少?

二叉搜索树是一棵以二叉树来组织的, 它搜索的时间复杂度 $O(h)$ 与树的高度成正比, 最坏的运行时间是 $\Theta(\lg n)$.
网站地图xml地图