面试题(十四)

blob.png

唐巧前辈说这些都是 iOS 的基础问题,应该对此深入的了解。当初看到时,大部分回答不上来,因为平时没有好好思考整理过。这里大部分的概念大多会在学习 OC 的过程中遇到过,但还是得经过写代码才能有更深的理解。反正我当初看那些设计模式是云里雾里,每个字都认识,就是不知道说的什么。即使现在,有些东西,我也不是很理解。

Objective-C 底层

Objective-C runtime library:Objective-C 的对象模型,Block 的底层实现结构,消息发送,消息转发,category,method 实现,class load。

runtime 我在平时很少涉及到,没有系统学习过,而且很多次看了不久就忘了,所以这里给出一些不错的文章的链接供参考。这几个问题在《iOS 7 Programming Pushing the Limits》都有过深入的解读(我有电子版,是盗版,这里给出这本书在 Github 的地址,工作后我会把去年看过的盗版书全部补偿买回,没有 iOS 8 的版本,不知道是不是由于盗版太多导致的)。另外,唐巧前辈撰文讨论过前两者:

1. 《Objective-C 对象模型及应用》

唐巧在后记中也提到了 iOS 64-bit 带来的变化:

blob.png

那么就来看看 Session 404 Advanced in Objective-C ,从36分起讲相关的东西,喔,看不懂,那还是看看这个吧,在《iOS 7 Programming Pushing the Limits》的 Further Reading: objc_explain_Non-pointer_isa 部分谈论了这个问题。

2. 《谈 Objective-C Block 的实现》

内容非常翔实,特别是关于 Block 类型的部分,强烈建议做下文章开头提到的测试:Objective-C Blocks Quiz。

3. 消息发送和消息转发

消息发送比较好理解,先了解下 runtime 吧,可以查看官方文档《Objective-C Runtime Guide》。之前学习其他语言的时候还没有关注过调用函数的背后发生了什么,在 Objective-C 中,在对象上调用方法称为发送消息,比如[receiver message];这行代码,编译的时候编译器将之转换为对 底层 C 函数objc_msgSend 的调用:objc_msgSend(receiver, selector);在运行时,调用哪个方法则完全由 runtime 决定,甚至在运行时可以替换调用的方法,这是 Objective-C 被称为动态语言的根本原因。对于消息转发,说实话我现在还不知道这个的应用场景,看到的大部分博客都是说消息转发给了你补救措施来应对没有没有实现的方法防止 Crash 或者实现类似多继承的机制,我有个疑惑,干嘛不实现那个方法,而要在代价很大的转发机制里处理呢。在《Effective Objective-C 2.0》一书第 12 条 tip 中用 @dynamic 演示了实现动态方法解析的例子来说明消息转发的意义,老实说,我还是没有理解这个的意义。这里有个对官方文档的中文翻译和一些注解。

4. Implement of category and method

找到了来自这位比我厉害得多的90后:《刨根问底Objective-C Runtime(3)- 消息 和 Category》(文章原来的链接放进来跟简书的处理有冲突,这里给的是博客地址,而不是这篇文章的具体地址,不过很好找)。

5. Class load

可以看这篇博客:《Objective-C Class Loading and Initialization》,看了下作者的 Github,原来是我以前 follow 过的国外程序员,看人家的 repo 和星星,质量有保障,再看博客文章列表,有很多深入底层的内容,一座宝矿啊。另外在《Effective Objective-C 2.0》书中第51节《精简 initialize 与 load 的实现》中也讨论了这个问题,当初看完一头雾水,如今终于能看懂啦。

Core Data: 大量数据多线程同步

这个问题我已经单独成篇放到这里了,添加了更多的基础知识和介绍。

第一步:搭建 Core Data 多线程环境

这个问题首先要解决的是搭建 Core Data 多线程环境。NSManagedObjectContext 不是线程安全的,你不能随便地开启一个后台线程访问 managed object context 进行数据操作就管这叫支持多线程了。Core Data 对多线程的支持比较好,NSManagedObjectContext 在初始化时可以指定并发模式,有三种选项:

1.NSConfinementConcurrencyType

这种模式是用于向后兼容的,使用这种模式时你应该保证不能在其他线程使用 context,但这点很难保证,不推荐使用。此模式在 iOS 9中已经被废弃。

2.NSPrivateQueueConcurrencyType

在一个私有队列中创建并管理 context。

3.NSMainQueueConcurrencyType

其实这种模式与第 2 种模式比较相似,只不过 context 与主队列绑定,也因此与应用的 event loop 很亲密。当 context 与 UI 更新相关的话就使用这种模式。

搭建多线程 Core Data 环境的方案一般如下,创建一个 NSMainQueueConcurrencyType 的 context 用于响应 UI 事件,其他涉及大量数据操作可能会阻塞 UI 的就使用 NSPrivateQueueConcurrencyType 的 context。环境搭建好了,如何实现多线程操作?官方文档《Using a Private Queue to Support Concurrency》为我们做了示范,在 private queue 的 context 中进行操作时,应该使用以下方法:

 func performBlock(_ block: () -> Void)//在私有队列中异步地执行 Blcokfunc performBlockAndWait(_ block: () -> Void)//在私有队列中执行 Block 直至操作结束才返回

要在不同线程中使用 managed object context 时,不需要我们创建后台线程然后访问 managed object context 进行操作,而是交给 context 自身绑定的私有队列去处理,我们只需要在上述两个方法的 Block 中执行操作即可。而且,在 NSMainQueueConcurrencyType 的 context 中也应该使用这种方法执行操作,这样可以确保 context 本身在主线程中进行操作。

第二步:数据的同步操作

多 context 同步最简单的方案如下:

NSNotificationCenter.defaultCenter().addObserver(self, selector: "backgroundContextDidSave:", name: NSManagedObjectContextDidSaveNotification, object: backgroundContext)
func backgroundContextDidSave(notification: NSNotification){mainContext.performBlock(){mainContext.mergeChangesFromContextDidSaveNotification(notification)}
}

NSManagedObjectContext 在执行保存操作后会发出 NSManagedObjectContextDidSaveNotification,包含了 context 所有的变化信息,包括新增的、更新的以及删除的对象的信息;而 mergeChangesFromContextDidSaveNotification(_ notification) 方法则用于合并其他 context 中发生的变化。

如果 context 并未观察其他 context 的 NSManagedObjectContextDidSaveNotification通知,且保存时,persistent store 已经被其他 context 更改过,那么很可能存在差异,此时同步就有了以下几种选择:选择保存 context 中的版本或者使用 persistent store 的版本替换 context 的版本,又或是将两者的版本融合。这种同步方式由 NSManagedObjectContext 的 mergePolicy属性决定。

1.NSErrorMergePolicy

默认策略,有冲突时保存失败,persistent store 和 context 都维持原样,并返回错误信息,是唯一反馈错误信息的合并策略。

2.NSMergeByPropertyStoreTrumpMergePolicy

当 persistent store 和 context 里的版本有冲突,persistent store 里的版本有优先权, context 里使用 persistent store 里的版本替换,但是 context 里没有冲突的变化则不会受到影响。

3.NSMergeByPropertyObjectTrumpMergePolicy

与上面相反,context 里的版本有优先权,persistent store 里使用 context 里的版本替换,但是 persistent store 里没有冲突的变化不受影响。

4.NSOverwriteMergePolicy

用 context 里的版本强制覆盖 persistent store 里的版本。

5.NSRollbackMergePolicy

放弃 context 中的所有变化并使用 persistent store 中的版本进行替换。

