写点什么

iOS 开发底层面试攻略

用户头像
关注
发布于: 19 小时前
iOS开发底层面试攻略

以下是回顾之前上、中、下三篇底层面试题的补充,附上答案。

俗话说得好,底层不牢,地动山摇。

这些答案只是给大家一些参考,大家可以再结合自己理解进行回答,有需要的朋友们下面来一起看看吧。

本文收录:公众号【iOS 进阶宝典《iOS底层面试干货分享(补充)》】

iOS 开发中的加密方式

iOS 加密相关算法框架:CommonCrypto


1:对称加密: DES、3DES、AES


  • 加密和解密使用同一个密钥。

  • 加密解密过程:


  • 明文->密钥加密->密文

  • 密文->密钥解密->明文


  • 优点:算法公开、计算量少、加密速度快、加密效率高、适合大批量数据加密;

  • 缺点:双方使用相同的密钥,密钥传输的过程不安全,易被破解,因此为了保密其密钥需要经常更换。


AES:AES 又称高级加密标准,是下一代的加密算法标准,支持 128、192、256 位密钥的加密,加密和解密的密钥都是同一个。iOS 一般使用 ECB 模式,16 字节 128 位密钥。


AES 算法主要包括三个方面:轮变化圈数密钥扩展


  • 优点:高性能、高效率、灵活易用、安全级别高。

  • 缺点:加密与解密的密钥相同,所以前后端利用 AES 进行加密的话,如何安全保存密钥就成了一个问题。


DES:数据加密标准,DES 算法的入口参数有三个:KeyDataMode


  • 其中 Key 为 7 个字节共 56 位,是 DES 算法的工作密钥;Data 为 8 个字节 64 位,是要被加密或被解密的数据;Mode 为 DES 的工作方式,有两种:加密、解密

  • 缺点:与 AES 相比,安全性较低。


3DES:3DES 是 DES 加密算法的一种模式,它使用 3 条 64 位的密钥对数据进行三次加密。是 DES 向 AES 过渡的加密算法,是 DES 的一个更安全的变形。它以 DES 为基本模块,通过组合分组方法设计出分组加密算法。


2.非对称加密:RSA 加密


  • 非对称加密算法需要成对出现的两个密钥,公开密钥(publickey) 和私有密钥(privatekey) 。

  • 加密解密过程:对于一个私钥,有且只有一个与之对应的公钥。生成者负责生成私钥和公钥,并保存私钥,公开公钥。


公钥加密,私钥解密;或者私钥数字签名,公钥验证。公钥和私钥是成对的,它们互相解密。


  • 特点:

  • 1).对信息保密,防止中间人攻击:将明文通过接收人的公钥加密,传输给接收人,因为只有接收人拥有对应的私钥,别人不可能拥有或者不可能通过公钥推算出私钥,所以传输过程中无法被中间人截获。只有拥有私钥的接收人才能阅读。此方法通常用于交换对称密钥

  • 2). 身份验证和防止篡改:权限狗用自己的私钥加密一段授权明文,并将授权明文和加密后的密文,以及公钥一并发送出来,接收方只需要通过公钥将密文解密后与授权明文对比是否一致,就可以判断明文在中途是否被篡改过。此方法用于数字签名。


  • 优点:加密强度小,加密时间长,常用于数字签名和加密密钥、安全性非常高、解决了对称加密保存密钥的安全问题。

  • 缺点:加密解密速度远慢于对称加密,不适合大批量数据加密。


3. 哈希算法加密:MD5加密.SHA加密HMAC加密


  • 哈希算法加密是通过哈希算法对数据加密,加密后的结果不可逆,即加密后不能再解密。

  • 特点:不可逆、算法公开、相同数据加密结果一致。


  • 作用:信息摘要,信息“指纹”,用来做数据识别的。如:用户密码加密、文件校验、数字签名、鉴权协议。


MD5 加密:对不同的数据加密的结果都是定长的 32 位字符。


.SHA 加密:安全哈希算法,主要适用于数字签名标准(DSS)里面定义的数字签名算法(DSA)。对于长度小于2^64位的消息,SHA1会产生一个 160 位的消息摘要。当接收到消息的时候,这个消息摘要可以用来验证数据的完整性。在传输的过程中,数据很可能会发生变化,那么这时候就会产生不同的消息摘要。当然除了SHA1还有SHA256以及SHA512等。


HMAC 加密:给定一个密钥,对明文加密,做两次“散列”,得到的结果还是 32 位字符串。


