与网络打交道
可以直接测试网络上的资源, 如果想自己控制资源, 完成自己访问自己资源的话, 可以自己搭建一个服务器
网络环境搭建
客户端(前端) >>>>>发送网络请求 .>>>>>> 服务器端..>查询数据>>..数据库
<<<<<..响应请求, 返回数据.<<<< ..<返回数据 <<<..>
服务器端用什么的都可以....教程里竟然用了 JAVA....
用 eclipse, 配置教程:/Users/mac/IOS
> 安装 IDE[ 选择 workspace(存放服务器代码的空间, 即项目的位置) >> ] -> 编写服务器程序(或者拿其他的来用) -> 跑起服务器程序(将别人的服务器程序扔到 workspace) -> 在导航栏右击.import.import.general.exsistProject.选择程序 -> 打开看可能会报错, 因为没有配置服务器环境 - (如果乱码: Preference.General.ContentType.JAVASourceFile.defualtEncoding = UTF-8)
> 服务器程序需要有个容器才能跑起来, 一般用 apach, window.showView.Server, 在 debug 栏有 Server 窗口, 右键.new.Server.apache.tomcat.选择tomcat 文件夹容器
> 完成后用 debug 运行, 可以在 consol 中看到
> 服务器跑起来后, debug 运行还是显示不出来的, 先停掉, 在项目顶文件夹右击.debug as...选中要运行在的服务器, 勾选总是使用这个服务器, 完成
服务器要运行, 接着服务器程序要运行在上面, 所以有两次运行, 保证在服务器上运行
* 通过服务器中文件地址(url)来获得服务器中的资源文件
* 通过服务器告诉我们帐号密码正确与否 --- 通过返回的 data
* 本机的服务器地址: 127.0.0.1 | 路由分配的 ip | localhost | + 端口号
* 资源位置: 服务器地址 + 资源目录位置
* 通过服务器的各种接口想服务器发送请求, 获取资源. 或者是做什么事
* ping 本机是看自己的网卡有没有问题 : ping 127.0.0.1
* ping 路由: ping 192.168.x.x
* 真机调试时, 用路由分配的地址, 且是局域网内
http:
是种网络传输协议, 在不同客户端, 主机, 客户端和服务器之间, 是通过网络连接, 之间的通信不能鸡同鸭讲, 需要遵守协议, 来完成信息的交流和简析
有很多种网络协议: http: 超文本传输协议, 可以传输任何数据类型, 协议简单, 快速
ftp: 共享文件协议<只能访问文件>
file:// 访问本地资源
... 只要遵守的协议, 就可以解析传输过来的数据, 进行通信
协议内容
请求:
请求行: 请求方法, 请求资源路径, http协议版本
GET /.../.../....jpg http1.1
请求头: 服务器主机地址, 客户端的环境信息, 接收的配置
请求体: 客户端需要发给服务器的具体数据
相应: 一个http 相应中应该包含以下信息
状态行: 协议版本, 状态码, 状态英文名称: http1.1 200 OK
相应头: 服务器的描述, 返回数据的描述
实体内容: 返回给客户端的具体数据
利用 iOS 封装的方法发送请求
一般公司里才用第三方框架, 加快开发进度
ASI | AFNetwork
自带: NSConection, NSURLRequest(默认都是 get 请求)
get 请求的话在 iOS 中的 NSURLRequest 都不用写请求头和请求体, 直接传入 URL 就好了
可以在服务器代码中打断点, 模仿请求延迟,
在子线程中请求数据, 回到主线程来处理返回的相应数据, 并进行蒙版提示操作, 蒙版的操作一定要放到主线程中执行,
利用方法[NSURLRequest sendAsync...]向服务器发送请求, 这个方法会把 block 奋发到 queue 中执行, 所以 queue 应该传入主队列 NSOperationQueue mainQueue]
默认是异步执行, 同步方法 sendSync 不推荐使用
客户端的检测操作, 保证输入框中有值, 没有就直接返回, 并提示输入
接收服务器端的数据, 一般网络通信用的多的格式是 json | xml, 有几种解析 json 的方法:
* 第三方框架 JSONKit > SBJson > ... (新能排序)
* NSJSONSeries (性能最好) JSONObjectWithData:/// | DataWithJSON...
获取输入框的数据, 传给服务器的url 占时是拼接输入框的写死 URL
将获取到的数据解析后, 按照规范会有"error":"""" | "success":"""", 取出这些数据判断并展示
#GET 请求
三个方法发送 GET 请求
* 同步发送请求: sendSync...
* 异步发送: sendAsync...
* 上面两个是类方法直接发送, 这个是创建对象, start, 设置代理, 通过代理来做一些事情
设置请求超时: 请求响应的情况依据网络环境的不同而不同, 要考虑到极端的情况, 在服务器代码中设置断点模拟超时, 超时返回重试的提示
#POST 请求:
请求的 URL 中只有路径, 没有拼接用户名和密码, 用户名和密码是放到请求体中发送过去
在 iOS 中请求行和请求体一般不用我们发, 这里 POST 要发请求体
如果发送的请求中有中文, 还要对中文进行转码, 在拼接成字符串时, 用stringByAdding...Encoding:UTF8String...];
小结:
http 请求的过程 及 方法
GET: 请求行中包含资源连接, 用户数据, 参数有限制
POST: 请求体中包含用户数据, 参数无限制
客户端 ---发送请求---> 服务器
信息包括:请求行: 请求方式, http 协议版本, 资源链接
请求头: 客户端的一些数据
请求体: 客户端发送过去的实体数据, 二进制
客户端 <--接收响应--- 服务器
状态行(叫法而已, 相应行也行): 状态码, 状态英文, 协议版本
相应头: 服务器信息, 返回数据的一些信息: 类型, 长度
实体内容(响应体): 返回的具体数据
发送请求的方法,
NSURLConnection
同步,
异步
直接发送
代理方法: 代理方法其实都一样, 除非指定Immediatly = NO, 不然创建好对象就会直接发送请求,
数据加密
直接传送的到服务器的连接, 如果用 http 直接传的话, 连接和其请求头请求体都是明文传输的,
起码在密码账户方面, 最好不要明文
不应该用 GET 请求传送密码帐号,
POST 中是将密码帐号放到请求体中的, 单是如果被抓包的话数据也会暴露
应该对传输的用户数据进行加密
一般用非商业性的加密, 很强大, MD5[现在已经不在安全, www.cmd5.com 存储了很多 md5字典, 可以通过 md5值找出对应的密码],
利用算 md5的分类来计算 md5或者其他算法对数据进行加密, 再传输, 而服务器端就不能再检验明文, 而是也应该是对应的值
所以服务器一开始存储的就是暗纹, 在用户注册的时候, 发过去的信息就是加密的, 存储也是加密的
结论: 用户的隐式数据, 只有在输入的时候是明文, 进行处理还是传输什么的都是暗纹操作
可以在算出加密暗纹后, 对暗纹进行处理在传输, 那么解密出来的东西就不是原来的明文, 除非知道处理方法, 数据没有绝对的安全, 只能操着就算数据库被破解, 也不能从数据来算出明文
[但是...然并卵...数据库都被破解了,,,,里面存储的东西也都暴露了...有没有明文密码有什么重要的....]
XML 解析
与 JSON 同为数据交互的数据格式, 组成部分
* 文档声明: <?xml version = "1.0" encoding = "UTF-8">, 声明文档版本, 编码类型
* 元素(Element) <标签></标签>, 标签一般承兑出现, 有内容的: <标签>内容</标签>, 无内容的<标签></标签> = <标签[这里可以添加属性]/>
* 属性(Attribute)
规范:
* 必须要有文档声明
* 最多只有一个根元素, 其他的都是其子元素
语法:
* 标签成对出现 <></>, 无内容的还可以这样<标签/>
* 一个元素可以嵌套若干个子元素, 不能交叉嵌套
* xml 中的所有空格和换行, 都会当做具体内容来处理
* 一个元素可以拥有多个属性, 属性值必须有引号(单双皆可)
* 属性的信息也可以用子元素来表示
xml 和 JSON 比, JSON 的比较小, 因其不用写标签名, 体积会更小, 所以公司中数据交互一般哟给你 Json, 节省带宽
解析 xml:
一般有两种方法:
* dom: 一次性将 xml 数据加载进内存再解析, 可以获取里面所有任意的节点, 对小 xml 文档比较适用
* sax: 分步解析, 一条条解析下来, 不能回退, 对大 XML 文档比较适用
工具:
* NSXMLParser: SAX 模式, 系统自带
* libxml2: 第三方, 但是开源, iOS 中继承在框架里了, 纯 C, 性能好, 但是数据类型复杂, dom 和 sax 模式都有
* GDataXML : 第三方, google 做的, 基于 libxml, DOM 模式
一般用第一第三种方法
SAX:
NSXMLParser:
创建解析器, 传入数据, 设置代理, 因其是事件驱动型, 所以没有特定事件都会调用代理的方法
扫到文档头开始会调用, 扫到元素会调用, 元素结尾会调用, 文档结束会调用
可以把请求数据的方法和处理数据的方法封装到一个工具类中, 减小控制器压力
DOM:
GDataXML:
用到了 libxml2的库, 项目本身没有默认导入头文件, 但是在 iOSSDK 中已经集成有: 按照最上面注释的提示, 在导入框架后, 因为是动态库, 所以里面没哟头文件,
要自己在提示中的 HeaderPathSearch 中添加这个的路径,
在OtherLinker,,,中加上-lxml2
因为 CDataXML 是以前做的框架, 没有 ARC 特性, 还要在 BuildPhase 中设置这个框架为-fno-objx-arc
里面的类:
GDataXMLDocument : 代表整个 xml 文档
GDataXMLElement : 代表里面的元素
用 attributeForName来获得元素中的属性节点, 再取出其中的值
1. 先从 data 中加载出整个 xml 文档,
2. 取出 root 元素
3. 取出 root 元素中某个标签的所有子元素数组
4. 遍历元素数组 -> 元素转模型[取出属性节点->转换为值->赋值到模型的对应属性上]
5. 将转换好的模型加到数组中,
6. 返回这个数组, 控制器拿到数组后刷新 tableView
文件下载
文件下载有很多小细节在里面, 如果文件一大, 就要优化处理,
小文件下载可以使用 nsdata datawithContentOfURL:], 或者 NSURLConnection 来弄,
大文件下载
大文件下载需要实时监控下载进度, 所以需要代理来弄, 用 NSURLConnection 创建对象, 设置代理, 接收数据,
注意: 直接在内存中拼接数据, 连接结束时再写到 rom 中, 会使得数据留在内存中, 文件多大就占用多大内存, 在手机上会崩的...,
应该边接收数据边写到 rom 中,
大文件不要放到 Document 中, 会和 profile 一起被同步到 iCloud 上
将传回的数据立即写到 ROM 中, 不要占用内存
1. 发送请求, 如果错误就返回报告
2. 当接收到响应时, 用 fileManager 创建一个空文件, 在创建一个句柄即控制把手, 来对这个文件操作
3. 接收到数据时, 通过句柄将 data 写入到文件的最后,
4. 资源加载完毕时, 关闭句柄, 并移除
暂停, 恢复, 进度条
1. 设置属性在接收到响应时记录文件应该的大小(即总大小), 在接收 data记录累加当前下载的大小, 相除得进度, 赋值进度条
2. 按钮暂停后取消连接, connection 对象起作用. 并将对象 = nil. 因为 cancel 后就不能继续, 应该释放
3. 重新继续时, 重新创建链接, 并在请求头中设置属性 Rang, 告诉服务器从当下下载的大小开始发送数据.
封装,
将下载操作封装到类中, 每下载一个资源就创建一个下载器下载, 控制器不用关心过程,
传入控制器必要知道需要告诉下载器的参数
下载器通过 block 属性, 将需要传递给控制器的数据通过 block 参数传递, 当 block 过程可以由控制器设置来做什么事
压缩
如果图片多的话, 一般服务器是压缩发送, 在客户端再自行解压使用, 指定哪个 zip 解压到哪
用 ssZip...可以, 记得导入 libz 框架 , 将指定文佳家压缩到哪, 或者路径数组压缩到哪,
多线程断点下载
一样的道理, 只是将下载的文件分成几个部分来下载, 每个本分用一个线程下载, 每个线程用 donloader 管理, 所有线程管理的 downloader 放到 multidownload 来管理,
面向控制器只用一个 multidownload 就行,
multidownload 开开启和停止所有的下载,
线程的具体下载放到 singleDownLoad 弄,
都有的属性可以抽取到父类中
注意: 拼接 Data 时, 是在之前断点的地方, 所以在写入 data 之前不要累加 data 长度, 在写入 data 后在累加 data的长度, 以待之后定位写入
文件上传
等下的上传同 POST 的 Http 协议的用法不用掌握, 等到使用第三方框架的时候才需要掌握他们的用法
在 上传文件的操作中, 一定要设置请求头, 描述上传文件大小, 文件类型, 表明要上传文件, 以及参数分割线: boundary=--------------2892198随机数2199819
在请求体中 , 先用分割线来标示一个参数传递, 所以分割线就代表了一个参数传递,
分割线下面跟着参数的描述, 然后换行, 再换行空一行再接着参数
再传递参数的话就要先分割线, 再传参数,
(分割线可以是任意字符串, 但是绝对不能有中文和空格)
POST 发送文件,
connection Request, -> 设置 请求头, 内容描述, 文件类型, 然后是文件实体
按照 http POST 上传文件所要求的格式, 将变动的地方转为参数, 将这一大堆东西封装起来使用, 提高代码的重用绿
注意: 分割线的设置不要带-- , -- 在使用分割线的时候再拼接上去, 以标识参数开始或结束
请求缓存
有些资源相对比较固定的, 我们会将返回的相应和 data 缓存起来, 下次用的时候就不用去服务器发送请求, 直接拿缓存的用
一个 request 对应一个 NSCacheURLResponse, 可以通过 NSCach 对象获得这个 request 的缓存, 还能通过 standare...拿到缓存管理, 删除某个缓存或者全部缓存
可以对 request 设置缓存策略, 来决定怎么使用缓存
网络状态
网络应用需要在某些时候知道当前手机的网络状态, 好对应用的使用做出使用策略,
check 网络状态 :
/** 看看是否联网 */
if ([Reachability reachabilityForLocalWiFi]) {
NSLog(@"可以连接 wifi");
}else if ([Reachability reachabilityForInternetConnection])
{
NSLog(@"可以连接流量");
}else
{
NSLog(@"不可以联网");
}
不仅这样, 还要在状态改变时能做到监听, : 注册消息通知, 当网络状态改变的时候, reachability 会发出通知, 接收到通知时就用上面的方法判断是真没状态, 再做相应的操作
ASI
使用第三方框架可以更加高效的开发应用, 缩短开发流程
ASI的使用和自带的 NSURLRequest 差不多, 但是封装了很多好用的简单的方法
值得说的是: 异步请求中, 如果直接获取 respones 是没有东西的, 因为在异步, 数据没返回,
设置代理的话, 不要重新实现代理方法, 这是内部自己调用的, 重写的话就会认为是你想要自己处理 data, response 等数据, ASI 将不会去处理, 最后传入的 request 里面也是没有 data 的
要想在完成后获得异步处理的 data, 需要设置代理, 并且在 request 对象设置 didFinishSelector属性, 传入一个方法, ASI 将在请求完成后调用代理的这个方法, 传入数据
POST:
使用 ASIFormDataRequest * 专门用来发送 POST 请求, setPostValueForKey就可以给 POST 的 Body 中添加参数 , 添加多值参数可以用 add
文件下载:
因为封装了起来,所以文件下载我门不用关心太多, 类似我们封装的NSURLRequest 一样, 只用告诉上传什么文件, 服务器地址, 对应文件名, 类型即可
它封装了很多东西, 只暴露出简单的接口 , 我们只用简单对 request 设置, 就能达到很多目的
断点下载: allow... 除了设置允许回复外, 还要设置一个临时存储文件夹, 回复时会去这个文件夹拿到之前的数据
request.temporaryFileDownloadPath = [path stringByAppendingPathComponent:@"vid.zip.download"];
多线程下载:
直接设置代理拿到下载进度: (可以直接将进度条设置为代理, 因其内部有 setProgress:方法, 正好)
可以那网上封装好的控件, 呵护规范的话, 很容易拿过来用
文件上传
使用也很简单, 使用 ASIFormData... 之前的文件上传失败: 服务器中文件保存文件夹路径最后没有/, 它文件名是拼接前面的保存的, 没有/就会保存到上一级, 命名也会拼接最后一个文件夹
设置上传的文件: 从沙盒中或者项目中的文件上传, : 需要知道上传文件的具体路径, setFile:forKey:
从内存中上传二进制文件(如上传相册或者相机图片): setData:forKey:
用 UIImageWriteToSavedPhotosAlbum(image,nil, nil) 可以将图片写入相册
拿到UIImagePickerController, 设置来源, 可以调出相册或相机, 设置代理, 可以将选好图片传到代理方法(设置代理后熬自己 dismiss 控制器)
设置其他的参数: 和普通的请求一样, setPostValue:forKey
直接上传大文件:
和上传文件的设置几乎一样
ASIHttpRequest : NSOperation, 意味着可以将其加到队列中,
这样就能用 Operation 的特征操作 Request,
通过队列对整个的草走, 挂起停止等等,
设置依赖
线程控制,
多线程控制
还能通过 ASI 来判断是否正在处理网络请求
设置是否显示联网状态 , setShouldUpdateNetworkActivityIndicator:
是否后台后继续处理网络请求: ShouldContinueWhenAPPEnterBackground
设置重试次数: numberOfTimesToRetryOnTimeout
wiarning 之后会学到静态库的方式, 包装项目中都是非 ARC, 不用一个个项目去设置-fno-objc-arc
ASI 的缓存机制
获得 download 缓存对象, 设置默认策略, 在将这个对象赋值给请求的策略
AFNetworking
简单, 基于 NSURLConnection 封装了很多简便的东西给我们用,
GET 请求:
获得一个 HttpOperationManager, 直接 GET...就可以, 需要参数的可以拼接参数, 不需要的传 nil 就行,
HTTP 协议总结:
http: 超文本传输协议, 定制网络端点之间tong通信的一种规范, 只有按照一定的规范来, 信息才能交流 , 不至于鸡同鸭讲
请求: 客户端向服务器发送请求:
* 请求行: 请求的资源路径地址
* 请求头: 客户端的信息, 接收什么类型的参数, 系统信息,
* 请求体: (一般 POST 请求才有, 携带一些文件或者其他的参数信息)
响应: 服务器对客户端的响应, 回传一些信息
* 状态行: 对这个请求做出的响应状态, 成功还是失败, 使用 的协议版本, 状态码, 状态英文
* 响应头: 服务器的信息, 返回数据的类型, 长度等信息
* 实体内容: 返回客户端的实体内容
发送请求的方法:
* NSURLConnection: 同步请求, 异步请求(代理/block)
UIWebView
功能强大, 可以打开多种格式的文件
想要在 OC 中动态改变网页的内容, 需要 JavaScript.
关键点, 在 OC 中调用JS: webView stringbyJavaScript...
在网页的 JS 中调用 OC. 搭建桥梁, 当 webVIew 要加载某个 URL 时, 会调用 webVIew 代理的一个方法, 并传入这个 URL, 这时, 在 JavaScript 里调用打开一个 URL, 这个 URL 就会传到代理方法中, 可以截取里面的关键字, 然后取剩下的, 将信息提取出来封装成 SEL 消息,再调用这个消息就好, 之前实现这个消息, 完成某个功能
监控网络状况
为了更好的应用交互, 在不能联网的时候要做提醒, 不能让用户认为是软件的问题, 使用 AFN 来监听网络状态
AFNetworkReacherbilitymanager 可以将监控网络状态的代码抽取出来....反正也不依赖什么东西...
封装网络请求:
当前写的代码中有很多地方用到了 AFN, 这样存在风险: 当 AFN 停止维护之后, 依赖的项目就没有更多的保障了,
所以应该将业务的逻辑封装起来, 里面实现的技术细节封装, 项目中不需要知道实现的技术细节, 以后更换实现的技术就可以, 而且也更方便维护
技术的更新迭代迅速, 不应该让应用项目强依赖某个技术, 应该设置一个管理类来实现具体使用的技术细节,这样收外界影响的因素就只有自己的类
通过传递 block 形参, 在方法调用完成网络请求后调用这个 block, 并传递一些参数. 这些参数要先判断有没有值, 有值才调用, 不然报错
不要直接将自己方法中传入的 block 传给具体实现框架, 自己用的 block 可能参数的数量类型不一样, 应该在实现技术的调用 block 中调用自己传入的 block
关于发送图片的封装: 参数里面有 formdata 的东西, 还需要研究一下