同步是件很复杂的事情,实际上还是需要根据实际需要来选择同步方案。上面两种方案中第一种概念简单实现容易,第二种比较复杂相对危险,需要谨慎选择同步策略。还有一点需要注意,如果需要跨线程使用 managed object,那么不要直接在其他 context 里使用该 managed object,而应该通过该对象的 objectID 将该对象 fetch 到 context 里。

最后,搞定大量数据

多线程和同步问题解决,最后的难点:大量数据。大量数据意味着需要我们关注内存占用和性能,写代码时需要记得以下规则:

1.尽可能缓存需要的数据,不相关的数据保持 faults状态。

2.fetch 时尽可能精准,少引入不相关的数据。

3.构建多 context 时尽量将同类 managed object 集中,最大限度减少合并需求。

4.提升操作效率,对Asynchronous Fetch, Batch Update,Batch Delete 等新特性尽可能利用。

多线程编程

在 iOS 编程中,这几种情况下需要处理多线程:UI 事件必须在主线程里进行,其他的可以放在后台进行;而进行一些耗时长或阻塞线程的任务,最后放进后台线程里进行。iOS 的多线程技术有这么几种:线程,GCD 和 NSOperationQueue。线程这种技术比较复杂,而多线程编程向来是「复杂必死」,推荐尽可能使用后二者,但线程有个后二者没有的优势:能够精确保证任务执行的时间。GCD 全称是 Grand Central Dispatch, 是 libdispatch 这个库的外部代号,基于 C 的底层来实现;而NSOperationQueue,通称操作队列,是基于 GCD 实现的。GCD 能做的 NSOperationQueue 基本上都能做,而且还有些 GCD 中不易实现的特性,如挂起、取消任务,虽然在 iOS 8 中,GCD 也提供了取消任务的功能,但在 GCD 中任务的挂起和取消都有较大的局限性;虽然大多数情况下应该使用抽象级别更高的 API,也就是 NSOperationQueue,但处理一般的后台任务我偏爱 GCD,主要是 GCD 搭配 Blcok 使用简单,非常方便。如何选择,下面两个链接对此问题的讨论值得一看:

StackOverflow: NSOperation vs. Grand Central Dispatch

Blog: When to use NSOperation vs. GCD

另外,还推荐这些文章:objc 的并发编程专题《Concurrent Programming》 及中文翻译版本;雷纯锋的博客《iOS 并发编程之 Operation Queues》;NSHipster 的《NSOperation》。

设计模式

评价 Delegate, Notification, KVO 几种设计模式的优缺点

我不觉得这个问题是个好问题,与其比较这几个设计模式的优缺点,不如谈它们各自的特点比较好,因为它们是为了解决某类问题才设计出来的,有各自适合的使用场景。另外,给个 iOS 中设计模式的介绍:iOS Design Patterns。

为什么出题目都喜欢把这三个设计模式拿来对比呢?Notification 和 KVO都是用于协助对象间的通信:某个对象监听某个事件的发生,当某个事件发生时,该对象会得到通知然后做出响应。这几句话大概是以前看过的书本上说的。如果你以前没接触过设计模式,第一次学习时总是能够看到事件、响应这类模糊的词汇,看得你云里雾里,好吧,我说的是我。 但 delegate,应该说没有监听的功能,而是当事件发生或时机到了,要求 delegate 对象做点什么。刚开始学习 OC 的时候,一本书中将 delegate比喻为助手,那时候不怎么理解,现在觉得这个比喻十分恰当。虽然delegate 模式在 OC 中随处可见,在UIViewController 类中广泛存在,但在开发 FaceAlbum 的过程中只遇到过一次自定义 protocol/delegate 的情况,后来还是用 KVO 取代了。相对于 Notification 和 KVO 模式,使用 delegate 模式你会明确知道对象的 delegate 能干什么,因为要成为 某个对象的delegate,该对象得遵守指定的 protocol,protocol 指定了 delegate 对象需要实现的方法。

