1、MVC架构
1). MVC模式:Model View Control,把模型 视图 控制器 层进行解耦合编写。
2). MVVM模式:Model View ViewModel 把模型 视图 业务逻辑 层进行解耦和编写。
2、设计模式
设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型的事情。
1). 单例模式:通过static关键词,声明全局变量。在整个进程运行期间只会被赋值一次。
2). 观察者模式:KVO是典型的通知模式,观察某个属性的状态,状态发生变化时通知观察者。
3). 委托模式:代理+协议的组合。实现1对1的反向传值操作。
4). 工厂模式:通过一个类方法,批量的根据已有模板生产对象。
5). 装饰者模式:
3、KVC、KVO
KVO的底层实现?
KVO基于runtime机制实现。KVO这一机制是基于NSKeyValueObserving协议的
在iOS中是观察者模式的一种表现。我们可以使用KVO让某个对象成为另外一个对象的监听者。当被监听对象的属性发生改变时,KVO就会通知监听者。KVO的是通过一种叫isa-swizzling的技术实现的。(类似runtime的method swizzling,runtime进行方法互换的一种黑魔法。)
手动触发KVO?
手动调用willChangeValueForKey:和didChangeValueForKey:。
通过KVC修改属性会触发KVO。
KVC的底层实现?NSKeyValueCoding(KVC)协议
当一个对象调用setValue方法时,方法内部会做以下操作:
1). 检查是否存在相应的key的set方法,如果存在,就调用set方法。
2). 如果set方法不存在,就会查找与key相同名称并且带下划线的成员变量,如果有,则直接给成员变量属性赋值。
3). 如果没有找到_key,就会查找相同名称的属性key,如果有就直接赋值。
4). 如果还没有找到,则调用valueForUndefinedKey:和setValue:forUndefinedKey:方法。
这些方法的默认实现都是抛出异常,我们可以根据需要重写它们。
4、持久化方案
NSUserDefaults(Preference偏好设置) ,用于存储配置信息,和自己实例的信息
plist存储
NSKeyedArchiver钥匙串
NSCoding存档
SQLite3
CoreData 用于存储查询需求较多的数据,接口返回的对象
FMDB 用于存储查询需求较多的数据
FMDB是对于libsqlite3框架的封装,使用前也要打开一个数据库,这个数据库文件存在则直接打开否则会创建并打开。这里FMDB引入了一个MFDatabase对象来表示数据库,打开数据库和后面的数据库操作全部依赖此对象。在FMDB中FMDatabase有beginTransaction、commit、rollback三个方法进行开启事务、提交事务和回滚事务。
NSKeyedArchiver钥匙串,使用keychain需要导入Security框架。
plist是iOS系统中特有的文件格式。我们常用的NSUserDefaults偏好设置实质上就是plist文件操作。plist文件是用来持久化存储数据的。比如,存储全国城市名称和id。
NSCoding存档,遵循NSCoding协议,实现复杂对象的存储,实现该协议后可以对其进行打包或者解包,转化为NSDate
5、NSThread、GCD、NSOperation多线程常用方法
NSThread:初始化方式手动开辟内存需要启动,构造器方式自动启动线程。线程使用完毕后的资源回收。NSThread 需要我们自己去管理线程的生命周期,还要考虑线程同步、加锁问题,GCD和NSOperationQueue不需要考虑。
GCD 是面向底层的 C 语言的 API,NSOpertaionQueue 用 GCD 构建封装的,
GCD 共有三种队列类型:
main queue:通过 dispatch_get_main_queue()获得,这是一个与主线程相关的串行队列。
global queue:全局队列是并发队列,由整个进程共享。存在着高、中、低三种优先级的全局队列。调用 dispath_get_global_queue 并传入优先级来访问队列。
自定义队列:通过函数 dispatch_queue_create 创建的队列
设计多读单写:多个读者可以同时读取数据,而在读的时候,不能取写入数据。并且,在写的过程中,不能有其他写者去写,也不能其他有读者去读。
-(id)readDataForKey:(NSString *)key {
__block id result;
读的时候用同步方式立马返回数据
dispatch_sync(_concurrentQueue,^{
result = [self valueForKey:key];
} );
}
-(void)writeData:(id)data forKey:(NSString*)key {
栅栏函数做异步拦截操作
dispatch_barrier_async(_concurrentQueue,^{
[self setValue:data forKey:key];
});
}
6、加盐,加密,登录流程
哈希(散列)函数 : MD5、SHA (是一种不可逆的摘要算法,用于生成32位摘要,用于验证数据的有效性,无法逆着破解得到原文。)
对称加密算法:DES、3DES、AES
非对称加密算法:RSA
Base64:属于加密算法,是可逆的,经过encode后,可以decode得到原文。在开发中,有的公司上传图片采用的是将图片转换成base64字符串,再上传。在做加密相关的功能时,通常会将数据进行base64加密/解密。