4. Base64 加密


  • 一种编码方式,严格意义上来说不算加密算法。其作用就是将二进制数据编码成文本,方便网络传输。

  • base64 编码之后,数据长度会变大,增加了大约 1/3,但是好处是编码后的数据可以直接在邮件和网页中显示;


  • 虽然 base64 可以作为加密,但是 base64 能够逆运算,非常不安全!

  • base64 编码有个非常显著的特点,末尾有个 ‘=’ 号。


  • 原理:1). 将所有字符转化为 ASCII 码;2). 将 ASCII 码转化为 8 位二进制;3). 将二进制三位一组不足补 0,共 24 位,再拆分成 6 位一组共四组;4). 统一在 6 位二进制前补两个 0 到八位;5). 将补 0 后的二进制转为十进制;6). 最后从 Base64 编码表获取十进制对应的 Base64 编码。

App 安全,数字签名,App 签名,重签名

因为应用实际上是一个加壳的 ipa 文件,但是有可能被砸壳甚至越狱手机下载的 ipa 包直接就是脱壳的,可以直接反编译,所以不要在plist文件、项目中的静态文件中存储关键的信息。所以敏感信息对称加密存储或者就存储到keychain里。而且加密密钥也要定期更换。


数字签名是通过HASH算法RSA加密来实现的。 我们将明文数据加上通过RSA加密的数据HASH值 一起传输给对方,对方可以解密拿出HASH值来进行验证。这个通过 RSA 加密HASH值数据,我们称之为数字签名。


App 签名


  • 1.在 Mac 开发机器上生成一对公钥和私钥,这里称为公钥 L,私钥 L(L:Local)。

  • 2.苹果自己有固定的一对公钥和私钥,私钥在苹果后台,公钥在每个 iOS 设备上。这里称为公钥 A,私钥 A(A:Apple)。


  • 3.把开发机器上的公钥 L 传到苹果后台,用苹果后台的私钥 A 去签名公钥 L。得到一个包含公钥 L 以及其签名数据证书。

  • 4.在苹果后台申请 AppID,配置好设备 ID 列表APP 可使用的权限,再加上第③步的证书,组成的数据用私钥 A 签名,把数据和签名一起组成一个Provisioning Profile描述文件,下载到本地 Mac 开发机器


  • 5.在开发时,编译完一个 APP 后,用本地的私钥 L 对这个 APP 进行签名,同时把第④步得到的Provisioning Profile描述文件打包进 APP 里,文件名为embedded.mobileprovision,把 APP 安装到手机上。

  • 6.在安装时,iOS 系统取得证书,通过系统内置的公钥 A,去验证embedded.mobileprovision数字签名是否正确,里面的证书签名也会再验一遍。


  • 7.确保了embedded.mobileprovision里的数据都是苹果授权的以后,就可以取出里面的数据,做各种验证,包括用公钥 L 验证 APP 签名,验证设备 ID 是否在 ID 列表上,AppID 是否对应得上,权限开关是否跟 APP 里的 Entitlements 对应等。

OC 数据类型


① 基本数据类型


  • C 语言基本数据类型(如short、int、float等)在 OC 中都不是对象,只是一定字节的内存空间用于存储数值,他们都不具备对象的特性,没有属性方法可以被调用。

  • OC 中的基本数据类型:NSInteger(相当于 long 型整数)、NSUInteger(相当于 unsigned long 型整数)、CGFloat(在 64 位系统相当于 double,32 位系统相当于 float)等。他们并不是类,只是用typedef对基本数据类型进行了重定义,他们依然只是基本数据类型

  • 枚举类型:其本质是无符号整数。

  • BOOL 类型:是宏定义,OC 底层是使用 signed char 来代表 BOOL。


② 指针数据类型


指针数据类型包括: 类classid


  • 类 class:NSStringNSSetNSArrayNSMutableArrayNSDictionaryNSMutableDictionaryNSValueNSNumber(继承NSValue)等,都是 class,创建后便是对象,继承 NSObject。OC 中提供了NSValueNSNumber来封装 C 语言的基本类型,这样我们就可以让他们具有面向对象的特征了。


  • id:id是指向 Objective-C 对象的指针,等价于 C 语言中的void*,可以映射任何对象指针指向他,或者映射它指向其他的对象。常见的 id 类型就是类的 delegate 属性。


集合 NSSet 和数组 NSArray 区别:


  • 都是存储不同的对象的地址;

  • 但是 NSArray 是有序的集合,NSSet 是无序的集合,它们俩可以互相转换。


  • NSSet 会自动删除重复元素。

  • 集合是一种哈希表,运用散列算法,查找集合中的元素比数组速度更快,但是它没有顺序。


③ 构造类型