Notification和 KVO两者都需要监听事件的对象(早期看见事件就犯晕,如今写来觉得用这个词挺顺手的)去注册,delegate则需要 delegate 对象遵守指定的 protocol;Notification 中监听者向一个单例对象NSNotificationCenter注册,NSNotificationCenter类似一个广播中心,接受任何对象的注册,后者则向要监听的对象注册,一对一,这两者都不需要对象之间有联系,而 delegate 则需要通信的对象通过变量联系;NSNotification模式里监听的对象与被监听的对象通信是通过 NSNotificationCenter 这个中介,而KVO 里,不能说两者是直接通信的,我没有了解过过 KVO 是如何实现通信的,从表面上看两者就那么心灵感应一般,这是系统替我们实现的,而delegate,由于通过变量连接,直接向 delegate 发送消息即可,在这点上,NSNotification不需要通信双方知道对方,而后两者则不然;在响应事件时,NSNotification和 KVO 模式里都是在注册时指定响应方法,而 delegate 则在 protocol 里预定义了响应方法。

说了这么多,不直观,说个实际场景,比如在 UICollectionView 里选择 cell 的时候,希望 title 能够跟踪选中 cell 的数量。这里用NSNotification和 KVO 都能实现,但是我更喜欢 KVO,感觉更优雅,因为使用NSNotification模式的话,选中一个 cell 的时候要在选择的方法里手动发布通知,而 KVO,只要对观察的属性实现 KVO 兼容的方法就可以了;而delegate,自己做自己的 delegate,呃。而面对一些系统里的事件,比如键盘的出现与消失,图片库的变化,使用NSNotification更加自然,因为 KVO 限于对对象属性的跟踪。

转载于:https://www.cnblogs.com/shidaying/p/4991578.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/256368.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

工业相机基础知识详述 —— 焦平面,像平面,弥散圆,光圈,分辨率,景深,接口,靶面尺寸

一、焦平面 想到焦平面,很多人不由自主就想到不就是焦点所在的垂直于光轴的平面吗?其实其背后隐藏这更多的东西。 1)焦点不止一个 对于一般拍摄场景来说,光通过一个凸透镜,汇聚不到一个点,越靠近中轴线的…

机器学习——SVM之交叉验证对参数(C,gamma)进行优化以及选择

目录 一、(C,gamma)简介 二、交叉验证 1、什么是交叉验证? 2、参数优化方法

【BZOJ-2427】软件安装 Tarjan + 树形01背包

2427: [HAOI2010]软件安装 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 960 Solved: 380[Submit][Status][Discuss]Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一些软件…

Hadoop目录

1. 通过java读取HDFS的数据 (转) 2. FLume监控文件夹,将数据发送给Kafka以及HDFS的配置文件详解 3. 开启hadoop和Hbase集群的lzo压缩功能(转) 4. Hadoop集群WordCount运行详解(转)转载于:https://www.cnblo…

相机标定(二)深入理解四大坐标系与其变换关系

一、前言 视觉系统一共有四个坐标系:像素平面坐标系(u,v)、图像坐标系(x,y)、相机坐标系(Xc,Yc,Zc)和世界坐标系(Xw,Yw,Zw),如下图所示。每种坐标系之间均存…

numpy——ravel()和flatten()

目录 功能 用法 区别 flatten() ravel() 功能 这两个函数的功能都是将多维数组转换成一维 用法 import numpy as np arr np.array([[1, 2],[3, 4]]) arr.flatten()降维默认行序优先,传入参数‘F’表示列序优先 arr.flatten(F) arr.r…

Django的model中日期字段设置默认值的问题