7、循环引用
1、Block循环引用
原因:一个对象中强引用了block,并且在block中又使用了该对象,就会发生循环引用。
解决方式:避免产生循环引用,通常是将 strong 引用改为 weak 引用。 比如在修饰属性时用 weak。
2、代理(delegate)循环引用
原因:代理(delegate)循环引用是 iOS 中开发中比较常遇到的循环引用。
解决方式:一般在声明 delegate 的时候都要使用弱引用 weak,或者assign,MRC 的话只能用 assign,在 ARC 的情况下最好使用 weak, 因为 weak 修饰的变量在释放后自动指向 nil,防止野指针存在。
3、NSTimer 循环引用
原因:在控制器内,创建 NSTimer 作为其属性,由于定时器创建后也会强引用该控制器对象,那么该对象和定时器就相互循环引用了。
解决方式:这里我们可以使用手动断开循环引用, 如果是不重复定时器,在回调方法里将定时器 invalidate 并置为 nil 即可。 如果是重复定时器,在合适的位置将其 invalidate 并置为 nil 即可
内存管理
iOS内存管理机制的原理是引用计数。当这块内存被创建后,它的引用计数0->1,另外一个对象或指针指向这块内存,引用计数1->2,不再指向这块内存时,引用计数-1,当一块内存的引用计数变为0,表示没有任何对象或指针持有这块内存,系统便会立刻释放掉这块内存。
实际上是三种方案的结合
1.TaggedPointer(针对类似于NSNumber的小对象类型)
2.NONPOINTER_ISA(64位系统下)
3.散列表(引用计数表、weak表)
8、内存泄漏
泄露的内存主要有以下两种:
Abandon Memory 这种是循环引用,无法释放掉的内存。
Leak Memory 这种是忘记 Release 操作所泄露的内存。
检测内存泄漏的方式有:
Memory Leaks、
第二种忘记 Release 操作所泄露的内存
1、地图类处理
地图是比较耗费App内存的,因此在根据文档实现某地图相关功能的同时,我们需要注意内存的正确释放,大体需要注意的有需在使用完毕时将地图、代理等滞空为nil,注意地图中标注(大头针)的复用,并且在使用完毕时清空标注数组等。
2、大次数循环内存暴涨问题
原因:该循环内产生大量的临时对象,直至循环结束才释放,可能导致内存泄漏。
解决方法:循环中创建自己的autoReleasePool,及时释放占用内存大的临时变量,减少内存占用峰值。
- 类(class)和结构体(struct)有什么区别?
Swift 中,类是引用类型,结构体是值类型。值类型在传递和赋值时将进行复制,而引用类型则只会使用引用对象的一个"指向"。所以他们两者之间的区别就是两个类型的区别。
内存中,引用类型,类是在堆(heap)上,而值类型,结构体实在栈(stack)上进行存储和操作。相比于栈上的操作,堆上的操作更加复杂耗时,所以苹果官方推荐使用结构体,这样可以提高 App 运行的效率。
class有这几个功能struct没有的:
1、class可以继承,这样子类可以使用父类的特性和方法
2、类型转换可以在runtime的时候检查和解释一个实例的类型
3、可以用deinit来释放资源
4、一个类可以被多次引用
struct也有这样几个优势:
1、结构较小,适用于复制操作,相比于一个class的实例被多次引用更加安全。
2、无须担心内存memory leak或者多线程冲突问题
9、 Runtime实现的机制是什么,怎么用,一般用于干嘛?
1). 使用时需要导入的头文件
2). Runtime 运行时机制,它是一套C语言库。
3). 实际上我们编写的所有OC代码,最终都是转成了runtime库的东西。
比如:
类转成了 Runtime 库里面的结构体等数据类型,
方法转成了 Runtime 库里面的C语言函数,
平时调方法都是转成了 objc_msgSend 函数(所以说OC有个消息发送机制)
// OC是动态语言,每个方法在运行时会被动态转为消息发送,即:objc_msgSend(receiver, selector)。
// [stu show]; 在objc动态编译时,会被转意为:objc_msgSend(stu, @selector(show));
4). 因此,可以说 Runtime 是OC的底层实现,是OC的幕后执行者。有了Runtime库,能做什么事情呢
Runtime库里面包含了跟类、成员变量、方法相关的API。
比如
(1)获取类里面的所有成员变量。
(2)为类动态添加成员变量。
(3)为类动态添加新的方法。
(4)动态改变类的方法实现等。(Method Swizzling)
iOS:学习runtime的理解和心得
2. 什么是 Method Swizzle(黑魔法),什么情况下会使用?
1). 在没有一个类的实现源码的情况下,想改变其中一个方法的实现,除了继承它重写、和借助类别重名方法之外,还有更加灵活的方法 Method Swizzle。
2). Method Swizzle 指的是改变一个已存在的选择器对应的实现的过程。OC中方法的调用能够在运行时通过改变,通过改变类的调度表中选择器到最终函数间的映射关系。
3). 在OC中调用一个方法,其实是向一个对象发送消息,查找消息的唯一依据是selector的名字。利用OC的动态特性,可以实现在运行时偷换selector对应的方法实现。
4). 每个类都有一个方法列表,存放着selector的名字和方法实现的映射关系。IMP有点类似函数指针,指向具体的方法实现。
5). 我们可以利用 method_exchangeImplementations 来交换2个方法中的IMP。
6). 我们可以利用 class_replaceMethod 来修改类。
7). 我们可以利用 method_setImplementation 来直接设置某个方法的IMP。
归根结底,都是偷换了selector的IMP。
3. _objc_msgForward 函数是做什么的,直接调用它将会发生什么?
答:_objc_msgForward是 IMP 类型,用于消息转发的:当向一个对象发送一条消息,但它并没有实现的时候,_objc_msgForward会尝试做消息转发。
10、单例模式
通过static关键词,声明全局变量。在整个进程运行期间只会被赋值一次。
999、Swift相关
Swift特有,tuples(元组),可以使你创建和传递一组数值。
Swift特有,可选项类型(Optionals)。Optionals 相比于Objective-C中nil指针更加安全和简明。
在Swift中,泛型解决了代码复用的问题。
Swift 既是面向对象的,又是函数式的编程语言。
Swift 是函数式编程语言,是因为 Swift 支持 map, reduce, filter, flatmap 这类去除中间状态、数学函数式的方法,更加强调运算结果而不是中间过程。
Swift是一门静态语言。它的动态特性都是通过桥接OC来实现。runtime其实就是Objective-C的动态机制。可以动态加载对象、添加方法、修改属性、传递信息等。
1000、AFNetWorking的二次封装
1、AFNetWorking的使用我们通常会对通用参数、网址环境切换、网络状态监测、请求错误信息等进行封装。在封装网络请求类时需注意的是需要将请求队列管理者AFHTTPSessionManager声明为单例创建形式。
1001、蓝牙基础知识
CoreBluetooth框架的核心其实是两个东西,peripheral和central, 可以理解成外设和中心。对应他们分别有一组相关的API和类。
蓝牙中心模式流程
1\. 建立中心角色
2\. 扫描外设(discover)
3\. 连接外设(connect)
4\. 扫描外设中的服务和特征(discover)
- 4.1 获取外设的services
- 4.2 获取外设的Characteristics,获取Characteristics的值,获取Characteristics的Descriptor和Descriptor的值
5\. 与外设做数据交互(explore and interact)
6\. 订阅Characteristic的通知
7\. 断开连接(disconnect)
蓝牙外设模式流程
1\. 启动一个Peripheral管理对象
2\. 本地Peripheral设置服务,特性,描述,权限等等
3\. Peripheral发送广告
4\. 设置处理订阅、取消订阅、读characteristic、写characteristic的委托方法
蓝牙设备状态
1\. 待机状态(standby):设备没有传输和发送数据,并且没有连接到任何设
2\. 广播状态(Advertiser):周期性广播状态
3\. 扫描状态(Scanner):主动寻找正在广播的设备
4\. 发起链接状态(Initiator):主动向扫描设备发起连接。
5\. 主设备(Master):作为主设备连接到其他设备。
6\. 从设备(Slave):作为从设备连接到其他设备。
已连接(Connected)
网友评论