构造类型包括:结构体、联合体


  • 结构体:struct,将多个基本数据类型的变量组合成一个整体。结构体中访问内部成员用点运算符访问。

  • 联合体(共用体):union,有些类似结构体struct的一种数据结构,联合体(union)和结构体(struct)同样可以包含很多种数据类型和变量。


结构体和联合体的区别:


  • 结构体(struct)中所有变量是“共存”的,同一时刻每个成员都有值,其sizeof为所以成员的和。


优点: 是“有容乃大”,全面;

缺点: 是 struct 内存空间的分配是粗放的,不管用不用,全


分配,会造成内存浪费。


  • 联合体(union)中各变量是“互斥”的,同一时刻只有一个成员有值,其sizeof为最长成员的sizeof


优点: 是内存使用更为精细灵活,也节省了内存空间。

缺点: 就是不够“包容”,修改其中一个成员时会覆盖原来的成员值;

property 和属性修饰符

@property 的本质ivar(实例变量) + setter + getter.


我们每次增加一个属性时内部都做了什么:


  • 1.系统都会在 ivar_list 中添加一个成员变量的描述;

  • 2.在 method_list 中增加 settergetter 方法的描述;

  • 3.在属性列表中增加一个属性的描述;

  • 4.然后计算该属性在对象中的偏移量;


  • 5.给出 settergetter 方法对应的实现,在 setter 方法中从偏移量的位置开始赋值,在 getter 方法中从偏移量开始取值,为了能够读取正确字节数,系统对象偏移量的指针类型进行了类型强转。


修饰符:


  • MRC 下: assign、retain、copy、readwrite、readonly、nonatomic、atomic等。

  • ARC 下:assign、strong、weak、copy、readwrite、readonly、nonatomic、atomic、nonnull、nullable、null_resettable、_Null_unspecified等。


下面分别解释


  • assign:用于基本数据类型,不更改引用计数。如果修饰对象(对象在堆需手动释放内存,基本数据类型在栈系统自动释放内存),会导致对象释放后指针不置为 nil 出现野指针。

  • retain:和 strong 一样,释放旧对象,传入的新对象引用计数+1;在 MRC 中和 release 成对出现。

  • strong:在 ARC 中使用,告诉系统把这个对象保留在堆上,直到没有指针指向,并且 ARC 下不需要担心引用计数问题,系统会自动释放。

  • weak:在被强引用之前,尽可能的保留,不改变引用计数;weak 引用是弱引用,你并没有持有它;它本质上是分配一个不被持有的属性,当引用者被销毁(dealloc)时,weak 引用的指针会自动被置为 nil。可以避免循环引用。

  • copy:一般用来修饰不可变类型属性字段,如:NSStringNSArrayNSDictionary等。用 copy 修饰可以防止本对象属性受外界影响,在NSMutableString赋值给NSString时,修改前者 会导致 后者的值跟着变化。还有block也经常使用 copy 修饰符,但是其实在 ARC 中编译器会自动对 block 进行 copy 操作,和 strong 的效果是一样的。但是在 MRC 中方法内部的 block 是在栈区,使用 copy 可以把它放到堆区。

  • readwrite:可以读、写;编译器会自动生成 setter/getter 方法。

  • readonly:只读;会告诉编译器不用自动生成 setter 方法。属性不能被赋值。

  • nonatomic:非原子性访问。用 nonatomic 意味着可以多线程访问变量,会导致读写线程不安全。但是会提高执行性能。

  • atomic:原子性访问。编译器会自动生成互斥锁,对 setter 和 getter 方法进行加锁来保证属性的 赋值和取值 原子性操作是线程安全的,但不包括可变属性的操作和访问。比如我们对数组进行操作,给数组添加对象或者移除对象,是不在 atomic 的负责范围之内的,所以给被 atomic 修饰的数组添加对象或者移除对象是没办法保证线程安全的。原子性访问的缺点是会消耗性能导致执行效率慢。

  • nonnull:设置属性或方法参数不能为空,专门用来修饰指针的,不能用于基本数据类型。

  • nullable:设置属性或方法参数可以为空。

  • null_resettable:设置属性,get 方法不能返回为空,set 方法可以赋值为空。

  • _Null_unspecified:设置属性或方法参数不确定是否为空。


后四个属性应该主要就是为了提高开发规范,提示使用的人应该传什么样的值,如果违反了对规范值的要求,就会有警告。


weak 修饰的对象释放则自动被置为 nil 的实现原理:


Runtime维护了一个weak表,存储指向某个对象的所有weak指针weak表其实是一个hash(哈希)表Key是所指对象的地址,Valueweak指针的地址数组(这个地址的值是所指对象的地址)。


