三.数据存储
1.数据存储技术
1> 数据存储的几种方式
XML属性列表(plist)归档
Preference(偏好设置)
NSKeyedArchiver归档(NSCoding)
SQLite3
Core Data
2> 各自特点
Plist:
属性列表是一种XML格式的文件,拓展名为plist
如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,就可以使用writeToFile:atomically:方法直接将对象写到属性列表文件中
将一个NSDictionary对象归档到一个plist属性列表中
// 将数据封装成字典
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:@"母鸡" forKey:@"name"];
// 将字典持久化到Documents/stu.plist文件中
[dict writeToFile:path atomically:YES];
面试考点:
1. plist的根节点只能是NSDictionary和NSArray,所以存储内容必须转为对象类型
2. 使用场景 功能动态更新应用级别数据更新 XML的替代品
偏好设置:
每个应用都有个NSUserDefaults实例,通过它来存取偏好设置
比如,保存用户名、字体大小、是否自动登录
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:@"itcast" forKey:@"username"];
[defaults setFloat:18.0f forKey:@"text_size"];
[defaults setBool:YES forKey:@"auto_login"];
面试考点:
1. 使用场景保存应用信息
2. 特点 不会自动删除,itune同步,不适合存大数据
3. 使用单例模式、
4. 直接存取结构体,基本数据类型,无需转换
5. 即时操作注意同步
归档:
如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,可以直接用NSKeyedArchiver进行归档和恢复
不是所有的对象都可以直接用这种方法进行归档,只有遵守了NSCoding协议的对象才可以
NSCoding协议有2个方法:
encodeWithCoder:
每次归档对象时,都会调用这个方法。一般在这个方法里面指定如何归档对象中的每个实例变量,可以使用encodeObject:forKey:方法归档实例变量
initWithCoder:
每次从文件中恢复(解码)对象时,都会调用这个方法。一般在这个方法里面指定如何解码文件中的数据为对象的实例变量,可以使用decodeObject:forKey方法解码实例变量
归档一个NSArray对象到Documents/array.archive
NSArray *array = [NSArray arrayWithObjects:@”a”,@”b”,nil];
[NSKeyedArchiver archiveRootObject:array toFile:path];
使用archiveRootObject:toFile:方法可以将一个对象直接写入到一个文件中,但有时候可能想将多个对象写入到同一个文件中,那么就要使用NSData来进行归档对象
归档(编码)
// 新建一块可变数据区
NSMutableData *data = [NSMutableData data];
// 将数据区连接到一个NSKeyedArchiver对象
NSKeyedArchiver *archiver = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease];
// 开始存档对象,存档的数据都会存储到NSMutableData中
[archiver encodeObject:person1 forKey:@"person1"];
[archiver encodeObject:person2 forKey:@"person2"];
// 存档完毕(一定要调用这个方法)
[archiver finishEncoding];
// 将存档的数据写入文件
[data writeToFile:path atomically:YES];
恢复(解码)
// 从文件中读取数据
NSData *data = [NSData dataWithContentsOfFile:path];
// 根据数据,解析成一个NSKeyedUnarchiver对象
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
Person *person1 = [unarchiver decodeObjectForKey:@"person1"];
Person *person2 = [unarchiver decodeObjectForKey:@"person2"];
// 恢复完毕
[unarchiver finishDecoding];
利用归档实现深复制
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:person1];
// 解析data,生成一个新的Person对象
Student *person2 = [NSKeyedUnarchiver unarchiveObjectWithData:data];
面试考点:
1. 特点:存入Document,itune同步,不会自动删除,可存放大型用户数据
2. 使用场景:用户产生的数据,如游戏,操作记录等等
3. 可保存自定义对象,需要遵守NSCoding协议,实现对应的encodeWithCoder initWithCoder 方法
4. 和NSData的配合
4.1> 多对象单目录存储
4.2> 字典/数组内容的深拷贝
5. 不能直接存基本类型和结构体,需要转成对象 NSValue NSNumber
2> 沙盒目录结构
2.1> Library Caches Preferences
2.2> Documents
2.3> tmp
3> 如何读取沙盒中plist的内容
1> 3.1> 读取沙盒并拼接plist的文件路径
NSString *path = [[NSBundle mainBundle] pathForResource:@"app.plist" ofType:nil];
3.2> 根据plist根节点类型读取plist文件
NSArray *apps = [NSArray arrayWithContentsOfFile:path];
2.数据库技术(SQLite&CoreData)
1> SQLite和CoreData的区别
1.1> CoreData可以在一个对象更新时,其关联的对象也会随着更新,相当于你更新一张表时,其关联的其他表的也回随着更新
1.2> CoreData提供更简单的性能管理机制,可以限制查询记录的总数,这个类会自动更新其缓存
1.3> 多表查询方面,CoreData没有SQL直观,没有类似外连接,左连接等操作.
iOS App升级安装 - CoreData数据库升级
1.选中你的mydata.xcdatamodeld文件,选择菜单editor->Add Model Version 比如取名:mydata2.xcdatamodel
2.设置当前版本
3..修改新数据模型mydata2,在新的文件上添加字段及表
4.删除原来的类文件,重新生成下类。在appdelegate中添加*optionsDictionary,原来options:nil 改成options:optionsDictionary
5.重新编译下程序。
增加模型版本——->选择最新的版本——->选择表,添加字段——>删除之前的类,重新生成。
2> iOS内存区域
2.1>栈区
由编译器自动分配释放,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈.
2.2>堆区
一般由程序员分配释放,若程序员不释放,程序结束时由系统回收
2.3>全局区(静态区)
全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量相邻的另一块区域.
全局区分为未初始化全局区: .bss段和初始化全局区: data段.
2.4>常量区
常量字符串就是放在常量区
2.5>代码区
存放函数体的二进制代码
3. 你是如何优化内存管理
1>使用ARC
2>延迟加载 懒加载
3>重用 在正确的地方使用reuseIndentifier
4>缓存 NSCache 保存计算数据
5>处理内存警告 移除对缓存,图片object 和其他一些可以重创建的objects 的强引用
5.1> app delegate 中使用`applicationDidReceiveMemoryWarning:` 的方法
5.2> 自定义UIViewController 的子类(subclass) 中覆盖`didReceiveMemoryWarning`
5.3> 在自定义类中注册并接收UIApplicationDidReceiveMemoryWarningNotification 的通知
6>重用大开销对象 NSDateFormatter 和NSCalendar 懒加载/单例 _formatter.dateFormat = @"EEE MMM dd HH:mm:ss Z yyyy”; 设置和创建速度一样慢
7>自动释放池 手动添加自动释放池
8>是否缓存图片imageNamed imageWithContentOfFile
9>混编
10>循环引用 delegate block nstimer
11> 移除kvo nsnotificationcenter 并未强引用,只记录内存地址,野指针报错 UIViewController自动移除 一般在dealloc中
13> performselector 延迟操作 [NSObject cancelPreviousPerformRequestsWithTarget:self]
4. 循环引用
delegate属性的内存策略
block循环引用 实际场景
5. autorelease的使用
1>工厂方法为什么不释放对象
很多类方法为了在代码块结束时引用的对象不会因无强引用而被释放内存采用自动释放的方式,当其最近的自动释放池释放时该对象才会释放.
2> ARC下autorelease的使用场景
ARC中手动添加autoreleasepool可用于提前释放使用自动释放策略的对象,防止大量自动释放的对象堆积造成内存峰值过高.
3>自动释放池如何工作
自动释放池时栈结构,每个线程的runloop运行时都会自动创建自动释放池,程序员可以代码手动创建自动释放池,自动释放的对象会被添加到最近的(栈顶)自动释放池中,系统自动创建的自动释放池在每个运行循环结束时销毁释放池并给池中所有对象发release消息,手动创建释放池在所在代码块结束时销毁释放池并发消息统一release
避免内存峰值
SDWebimage中加载gif图片 大循环
栈结构栈顶
统一发release消息
5>ARC的实现原理
在程序预编译阶段,将ARC 的代码转换为非ARC 的代码,自动加入release、autorelease、retain
6.Runloop
1> 每个线程上都有一个runloop,主线程默认开启,辅助线程需要手动开启,主要用于
• 使用端口或自定义输入源来和其他线程通信
• 使用线程的定时器
• Cocoa中使用任何performSelector…的方法
• 使线程周期性工作
2> runloop的工作流程
7 Core Graphics绘图的步骤:
获取上下文(画布)
创建路径(自定义或者调用系统的API)并添加到上下文中。
进行绘图内容的设置(画笔颜色、粗细、填充区域颜色、阴影、连接点形状等)
开始绘图(CGContextDrawPath)
释放路径(CGPathRelease)
(1)核心图形Core Graphics是用来实现用户界面视觉设计方案的重要技术框架
(2)核心动画Core Animation提供了一套用于创建和渲染动态交互效果的简单易行的解决方案,通过与UIKit的紧密配合,核心动画可以将界面交互对象与动画过渡效果进行完美地整合。
(3)UIkit是用来打造iOS应用的最重要的图形技术框架,它提供了用于构造触屏设备用户界面的全部工具和资源,并在整个交互体验的塑造过程中扮演着至关重要的角色
8点讲动画和layer ,view的区别
1)触摸
2)layer 特有
3)不触摸的替代
4)属性
5)为什么不合二为1
6)高级用法
1.图层与视图
一个视图就是在屏幕上显示的一个矩形块(比如图片,文字或者视频),它能够1)拦截类似于鼠标点击或者触摸手势等用户输入。视图在层级关系中可以互相嵌套,一个视图可以管理它的所有子视图的位置。
所有的视图都从一个叫做UIVIew的基类派生而来,UIView可以处理触摸 2)(layer不行,但是layer有锚点和position的概念选装变换的时候用),可以支持基于Core Graphics绘图,可以做仿射变换(例如旋转或者缩放),或者简单的类似于滑动或者渐变的动画。
CALayer类在概念上和UIView类似,同样也是一些被层级关系树管理的矩形块,同样也可以包含一些内容(像图片,文本或者背景色),管理子图层的位置。它们有一些方法和属性用来做动画和变换。和UIView最大的不同是CALayer不处理用户的交互。
CALayer并不清楚具体的响应链(iOS通过视图层级关系用来传送触摸事件的机制),于是它并不能够响应事件,即使3)它提供了一些方法来判断是否一个触点在图层的范围之内。
2.平行的层级关系
4)每一个UIview都有一个CALayer实例的图层属性,也就是所谓的backing layer,视图的职责就是创建并管理这个图层,以确保当子视图在层级关系中添加或者被移除的时候,他们关联的图层也同样对应在层级关系树当中有相同的操作。
实际上这些背后关联的图层才是真正用来在屏幕上显示和做动画,UIView仅仅是对它的一个封装,提供了一些iOS类似于处理触摸的具体功能,以及Core Animation底层方法的高级接口。
5)但是为什么iOS要基于UIView和CALayer提供两个平行的层级关系呢?为什么不用一个简单的层级来处理所有事情呢?原因在于要做职责分离,这样也能避免很多重复代码。在iOS和Mac OS两个平台上,事件和用户交互有很多地方的不同,基于多点触控的用户界面和基于鼠标键盘有着本质的区别,这就是为什么iOS有UIKit和UIView,但是Mac OS有AppKit和NSView的原因。他们功能上很相似,但是在实现上有着显著的区别。
绘图,布局和动画,相比之下就是类似Mac笔记本和桌面系列一样应用于iPhone和iPad触屏的概念。把这种功能的逻辑分开并应用到独立的Core Animation框架,苹果就能够在iOS和Mac OS之间共享代码,使得对苹果自己的OS开发团队和第三方开发者去开发两个平台的应用更加便捷。
实际上,这里并不是两个层级关系,而是四个,每一个都扮演不同的角色,除了视图层级和图层树之外,还存在呈现树和渲染树,将在第七章“隐式动画”和第十二章“性能调优”分别讨论。
3.图层的能力
如果说CALayer是UIView内部实现细节,那我们为什么要全面地了解它呢?苹果当然为我们提供了优美简洁的UIView接口,那么我们是否就没必要直接去处理Core Animation的细节了呢?
某种意义上说的确是这样,对一些简单的需求来说,我们确实没必要处理CALayer,因为苹果已经通过UIView的高级API间接地使得动画变得很简单。
但是这种简单会不可避免地带来一些灵活上的缺陷。如果6)你略微想在底层做一些改变,或者使用一些苹果没有在UIView上实现的接口功能,这时除了介入Core Animation底层之外别无选择。
我们已经证实了图层不能像视图那样处理触摸事件,那么他能做哪些视图不能做的呢?这里有一些UIView没有暴露出来的CALayer的功能:(CALayer高级用法)
阴影,圆角,带颜色的边框
3D变换
非矩形范围
透明遮罩
多级非线性动画
4.使用图层
首先我们来创建一个简单的项目,来操纵一些layer的属性。打开Xcode,使用Single View Application模板创建一个工程。
在屏幕中央创建一个小视图(大约200 X 200的尺寸),当然你可以手工编码,或者使用Interface Builder(随你方便)。确保你的视图控制器要添加一个视图的属性以便可以直接访问它。我们把它称作layerView。
运行项目,应该能在浅灰色屏幕背景中看见一个白色方块(图1.3),如果没看见,可能需要调整一下背景window或者view的颜色
8动画
1> ios界面切换
2> iOS中各种动画的类型&特点&使用场景
CAPropertyAnimation
是CAAnimation的子类,也是个抽象类,要想创建动画对象,应该使用它的两个子类:CABasicAnimation和CAKeyframeAnimation
属性解析:
keyPath:通过指定CALayer的一个属性名称为keyPath(NSString类型),并且对CALayer的这个属性的值进行修改,达到相应的动画效果。比如,指定@”position”为keyPath,就修改CALayer的position属性的值,以达到平移的动画效果
CABasicAnimation
CAPropertyAnimation的子类
属性解析:
fromValue:keyPath相应属性的初始值
toValue:keyPath相应属性的结束值
随着动画的进行,在长度为duration的持续时间内,keyPath相应属性的值从fromValue渐渐地变为toValue
如果fillMode=kCAFillModeForwards和removedOnComletion=NO,那么在动画执行完毕后,图层会保持显示动画执行后的状态。但在实质上,图层的属性值还是动画执行前的初始值,并没有真正被改变。比如,CALayer的position初始值为(0,0),CABasicAnimation的fromValue为(10,10),toValue为(100,100),虽然动画执行完毕后图层保持在(100,100)这个位置,实质上图层的position还是为(0,0)
CAKeyframeAnimation
CApropertyAnimation的子类,跟CABasicAnimation的区别是:CABasicAnimation只能从一个数值(fromValue)变到另一个数值(toValue),而CAKeyframeAnimation会使用一个NSArray保存这些数值
属性解析:
values:就是上述的NSArray对象。里面的元素称为”关键帧”(keyframe)。动画对象会在指定的时间(duration)内,依次显示values数组中的每一个关键帧
path:可以设置一个CGPathRef\CGMutablePathRef,让层跟着路径移动。path只对CALayer的anchorPoint和position起作用。如果你设置了path,那么values将被忽略
keyTimes:可以为对应的关键帧指定对应的时间点,其取值范围为0到1.0,keyTimes中的每一个时间值都对应values中的每一帧.当keyTimes没有设置的时候,各个关键帧的时间是平分的
CABasicAnimation可看做是最多只有2个关键帧的CAKeyframeAnimation
CAAnimationGroup
CAAnimation的子类,可以保存一组动画对象,将CAAnimationGroup对象加入层后,组中所有动画对象可以同时并发运行
属性解析:
animations:用来保存一组动画对象的NSArray
默认情况下,一组动画对象是同时运行的,也可以通过设置动画对象的beginTime属性来更改动画的开始时间
CATransition
CAAnimation的子类,用于做转场动画,能够为层提供移出屏幕和移入屏幕的动画效果。iOS比Mac OS X的转场动画效果少一点
UINavigationController就是通过CATransition实现了将控制器的视图推入屏幕的动画效果
属性解析:
type:动画过渡类型
subtype:动画过渡方向
startProgress:动画起点(在整体动画的百分比)
endProgress:动画终点(在整体动画的百分比)
UIView动画
UIKit直接将动画集成到UIView类中,当内部的一些属性发生改变时,UIView将为这些改变提供动画支持
执行动画所需要的工作由UIView类自动完成,但仍要在希望执行动画时通知视图,为此需要将改变属性的代码放在[UIView beginAnimations:nil context:nil]和[UIView commitAnimations]之间
Block动画
帧动画
8 .网络传输
1>DNS是如何工作的
DNS是domain name server的简称,每个网络的计算机都有ip,但是不好记,所以用域名替代(如www.baidu.com),在Internet 上真实在辨识机器的还是IP,所以当使用者输入Domain Name 后,浏览器必须要先去一台有Domain Name 和IP 对应资料的主机去查询这台电脑的IP,而这台被查询的主机,我们称它为Domain Name Server,简称DNS,例如:当你输入www.pchome.com.tw时,浏览器会将www.pchome.com.tw这个名字传送到离他最近的DNS Server 去做辨识,如果查到,则会传回这台主机的IP,进而跟它索取资料,但如果没查到,就会发生类似DNS NOT FOUND 的情形,所以一旦DNS Server当机,就像是路标完全被毁坏,没有人知道该把资料送到那里
9 .AFN
1>实现原理
AFN的直接操作对象AFHTTPClient不同于ASI,是一个实现了NSCoding和NSCopying协议的NSObject子类。AFHTTPClient是一个封装了一系列操作方法的“工具类”,处理请求的操作类是一系列单独的,基于NSOperation封装的,AFURLConnectionOperation的子类。AFN的示例代码中通过一个静态方法,使用dispatch_once()的方式创建AFHTTPClient的共享实例,这也是官方建议的使用方法。在创建AFHTTPClient的初始化方法中,创建了OperationQueue并设置一系列参数默认值。在getPath:parameters:success:failure方法中创建NSURLRequest,以NSURLRequest对象实例作为参数,创建一个NSOperation,并加入在初始化发方中创建的NSOperationQueue。以上操作都是在主线程中完成的。在NSOperation的start方法中,以此前创建的NSURLRequest对象为参数创建NSURLConnection并开启连结。
2> 传递指针如何使一个方法返回多个返回值
传参指针变量的地址,方法内部通过*运算符使用该地址可以修改该地址保存的内容(引用对象的地址),当外部再次使用该指针变量取出引用对象时,引用对象已经在方法内部发生了改变,指针变量指向其他数据,相当于方法的返回值(经方法处理后生成的外部可使用的结果数据).
9 AFNetworking&ASIHttpRequest&MKNetWorking
1、AFN的底层实现基于OC的NSURLConnection和NSURLSession
2、ASI的底层实现基于纯C语言的CFNetwork框架
3、因为NSURLConnection和NSURLSession是在CFNetwork之上的一层封装,因此ASI的运行性能高于AFN
二、对服务器返回的数据处理
1、ASI没有直接提供对服务器数据处理的方式,直接返回的是NSData/NSString
2、AFN提供了多种对服务器数据处理的方式
(1)JSON处理-直接返回NSDictionary或者NSArray
(2)XML处理-返回的是xml类型数据,需对其进行解析
(3)其他类型数据处理
三、监听请求过程
1、AFN提供了success和failure两个block来监听请求的过程(只能监听成功和失败)
* success : 请求成功后调用
* failure : 请求失败后调用
2、ASI提供了3套方案,每一套方案都能监听请求的完整过程
(监听请求开始、接收到响应头信息、接受到具体数据、接受完毕、请求失败)
* 成为代理,遵守协议,实现协议中的代理方法
* 成为代理,不遵守协议,自定义代理方法
* 设置block
四、在文件下载和文件上传的使用难易度
1、AFN
*不容易实现监听下载进度和上传进度
*不容易实现断点续传
*一般只用来下载不大的文件
2、ASI(ipv6)
*非常容易实现下载和上传
*非常容易监听下载进度和上传进度
*非常容易实现断点续传
*下载大文件或小文件均可
3、实现下载上传推荐使用ASI
五、网络监控
1、AFN自己封装了网络监控类,易使用
2、ASI使用的是Reachability,因为使用CocoaPods下载ASI时,会同步下载Reachability,但Reachability作为网络监控使用较为复杂(相对于AFN的网络监控类来说)
3、推荐使用AFN做网络监控-AFNetworkReachabilityManager
六、ASI提供的其他实用功能
1、控制信号旁边的圈圈要不要在请求过程中转
2、可以轻松地设置请求之间的依赖:每一个请求都是一个NSOperation对象
3、可以统一管理所有请求(还专门提供了一个叫做ASINetworkQueue来管理所有的请求对象)
* 暂停/恢复/取消所有的请求
* 监听整个队列中所有请求的下载进度和上传进度
MKNetworkKit 是一个使用十分方便,功能又十分强大、完整的iOS网络编程代码库。它只有两个类, 它的目标是使用像AFNetworking这么简单,而功能像ASIHTTPRequest(已经停止维护)那么强大。它除了拥有 AFNetworking和ASIHTTPRequest所有功能以外,还有一些新特色,包括:
1、高度的轻量级,仅仅只有2个主类
2、自主操作多个网络请求
3、更加准确的显示网络活动指标
4、自动设置网络速度,实现自动的2G、3G、wifi切换
5、自动缓冲技术的完美应用,实现网络操作记忆功能,当你掉线了又上线后,会继续执行未完成的网络请求
6、可以实现网络请求的暂停功能
7、准确无误的成功执行一次网络请求,摒弃后台的多次请求浪费
8、支持图片缓冲
9、支持ARC机制
10、在整个app中可以只用一个队列(queue),队列的大小可以自动调整
10.性能优化
1> 如何进行性能优化
1.1> 内存优化的点 重用 懒加载
1.2> 渲染优化 尽量使用不透明的图 把views 设置为透明
1.3> 在ImageView设置前,尽量先调整好图片大小 尤其放在uiscrolliview中自动缩放耗能
1.4> 避免使用过大的xib 和分镜的区别 一次性加载
1.5> 不要阻塞主线程 除渲染,触摸响应等 尽量异步处理 如存储,网络 异步线程通知
1.6> 缓存 网络响应,图片,计算结果(行高) 网络响应NSUrlconnection默认缓存request,设置策略 非网络请求使用nscache nsdictionary
1.7> 避免反复处理数据 在服务器端和客户端使用相同的数据结构
1.8> 选择正确的数据格式 json 速度快解析方便 xml sax方式逐行解析解析大文件不占用内存和损失性能
1.9> 优化tableview 重用cell 缓存行高cell子视图尽量少且不透明
1.10> 选择正确的数据存储选项 plist nscoding NSUserDefaults sqlite coredata