-
Notifications
You must be signed in to change notification settings - Fork 0
/
YashiNetworkKit3.swift
executable file
·281 lines (266 loc) · 15.8 KB
/
YashiNetworkKit3.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
//
// YashiNetworkKit.swift
// 雅诗独立类库:网络下载工具 v3.0 Swift中文版 (Xcode7.1/Swift2) | 开发版
// 1.0 Created by 神楽坂雅詩 on 2012/8/8.
// 2.0 Created by 神楽坂雅詩 on 2015/4/19.
// 3.0 Created by 神楽坂雅詩 on 2015/9/24.
// Copyright (c) 2012-2015 KagurazakaYashi/TerenceChen . All rights reserved.
//
// 依赖:无需其他类库
// 输入:使用修改属性输入
// 输出:代理方法
//
//import Cocoa
import UIKit
enum 会话模式为:Int16 {
case 默认 = 0
//默认会话模式(default):工作模式类似于原来的NSURLConnection,使用的是基于磁盘缓存的持久化策略,使用用户keychain中保存的证书进行认证授权。
case 瞬时 = 1
//瞬时会话模式(ephemeral):该模式不使用磁盘保存任何数据。所有和会话相关的caches,证书,cookies等都被保存在RAM中,因此当程序使会话无效,这些缓存的数据就会被自动清空。
case 后台 = 2
//后台会话模式(background):该模式在后台完成上传和下载,在创建Configuration对象的时候需要提供一个NSString类型的ID用于标识完成工作的后台会话。
}
enum 传输模式为:Int16 {
case 加载数据 = 0
case 上载文件 = 1
case 下载文件 = 2 //异步
case 断点续传下载文件 = 3
case 后台下载文件 = 4 //程序级异步
}
enum 请求模式为:Int16 {
case 显式 = 0
//GET - 从指定的资源请求数据。
case 隐式 = 1
//POST - 向指定的资源提交要被处理的数据。
}
protocol YashiNetworkKitDelegate {
func YashiNetworkKit实时汇报进度(_ 已下载字节数:Int64, 总计字节数:Int64, 当前进度百分比:Int64)
func YashiNetworkKit下载结束(_ 当前下载类:YashiNetworkKit)
func YashiNetworkKit网络操作结束(_ 当前下载类:YashiNetworkKit, 发生错误:NSError?)
func YashiNetworkKit请求结果(_ 当前下载类:YashiNetworkKit, 返回的网址:URL?, 返回的数据:Data?, 返回的文件:String?, 返回的状态码:URLResponse?, 错误信息:NSError?)
//func YashiNetworkKit开始断点续传(已下载字节数:Int64, 总计字节数:Int64);
}
class YashiNetworkKit: NSObject,URLSessionDownloadDelegate,URLSessionDataDelegate {
//可以修改的属性
var 会话模式:会话模式为 = 会话模式为.默认
var 请求模式:请求模式为 = 请求模式为.显式
var 传输模式:传输模式为 = 传输模式为.加载数据
var 网址:AnyObject? = nil //支持 NSURL, NSString, String
var 数据:Data? = nil //上传操作前输入,下载操作时输出
var 下载到文件:String? = nil //下载到本地文件的绝对路径,不填写则下载到临时文件
var 缓存策略:NSURLRequest.CachePolicy = NSURLRequest.CachePolicy.useProtocolCachePolicy
var 超时时间:TimeInterval = 60
var 要提交的参数:NSDictionary? //.php?key=value&key=value
//外部只读的属性
var 网络会话:Foundation.URLSession? = nil
var 网络会话任务加载数据:URLSessionDataTask? = nil
var 网络会话任务上载数据:URLSessionUploadTask? = nil
var 网络会话任务下载数据:URLSessionDownloadTask? = nil
var 续传数据:Data? = nil
var 代理:YashiNetworkKitDelegate? = nil
var 临时文件:String? = nil
var 错误:NSError? = nil
var 下载文件总大小:Int64 = 0
var 下载文件完成大小:Int64 = 0
var 下载文件完成百分比:Int64 = 0
//方法
func 开始请求() {
//菊花.startAnimating()
var 网址串:URL = URL(string: "")!
if ((网址 as? URL) != nil) {
网址串 = 网址 as! URL
} else if ((网址 as? NSString) != nil) {
网址串 = URL(string: 网址 as! String)!
} else if ((网址 as? String) != nil) {
网址串 = URL(string: 网址 as! String)!
}
let 网络请求:NSMutableURLRequest = NSMutableURLRequest(url: 网址串, cachePolicy: 缓存策略, timeoutInterval: 超时时间)
if (要提交的参数 != nil) {
let 要提交的字符串:String = 参数字典转换为字符串(要提交的参数!)
网络请求.httpBody = 要提交的字符串.data(using: String.Encoding.utf8)
}
if (请求模式 == 请求模式为.显式) {
网络请求.httpMethod = "GET";
} else {
网络请求.httpMethod = "POST";
}
if (传输模式 == 传输模式为.加载数据) {
创建网络会话()
网络会话任务加载数据 = 网络会话!.dataTask(with: 网络请求 as URLRequest, completionHandler: { (返回的数据:Data?, 返回的状态码:URLResponse?, 错误信息:NSError?) -> Void in
self.请求结果(nil, 返回的数据: 返回的数据, 返回的文件: nil, 返回的状态码: 返回的状态码, 错误信息: 错误信息)
} as! (Data?, URLResponse?, Error?) -> Void)
网络会话任务加载数据!.resume() //启动
}
else if (传输模式 == 传输模式为.上载文件) {
创建网络会话()
if (数据 == nil) {
NSLog("[YashiNetworkKit]错误:没有要上传的数据。")
}
网络会话任务上载数据 = 网络会话!.uploadTask(with: 网络请求 as URLRequest, from: 数据, completionHandler: { (返回的数据:Data?, 返回的状态码:URLResponse?, 错误信息:NSError?) -> Void in
self.请求结果(nil, 返回的数据: 返回的数据, 返回的文件: nil, 返回的状态码: 返回的状态码, 错误信息: 错误信息)
} as! (Data?, URLResponse?, Error?) -> Void)
//网络会话任务上载数据 = 网络会话!.uploadTaskWithRequest(网络请求, fromData: 数据!)
网络会话任务上载数据!.resume() //启动
}
else if (传输模式 == 传输模式为.下载文件) {
if (网络会话任务下载数据 != nil) {
网络会话任务下载数据 = nil
}
if (网络会话 != nil) {
网络会话 = nil
}
创建网络会话()
网络会话任务下载数据 = 网络会话!.downloadTask(with: 网络请求 as URLRequest, completionHandler: { (返回的网址:URL?, 返回的状态码:URLResponse?, 错误信息:Error?) -> Void in
self.将下载的临时文件移动到目标(返回的网址, 返回的状态码: 返回的状态码, 错误信息: 错误信息)
})
网络会话任务下载数据!.resume()
}
else if (传输模式 == 传输模式为.断点续传下载文件) {
if (网络会话任务下载数据 != nil) {
网络会话任务下载数据 = nil
}
if (网络会话 == nil) {
创建网络会话()
}
if (数据 != nil) { //继续下载
网络会话任务下载数据 = 网络会话!.downloadTask(withResumeData: 数据!, completionHandler: { (返回的网址:URL?, 返回的状态码:URLResponse?, 错误信息:NSError?) -> Void in
self.将下载的临时文件移动到目标(返回的网址, 返回的状态码: 返回的状态码, 错误信息: 错误信息)
} as! (URL?, URLResponse?, Error?) -> Void )
} else { //新建下载
网络会话任务下载数据 = 网络会话!.downloadTask(with: 网络请求 as URLRequest, completionHandler: { (返回的网址:URL?, 返回的状态码:URLResponse?, 错误信息:NSError?) -> Void in
self.将下载的临时文件移动到目标(返回的网址, 返回的状态码: 返回的状态码, 错误信息: 错误信息)
} as! (URL?, URLResponse?, Error?) -> Void)
}
网络会话任务下载数据!.resume()
}
else if (传输模式 == 传输模式为.后台下载文件) {
网络会话任务下载数据 = 网络会话!.downloadTask(with: 网络请求 as URLRequest, completionHandler: { (返回的网址:URL?, 返回的状态码:URLResponse?, 错误信息:NSError?) -> Void in
self.将下载的临时文件移动到目标(返回的网址, 返回的状态码: 返回的状态码, 错误信息: 错误信息)
} as! (URL?, URLResponse?, Error?) -> Void)
网络会话任务下载数据!.resume()
}
}
func 将下载的临时文件移动到目标(_ 返回的网址:URL?, 返回的状态码:URLResponse?, 错误信息:Error?) {
let 文件管理器:Foundation.FileManager = Foundation.FileManager.default
let 临时文件URL:URL = 返回的网址!
let 下载到:String? = self.下载到文件
if (返回的网址 == nil || 错误信息 != nil) {
NSLog("[YashiNetworkKit]下载返回了错误。")
self.请求结果(返回的网址, 返回的数据: nil, 返回的文件: nil, 返回的状态码: 返回的状态码, 错误信息: 错误信息 as NSError?)
return
}
self.临时文件 = 临时文件URL.absoluteString
if (下载到 != nil) {
if (文件管理器.fileExists(atPath: 下载到!)) {
do {
try 文件管理器.removeItem(atPath: 下载到!)
} catch let 捕获的错误 as NSError {
NSLog("[YashiNetworkKit]删除已存在的目标文件失败。")
self.请求结果(返回的网址, 返回的数据: nil, 返回的文件: 下载到, 返回的状态码: 返回的状态码, 错误信息: 捕获的错误)
return
}
}
do {
try 文件管理器.moveItem(atPath: self.临时文件!, toPath: 下载到!)
self.请求结果(返回的网址, 返回的数据: nil, 返回的文件: 下载到!, 返回的状态码: 返回的状态码, 错误信息: 错误信息 as NSError?)
} catch let 捕获的错误 as NSError {
NSLog("[YashiNetworkKit]将临时文件夹中的文件%@移动到%@失败。",临时文件URL.absoluteString,下载到!)
self.请求结果(返回的网址, 返回的数据: nil, 返回的文件: 下载到!, 返回的状态码: 返回的状态码, 错误信息: 捕获的错误)
}
} else {
self.请求结果(返回的网址, 返回的数据: nil, 返回的文件: self.临时文件, 返回的状态码: 返回的状态码, 错误信息: 错误信息 as NSError?)
}
}
func 参数字典转换为字符串(_ 提交的参数:NSDictionary) -> String {
if (提交的参数.count <= 0) {
return ""
}
let 参数字符串:NSMutableString = NSMutableString()
let 所有的键:NSArray = (提交的参数.allKeys as NSArray)
for 当前第几个键 in 0 ..< 所有的键.count {
let 当前键:NSString = 所有的键.object(at: 当前第几个键) as! NSString
let 当前值:NSString = (提交的参数.object(forKey: 当前键))! as! NSString
let 要添加的字符串:NSString = NSString(format: "%@=%@&", 当前键,当前值)
参数字符串.append(要添加的字符串 as String)
}
return 参数字符串.substring(to: 参数字符串.length-1)
}
func 创建网络会话() {
let 会话配置:URLSessionConfiguration = URLSessionConfiguration.default
//会话配置.HTTPAdditionalHeaders = ["key":"val"] //HTTP头
网络会话 = Foundation.URLSession(configuration: 会话配置, delegate: self, delegateQueue: nil)
网络会话!.sessionDescription = "Current Session"
}
func 中止请求() {
if (网络会话任务加载数据 != nil) {
网络会话任务加载数据!.cancel()
网络会话任务加载数据 = nil
}
if (网络会话任务上载数据 != nil) {
网络会话任务上载数据!.cancel()
网络会话任务上载数据 = nil
}
if (网络会话任务下载数据 != nil) {
if (传输模式 == 传输模式为.断点续传下载文件) {
网络会话任务下载数据?.cancel(byProducingResumeData: { (断点数据) -> Void in
self.续传数据 = 断点数据
self.网络会话任务下载数据 = nil
})
} else {
网络会话任务下载数据!.cancel()
网络会话任务下载数据 = nil
}
}
}
//发送下载任务时已完成下载。代表应复制或移动该文件在给定位置到一个新的位置,因为它将删除委托消息返回时。
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
print("[YashiNetworkKit]下载:%@", location)
if (代理 != nil) {
代理?.YashiNetworkKit下载结束(self)
}
}
//定期发送通知的代表下载进度。
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
下载文件总大小 = totalBytesExpectedToWrite
下载文件完成大小 = totalBytesWritten
下载文件完成百分比 = (Int64(下载文件完成大小) / Int64(下载文件总大小))*100
NSLog("[YashiNetworkKit]已下载%d/%d(%f%%)...", 下载文件完成大小,下载文件总大小,下载文件完成百分比)
if (代理 != nil) {
代理?.YashiNetworkKit实时汇报进度(下载文件完成大小, 总计字节数: 下载文件总大小, 当前进度百分比: 下载文件完成百分比)
}
}
//发送时已恢复下载。如果下载失败错误,错误的用户信息的字典包含一个nsurlsessiondownloadtaskresumedata关键,其价值是简历数据。
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64) {
NSLog("[YashiNetworkKit]开始从%lld/%lld字节续传...", fileOffset,expectedTotalBytes)
// if (代理 != nil) {
// 代理?.YashiNetworkKit开始断点续传(fileOffset, 总计字节数: expectedTotalBytes)
// }
}
//无论成败都调用
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
if (error != nil) {
NSLog("[YashiNetworkKit]网络操作失败,%@",error!.localizedDescription)
} else {
NSLog("[YashiNetworkKit]网络操作成功");
}
if (代理 != nil) {
代理?.YashiNetworkKit网络操作结束(self, 发生错误: error as NSError?)
}
}
func 请求结果(_ 返回的网址:URL?, 返回的数据:Data?, 返回的文件:String?, 返回的状态码:URLResponse?, 错误信息:NSError?) {
if (返回的状态码 != nil) {
let 状态对象:HTTPURLResponse = 返回的状态码! as! HTTPURLResponse
let 状态码:Int = 状态对象.statusCode
NSLog("[YashiNetworkKit]返回状态(%d):", 状态码, HTTPURLResponse.localizedString(forStatusCode: 状态码))
}
// if (返回的数据 != nil) {
// //let b:UIWebView = UIWebView()
// //b.loadData(返回的数据!, MIMEType: "text/html", textEncodingName: "utf-8", baseURL: NSURL())
// }
// if (返回的文件 != nil) {
//
// }
self.代理?.YashiNetworkKit请求结果(self, 返回的网址:返回的网址, 返回的数据: 返回的数据, 返回的文件: 返回的文件, 返回的状态码: 返回的状态码, 错误信息: 错误信息)
//返回后应判断是否有错误
}
}