1. HBKit 来源
HBKit最早由HuobanKit演变而来,我将HuobanKit中跟业务无关的代码抽离出来,精简成基本的网络框架和数据库(CoreData)框架,对MVVM架构设计方案清晰分层,并结合VIPER、Riblets架构设计思路引入Router路由,组成:网络、数据库、路由三个体系。可以以极简的方式来使用,并让ViewController间解耦。并由Swift进行代码重写,一个全新Swift框架。
而HuobanKit则以后由业务model组成,负责业务的数据与服务器交互。
目前本框架还没有公布出来,尚需进一步完善
1.1 网络部分
网络请求部分针对Alamofire进行二次封装,
提取出可以方便快捷使用的网络请求GET/ POST/ PUT/ DELETE的四种方法
1.2 数据库部分
采用apple原生CoreData作为基础数据库,提供数据增、删、查(改)的动作,
并支持Api属性对应数据entity模型的驼峰命名法的匹配:如user_id => userId
1.3 路由部分
采用url网络链接写法,基于url进行拆分并提取出class/function?params进行ViewController窗口的初始化
2. 用法
2.1 发起网络请求
2.1.1 GET
- 按任意请求举例
// 接口域在HBKitConfig.swift HBApiURL中设置
let request = HBRequest.GETRequestWithPath(path: "/uri")
request.completion { [unowned self] (error:NSError?, response:HBResponse) in
if error != nil {
print("faild to request, error :", error)
} else {
print("response:", response)
}
}
request.send()
2.1.2 POST
- 按用户登录举例
var parameters: Dictionary = Dictionary<String, Any>()
parameters["username"] = "username"
parameters["password"] = "password"
let request:HBRequest = HBRequest.POSTRequestWithPath(path: "/auth", parameters: parameters)
request.completion { (error:NSError?, response:HBResponse) in
if error != nil {
print("faild to request, error :", error)
} else {
print("response:", response.body as Any)
}
}
request.send()
2.1.3 MultiRequest
- 多请求需要服务器支持batch接口、并对POST请求进行拆分和返回数据
// 基于GET请求将send方法添加参数packer: HBMultiRequestPacker.shared
request.send(packer: HBMultiRequestPacker.shared)
// 并由HBMultiRequestPacker类send
HBMultiRequestPacker.shared.send()
2.2 数据库
2.2.1 网络请求入库
2.2.1.1 如何根据接口返回数据构建数据表?
- 如果已经存在 {YourProjectName}.xcdatamodeld 文件则建立Entity, 比如ItemModel
- 在ItemModel当中新建两个字段:
ItemModel
itemId (Integer 64)
name (String)
- 并打开XCode -> Editor -> Create NSManagedObject Class 新建一个针对于ItemModel的类
- 打开ItemModel的类,在class后面加入HBManagedObject声明
- 并为ItemModel类添加一个类方法identityPropertyNames指明主键(Primary key):
public class ItemModel:NSManagedObject, HBManagedObject {
static func identityPropertyNames() -> [String] {
return ["itemId"]
}
}
2.2.1.2 如何将接口数据存入CoreData?
- 比如:接收到Api数据如下
{"item_id": 10000, "name": "测试Item"}
- 在线请求HBRequest接收到的数据在response.body当中(response:HBResponse),尝试入库
// 网络请求返回值片段...
request.completion { [unowned self] (error:NSError?, response:HBResponse) in
if error == nil {
// response.body = {"item_id": 10000, "name": "测试Item"}
let body = response.body as! Dictionary
let itemModel = ItemModel.hb_createObjectOrUpdate(fromDictionary: body, isSave: true)
}
}
- 如果请求的response.body是一个Array,则可以使用HBManagedObject针对Array的扩展方法:
/*
response.body = [
{"item_id": 10000, "name": "测试Item0"},
{"item_id": 10001, "name": "测试Item1"},
{"item_id": 10002, "name": "测试Item2"}
]
*/
// 网络请求返回值,入库片段
request.completion { [unowned self] (error:NSError?, response:HBResponse) in
let body = response.body as! [Dictionary]
let itemArray:Array = ItemModel.hb_createObjectsOrUpdate(fromArray: body,
isSave: true,
step: { (itemModel:ItemModel, index:Int) in
// 单步执行,可以改造数据等
}, completion: {
// 注意completion还可以做其他事情,比如Array循环结尾的回调
})!
}
2.2.2 数据库数据查询
- 数据库查询方法,可以写在ItemModel中,比如按itemId查询一个指定数据
public class ItemModel: NSManagedObject, HBManagedObject {
static func identityPropertyNames() -> [String] {
return ["itemId"]
}
static func queryModel(itemId:Int64) -> ItemModel? {
let result:Array = self.hb_getObjects(predicate: NSPredicate.init(format: "itemId=%ld", itemId))
if result.count > 0 {
return result.first
}
return nil
}
}
2.2.3 数据库数据删除
- 通过ItemModel查询到的数据,通过实例方法.delete()即可删除,比如:
let itemModel = ItemModel.queryModel(itemId:10000)
itemModel.delete()
2.2.4 数据库数据修改和保存
let itemModel = ItemModel.queryModel(itemId:10000)
itemModel.name = "change the name"
itemModel.save()
2.3 Router 路由解耦
- HBKit提供一个HBRouter类来进行业务层(UIViewController)开发解耦,并提供HBBaseViewController的协议来约定解耦规则
- HBRouter基于网络链接来进行url的拆解,识别huoban://host(class)/action(function)?params...
- HBRouter会根据host,自动寻找host + "ViewController"的类来初始化
2.3.1 声明一个可用于HBRouter路由的HBBaseViewController
- HBBaseViewController 存在一个协议,需要实现该方法,才能完成Router的调用
protocol HBBaseViewController {
static func createViewController() -> UIViewController
}
- 开始声明一个基于HBBaseViewController协议的ViewController,叫ItemViewController
- ItemViewController可以有HBRouter传参,比如:itemId:NSNumber
class ItemViewController: UIViewController, HBBaseViewController {
var itemId:NSNumber? = nil
// 基于HBBaseViewController协议,声明createViewController,方便HBRouter
static func createViewController() -> UIViewController {
//这里采用从StoryBoard来获取一个UIViewController
return self.instantiateViewControllerFromStoryboard(name: "Item")
}
override func viewDidLoad() {
}
}
- 需要打开ItemViewController的地方,可以采用HBRouter的url形式来打开它:
HBRouter.shared.push(path: "huoban://item", params: ["item_id": NSNumber.init(value: 10000)])
当然我们也可以通过?item_id=10000传参
HBRouter.shared.push(path: "huoban://item?item_id=10000")
- HBRouter会自动将item_id转换成itemId的方式进行赋值(?itemId=10000则不会转换)
- 这代码的结果将会是:
var itemViewController = ItemViewController.createViewController()
itemViewController.itemId = NSNumber.init(value:10000)
self.navigationController.pushViewController(itemViewController)
- HBRouter有两个方法打开ViewController: 1. push, 2. present
2.4 OBServable(订阅被观察者Block)
2.4.1 HBKit/Extension/Observable.swift 是被观察者
- 由于MVVM的架构变更,ViewModel层和ViewController层需要一种方式来解耦,将ViewModel 状态变更自动回调给 ViewController。做到减少状态设置,对ViewController减肥。
- 具体用法
//ViewModel
class ItemViewModel {
var itemName = Observable<String>("")
init (_ itemId:Int) {
// itemId......do something
}
func requestNetworkData() {
itemName <- "refresh new name!"
}
func requestNetworkData2() {
itemName <- "refresh new name2!"
}
}
// ViewController
class ItemViewController {
var itemViewModel = ItemViewModel(10000)
@IBOutlet weak var itemNameLabel: UILabel!
itemViewModel.itemName.subscribe{ [unowned self] (oldValue, newValue:Bool) in
self.itemNameLabel.text = newValue
}
itemViewModel.requestNetworkData()
itemViewModel.requestNetworkData2()
}
- 看到上面的代码,ViewController让ViewModel进行了两次“模拟网络请求”,让itemName改名后,自动反应在itemNameLabel的UI控件上
- 我有一个关于OBServable的详细教程,有兴趣可以翻阅:http://www.jianshu.com/p/f1acd9dcc384 GitHub: https://github.com/maxcong/Observable-Block-Swift
2.5 工程目录结构推荐
- 基于尽可能的解耦业务逻辑间的联系,我们在使用HBRouter的时候,会将ViewController进行分类,我推荐的目录结构为:
Project
Core
Common
HBKit
Data
ItemModel.swift
Model
ItemAgent.swift
Module
Item
Item.storyboard
ItemList
ItemListViewController.swift
3. HBKit 目录结构
-
HBKitConfig (Config设置类)
-
Network (网络请求组件目录)
- HBClient
网络请求发送,认证信息拼接,用于将HBRequest包装成真实的URLRequest类的请求 拼接Header
- HBRequest
请求体包装用户接口类 用户可以设定HttpMethod: GET/ POST/ PUT/ DELETE
- HBResponse
网络请求返回值的包装用户接口类
- HBAuthorization
登录用户验证类
- HBMultiRequest
多请求类,基于Batch接口进行Post打包提交
-
CoreData (基于CoreData实现数据组件目录)
- HBManagedObject (NSManagedObject+extension)
对NSManagedObject的扩展,封装了方便增、删、改、查的动作,使用反射的原理映射给CoreData的Model类
-
Extension
-
Class
- HBNotificationCenter
广播的block轻巧封装
- Observable
极简观察者模式
- HBImageURLSessionDataTask
轻巧的图片下载类
-
NSObject扩展
1.获取NSObject中的属性名称列表
- String扩展
1.字符串切割"_"现转换为驼峰命名法
- UIImageView扩展
1. 针对ImageView提供快捷网络图片设置
- UIButton扩展
1. 针对UIButton提供快捷网络图片设置
- UIViewController扩展
定义常规HBBaseViewController针对HBRouter和Storyboard初始化的动作
- UIActivityIndicatorView
loading的快捷显隐的扩展
- NSError
网络请求错误的NSError扩展
-
-
Router
- HBRouter
路由,与HBBaseViewController一起联合进行路由的反射操作,用于解耦业务间的类
网友评论