网络规范开发简单练习-swift-NSURLConnection
虽然NSURLConnection已经很少使用,可是并不能说明它不重要,对于一个初学者来说,要想学好网络,必须从最基础的地方入手,基础牢了,在以后的学习中才能事半功倍。根基不稳,再怎么小心翼翼也抵达不到云层。
所用接口
//限免
"http://iappfree.candou.com:8080/free/applications/limited?currency=rmb&page=1”
//降价
"http://iappfree.candou.com:8080/free/applications/sales?currency=rmb&page=1”
//免费
"http://iappfree.candou.com:8080/free/applications/free?currency=rmb&page=1”
www.bejson.com 解析
效果
<img src="/Users/qianfeng/Desktop/屏幕快照 2016-08-25 下午6.37.00.png" width = "120" height = "200" />
<img src="/Users/qianfeng/Desktop/屏幕快照 2016-08-25 下午6.37.10.png" width = "120" height = "200" />
<img src="/Users/qianfeng/Desktop/屏幕快照 2016-08-25 下午6.37.20.png " width = "120" height = "200" />
删除Mainboard,ViewController,Info.plist中的Main函数入口,导入第三方库MJRefresh(下拉刷新),SDWebImage并设置桥接。
- 右键项目->NewFile->ios(Source)->Header File->Save As:(输入文件名字,例如:bridgingHeader)->Create
- 打开bridgingHeader.h导入第三方库
(#import "UIImageView+WebCache.h"
(#import "MJRefresh.h" - 桥接 ->点一下项目名->点一下左边PROJECT下的文件名 ->Build Settings ->选择All ->输入bridge搜索->Objectives-C Bridging Header->双击右侧空白区域输入->文件夹的名字/bridgingHeader.h
桥接文件时,如果.h文件建在根项目下,直接输入文件名字即可,如果在文件夹内,则需要加入文件夹的名字,在这里我们把桥接文件建立在了文件夹内
1.新建一个MytabBarController继承自UITabBarController
2.打开AppDelegate.swift文件,修改里面的第一个函数application
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
window = UIWindow.init(frame: UIScreen.mainScreen().bounds)
window?.rootViewController = MyTabBarController()
window?.backgroundColor = UIColor.whiteColor()
window?.makeKeyAndVisible()
return true
}
3.
- 新建一个BaseViewController作为所有控制器的基类,用来统一修改界面风格,现在只插入一行代码作为示范
self.view.backgroundColor = UIColor.grayColor()
* 新建ListViewController继承自BaseViewController
* 新建LimitViewController,FreeViewController,SaleViewController分别继承自ListViewController
###4.新建一个TabBar.plist文件,用来存放MyTabBarController里的控制器内容,在文章底部自行下载源代码进行查看tabBar.plist文件,此处不再上图
###5.打开MytabBarController文件进行编辑
override func viewDidLoad() {
super.viewDidLoad()
//工程名
let proName = NSBundle.mainBundle().infoDictionary!["CFBundleExecutable"] as! String
//拿到plist文件路径
let path = NSBundle.mainBundle().pathForResource("TabBar.plist", ofType: nil)!
//将plist文件数据读到数组里
let plistArr = NSArray.init(contentsOfFile: path) as! [[String : String]]
for dic in plistArr {
//拿到代表类名的字符串
let name = proName + "." + dic["name"]!
// self Type dynamicType
//将字符串转成类
let vcClass = NSClassFromString(name) as! UIViewController.Type
//构造页面对象
let vc = vcClass.init()
//导航
let nc = UINavigationController.init(rootViewController: vc)
vc.navigationItem.title = dic["title"]
//显示在tabBar上的专用按钮
nc.tabBarItem = UITabBarItem.init(title: dic["title"], image: UIImage.init(named: dic["icon"]!), tag: 0)
//将页面/导航添加到tabBarController里面
self.addChildViewController(nc)
}
}
##注意:以上只是用纯代码规范化搭建了一个tabController的界面,仅作参考,读者也可以自行拖控件搭建
###6.新建AppModel继承自NSObject用来存放数据模型
class AppModel: NSObject {
var applicationId: String?
var iconUrl: String?
var name: String?
var starCurrent: String?
var lastPrice: String?
var categoryName: String?
var favorites: String?
var shares: String?
var downloads: String?
var expireDatetime: String?
var currentPrice: String?
static func modelWith(dic: [String: AnyObject]) -> AppModel {
let model = AppModel()
model.setValuesForKeysWithDictionary(dic)
return model
}
//如果输入了未定义的属性,则调用该方法
override func setValue(value: AnyObject?, forUndefinedKey key: String) {
print("您输入了未定义属性的Key:\(key)")
}
}
###7.新建AppCell继承自UITableViewCell并勾选xib文件,界面自行搭建,此处不再演示,cell重用标识符"qqq",需要注意的是降价页面又一个黑色的线,可以用view,背景设置为黑色(但在cell点击时,cell内的所有控件的背景色都将失去效果)
![](/Users/qianfeng/Desktop/屏幕快照 2016-08-24 下午7.50.16.png)
###8.编辑ListViewContoller文件,ListViewController放了所有控制器界面的相同部分(请先编写第9步)
class ListViewController: BaseViewController {
let limit_url = "http://iappfree.candou.com:8080/free/applications/limited?currency=rmb&page=%d"
let sale_url = "http://iappfree.candou.com:8080/free/applications/sales?currency=rmb&page=%d"
let free_url = "http://iappfree.candou.com:8080/free/applications/free?currency=rmb&page=%d"
let tableView = UITableView()
var dataArr = [AppModel]()
var urlStr: String?
//记录触底加载的页数
var page = 2
override func viewDidLoad() {
super.viewDidLoad()
tableView.frame = self.view.frame
tableView.delegate = self
tableView.dataSource = self
self.view.addSubview(tableView)
tableView.separatorColor = UIColor.redColor()
tableView.rowHeight = 100
tableView.registerNib(UINib.init(nibName: "AppCell", bundle: nil), forCellReuseIdentifier: "qqq")
//闭包会捕获内部使用的实例(强引用)
//为了防止循环引用,闭包内部通常都用弱引用
weak var weakSelf = self
//下拉刷新的控件
tableView.mj_header = MJRefreshNormalHeader.init(refreshingBlock: {
let url = String.init(format: weakSelf!.urlStr!, 1)
let mc = MyConnection.init(urlStr: url, target: weakSelf!, action: #selector(weakSelf!.connectionFinish(_:)),tag: 1)
mc.start()
})
//上拉刷新控件
tableView.mj_footer = MJRefreshAutoNormalFooter.init(refreshingBlock: {
let url = String.init(format: weakSelf!.urlStr!, weakSelf!.page)
let mc = MyConnection.init(urlStr: url, target: weakSelf!, action: #selector(weakSelf!.connectionFinish(_:)),tag: 2)
mc.start()
})
//直接进入下拉刷新状态
tableView.mj_header.beginRefreshing()
if let data = self.readLocal() {
self.parseData(data)
}
}
func connectionFinish(mc:MyConnection) -> Void {
if mc.isFinish {
//触底加载之后会有许多内容,然后上拉刷新恢复
if mc.tag == 1 {
dataArr.removeAll()
page = 2
self.writeTolocalWith(mc.downloadData)
} else {
page += 1
}
self.parseData(mc.downloadData)
tableView.reloadData()
} else {
print("\(self)网络请求失败")
}
//关闭加载状态
tableView.mj_header.endRefreshing()
tableView.mj_footer.endRefreshing()
}
func parseData(data:NSData) -> Void {
//json
let dataDic = try! NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) as! NSDictionary
let appArr = dataDic["applications"] as! [[String: AnyObject]]
//字典转模型
for appDic in appArr {
dataArr.append(AppModel.modelWith(appDic))
}
}
}
//MARJK: 缓存
extension ListViewController {
//往本地存数据
func writeTolocalWith(data: NSData) {
//类名转成字符串
let name = NSStringFromClass(self.dynamicType)
//拼接完整的沙盒路径
let path = String.init(format: "%@/Documents/%@.txt", NSHomeDirectory(),name)
//将数据写入文件
data.writeToFile(path, atomically: true)
}
//从本地读区数据
func readLocal() -> NSData? {
let name = NSStringFromClass(self.dynamicType)
let path = String.init(format: "%@/Documents/%@.txt", NSHomeDirectory(),name)
return NSData.init(contentsOfFile: path)
}
}
extension ListViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataArr.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("qqq", forIndexPath: indexPath) as! AppCell
cell.customWithModel(dataArr[indexPath.row])
return cell
}
}
###9.新建MyConnection继承自NSObject
class MyConnection: NSObject {
//MARK:属性
//记录网址
var urlStr: String?
//记录下载的数据
let downloadData = NSMutableData()
//记录一个对象
var target: AnyObject?
//记录一个方法
var action: Selector?
//记录下载的状态
var isFinish: Bool = false
//标记
var tag: Int?
//记录执行网络连接的对象
var connection: NSURLConnection?
//MARK:方法
init(urlStr: String, target: AnyObject, action: Selector, tag: Int = 0) {
self.urlStr = urlStr
self.target = target
self.action = action
self.tag = tag
}
//启动
func start() -> Void {
let url = NSURL.init(string: urlStr!)!
let request = NSURLRequest.init(URL: url)
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
connection = NSURLConnection.init(request: request, delegate: self)
}
func stop() -> Void {
connection?.cancel()
}
deinit {
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
}
}
extension MyConnection: NSURLConnectionDataDelegate {
func connection(connection: NSURLConnection, didReceiveResponse response: NSURLResponse) {
self.downloadData.length = 0
}
func connection(connection: NSURLConnection, didReceiveData data: NSData) {
self.downloadData.appendData(data)
}
func connectionDidFinishLoading(connection: NSURLConnection) {
self.isFinish = true
self.target!.performSelector(action!, withObject: self)
}
func connection(connection: NSURLConnection, didFailWithError error: NSError) {
self.isFinish = false
self.target!.performSelector(action!, withObject: self)
}
}
###10.编辑LimitViewController
class LimitViewController: ListViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.urlStr = self.limit_url
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath) as! AppCell
let model = dataArr[indexPath.row]
cell.subLabel.text = self.stringFrom(model.expireDatetime!)
return cell
}
func stringFrom(dataStr:String) -> String {
//时间戳(将时间和字符串进行转化)
let dateFormat = NSDateFormatter()
//设置转化格式(大MM,小dd,ss后面的 .0可要可不要)
dateFormat.dateFormat = "yyyy-MM-dd HH:mm:ss.0"
let date = dateFormat.dateFromString(dataStr)!
//计算时间差
let time = Int(date.timeIntervalSinceNow)
return String.init(format: "剩余:%02d:%02d:%02d", time / 3600, time % 3600 / 60, time % 60)
}
}
###11.编辑FreeViewController
class FreeViewController: ListViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.urlStr = self.free_url
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath) as! AppCell
cell.subLabel.text = "我爱中国"
return cell
}
}
###12.编辑SaleViewController
class SaleViewController: ListViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.urlStr = self.sale_url
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath) as! AppCell
let model = dataArr[indexPath.row]
cell.subLabel.text = String.init(format: "现价:¥%0.1f", Float(model.currentPrice!)!)
return cell
}
}
###补充:在Info.plist文件中加入http链接的请求,读者自己比较.plist文件有什么不同,缺少的地方自己点击加入
[点这里下载源代码](/Users/qianfeng/Desktop/LoveFree副本.zip)