weak 的实现原理可以概括一下三步:


  • 1、初始化时:runtime会调用objc_initWeak函数,初始化一个新的 weak 指针指向对象的地址。

  • 2、添加引用时:objc_initWeak函数会调用 objc_storeWeak()函数, objc_storeWeak() 的作用是更新指针指向,创建对应的弱引用表。

  • 3、释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个 entry 从 weak 表中删除,最后清理对象的记录。

成员变量ivar和属性property的区别,以及不同关键字的作用

成员变量: 成员变量的默认修饰符是@protected、不会自动生成 set 和 get 方法,需要手动实现、不能使用点语法调用,因为没有 set 和 get 方法,只能使用->


属性: 属性会默认生成带下划线的成员变量和setter/getter方法、可以用点语法调用,实际调用的是 set 和 get 方法。


注意:分类中添加的属性是不会自动生成 **setter/getter**方法的,必须要手动添加。


实例变量: class 类进行实例化出来的对象为实例对象


关键字作用:


  • 访问范围关键字

  • @public:声明公共实例变量,在任何地方都能直接访问对象的成员变量。

  • @private:声明私有实例变量,只能在当前类的对象方法中直接访问,子类要访问需要调用父类的 get/set 方法。

  • @protected:可以在当前类及其子类对象方法中直接访问(系统默认)。

  • @package:在同一个包下就可以直接访问,比如说在同一个框架。

  • 关键字

  • @property:声明属性,自动生成一个以下划线开头的成员变量_propertyName(默认用 @private 修饰)、属性 setter、getter 方法的声明、属性 setter、getter 方法的实现。**注意:**在协议@protocol中只会生成 getter 和 setter 方法的声明,所以不仅需要手动实现 getter 和 setter 方法还需要手动定义变量。

  • @sythesize:修改 @property 自动生成的_propertyName 成员变量名,@synthesize propertyName = newName;

  • @dynamic:告诉编译器:属性的 setter 与 getter 方法由用户自己实现,不自动生成。**谨慎使用:**如果对属性赋值取值可以编译成功,但运行会造成程序崩溃,这就是常说的动态绑定。

  • @interface:声明类

  • @implementation:类的实现

  • @selecter:创建一个 SEL,类成员指针

  • @protocol:声明协议

  • @autoreleasepool:ARC 中的自动释放池

  • @end:类结束

类簇

类簇是 Foundation 框架中广泛使用的设计模式。类簇在公共抽象超类下对多个私有的具体子类进行分组。以这种方式对类进行分组简化了面向对象框架的公共可见体系结构,而不会降低其功能丰富度。类簇是基于抽象工厂设计模式的


常见的类簇有 NSStringNSArrayNSDictionary等。 **以数组为例:**不管创建的是可变还是不可变的数组,在alloc之后得到的类都是 __NSPlaceholderArray。而当我们 init 一个不可变的空数组之后,得到的是 __NSArray0;如果有且只有一个元素,那就是 __NSSingleObjectArrayI;有多个元素的,叫做 __NSArrayIinit 出来一个可变数组的话,都是 __NSArrayM


优点:

  • 可以将抽象基类背后的复杂细节隐藏起来。

  • 程序员不会需要记住各种创建对象的具体类实现,简化了开发成本,提高了开发效率。

  • 便于进行封装和组件化。

  • 减少了 if-else 这样缺乏扩展性的代码。

  • 增加新功能支持不影响其他代码。


缺点:

  • 已有的类簇非常不好扩展。


我们运用类簇的场景:


  1. 出现 bug 时,可以通过崩溃报告中的类簇关键字,快速定位 bug 位置。

  2. 在实现一些固定且并不需要经常修改的事物时,可以高效的选择类簇去实现。例:


  • 针对不同版本,不同机型往往需要不同的设置,这时可以选择使用类簇。

  • app 的设置页面这种并不需要经常修改的页面,可以使用类簇去创建大量重复的布局代码。

文末推荐:iOS 热门文集 &视频解析

① Swift

② iOS底层技术

③ iOS逆向防护

④ iOS面试合集

⑤ 大厂面试题+底层技术+逆向安防+Swift

喜欢的小伙伴记得点赞喔~

收藏等于白嫖,点赞才是真情ღ( ´・ᴗ・` )ღ

用户头像

关注

你的努力没人会看到,可成功会让人羡慕。 2020.12.08 加入

iOS交流群:642363427 公众号:iOS进阶宝典 抖音:iOS 普拉斯 视频学习:https://space.bilibili.com/107521719 感谢支持与关注

评论

发布
暂无评论
iOS开发底层面试攻略