之前写过这样一个model: class MonthlyFeeMember(models.Model):worker models.ForeignKey(Student, verbose_nameu"worker", related_name"as_monthly_fee_members")month models.CharField(umonth, max_length10, defaultget_current_month…

相机标定(三) —— 畸变校正

一、前言 根据针孔模型,物体和成像之间参数会满足相似三角形的关系。但现实中会存在装配误差和透视失真等原因,导致这种关系无法成立,使理想成像与实际成像存在误差,这种误差即称为畸变。 畸变分为径向畸变,切向畸变和…

SVG技术入门:线条动画实现原理

相信大家都见到过这样神奇的技术:一副线条构成的画能自动画出自己。非常的酷。Jake Archibald是这种SVG技术的首创者,并且写了一篇非常好的文章来描述它是如何实现的。Brian Suda也在24 Ways网站上讨论过它。 Polygon使用它在一篇设计方面的文章里创造出…

机器学习——人工神经网络之BP算法编程(python二分类数据集:马疝病数据集)

目录 一、理论知识回顾 1、神经网络模型 2、明确任务以及参数 1)待估参数: 2)超参数: 3)任务 3、神经网络数学模型定义 1)激活函数 ​ 2)各层权重、阈值定义 3)各层输入输…

Halcon例程(基于多个标定图的单目相机标定)详解—— Camera_calibration_multi_image.hdev

一、前言 在我的工业相机专栏里已经将相机标定涉及到的理论部分讲解完毕,为什么要标定以及标定要求出什么参数呢,用一个Halcon 例程来帮助理解。 这个例程是比较经典的标定程序,基本将标定过程讲的比较清楚,用的标定图像是系统自…

SkipList 跳表

为什么选择跳表 目前经常使用的平衡数据结构有:B树,红黑树,AVL树,Splay Tree, Treep等。 想象一下,给你一张草稿纸,一只笔,一个编辑器,你能立即实现一颗红黑树,或者AVL树…

Redis failover过程

在Leader触发failover之前,首先wait数秒(随即0~5),以便让其他sentinel实例准备和调整。如果一切正常,那么leader就需要开始将一个salve提升为master,此slave必须为状态良好(不能处于SDOWN/ODOWN状态)且权重值最低(redis.conf中)的…

机器学习——深度学习之卷积神经网络(CNN)——LeNet卷积神经网络结构

目录 一、卷积神经网络 1、卷积神经的作用 2、LeNet 1)数据库准备——minst 2)模型 二、关于卷积神经网络结构的一些术语定义 1、特征图(Feature map) 2、height(长度)、width(宽度&…

工业相机(3D)主要参数详述

一、前言 准确的完成相机选型是一个视觉工程师必备的技能,而选型前必须对其内部参数了如指掌。工业相机是一种比较复杂的产品,其参数很多,每个参数可能会有不同的标准,下面对主要的参数会做比较详细的阐述。 二、参数详述 2.1 …

JAVA8永久代

在Java虚拟机(以下简称JVM)中,类包含其对应的元数据,比如类的层级信息,方法数据和方法信息(如字节码,栈和变量大小),运行时常量池,已确定的符号引用和虚方法表…

Struts 2初体验

Struts2简介: Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。 Struts 2 目录结构:     apps目录:Struts2示例…

机器学习——深度学习之数据库和自编码器

目录 一、数据库——数据获取 1、Mnist 2、ImageNet 二、自编码器(Auto-encoder)——参数初始化 1、功能 2、基本思想 1)训练第一层 2)训练第二层及以后的神经网络 ​ 3)利用BP对整个神经网络的参数初始值进…

Halcon例程详解 (深度图转换为3D图像)—— xyz_attrib_to_object_model_3d

一、前言 深度图向点云图进行转换是进行3D检测项目时会遇到的问题,halcon里也有针对此问题的相关例程,下面对此例程进行分析。通过学习此例程,我们可以掌握如何将一张深度图像和一张正常二维图像转换为3D点云。 二、分析 * 初始化界面 dev…

动态代理之Cglib浅析

什么是Cglib Cglib是一个强大的,高性能,高质量的代码生成类库。它可以在运行期扩展JAVA类与实现JAVA接口。其底层实现是通过ASM字节码处理框架来转换字节码并生成新的类。大部分功能实际上是ASM所提供的,Cglib只是封装了ASM,简化了…