swift设备管理制作过程(xib自动布局)
该工程git仓库 https://gitee.com/zjf1998/DeviceManage-swift
目录
1. swift工程搭建 2
1.1新建DeviceManager-swift项目 2
1.2 installpod 3
1.3 整理项目目录 5
2. 封装AFNetworking 5
2.1 创建网络工具类 5
2.2创建Model解析类 7
3. 实现登录模块功能 8
3.1 创建用户信息模型UserInfoModel类 8
3.2 创建登录xib和Controller 11
4. 实现首页模块功能 16
4.1 实现TabBar功能 16
4.2实现HomeViewController,并使用xib适配 17
5. 实现咨询模块功能 24
1.新建InfoViewController 24
2.添加上下左右4个约束0,使得这个tableView布满整个屏幕 24
3.新建一个viewController,同时添加一个webView,同样使其布满整个屏幕 25
4.最后在infoViewController中添加tableViewCell点击事件 25
6. 实现购物车模块功能 26
1.创建ShoppingCartViewController并勾选xib文件 26
2.在xib文件中拖入一个tableView和一个view 27
3.适配iphoneX界面 28
4.创建UITableViewCell 30
7. HandyJSON的使用 33
8. SwiftyJSON的使用 34
首先需要使用Xcode创建DeviceManager-swift工程,选择iOS-Application-SingleViewApp,点击Next:
输入项目名称,组织名称,bundleid,和使用的语言。由于不要需要使用单元测试和CoreDate,所以去掉底部的三个勾,如图配置好以后,点击Finish:
本项目使用CocoaPod管理第三方框架,所以需要将Pod引入项目。
使用命令行,切换到项目根目录,使用如下命令创建Pod:
此时在工程目录下Pod会创建一个文件,名为Podfile。需工程需要导入的第三方框架就添加在这个文件当中。使用vim编辑Podfile,加入DeviceManage-swift需要使用的第三方库,修改Podfile文件为:
# Uncomment the next line to define a global platform for your project
platform :ios, '9.0'
# Uncomment the next line if you're using Swift or would like to use dynamic frameworks
use_frameworks!
target 'DeviceManage-swift' do
# Pods for DeviceManage-swift
pod 'AFNetworking' , '~> 3.1.0'
pod 'SVProgressHUD'
pod 'SDCycleScrollView', '~> 1.73'
pod 'SDAutoLayout'
pod 'MJRefresh'
pod 'JPush'
pod 'AMapLocation'
pod 'SDWebImage'
pod 'SnapKit'
pod 'HandyJSON', '~> 4.2.0'
pod 'SwiftyJSON'
end
依次说明一下这几个第三方库的作用:
保存Podfile后,在Podfile当前目录下执行pod install命令,安装第三方库。
如图所示安装成功后,pod会把第三方库和工程合并到一个workspace中,所以现在需要从DeviceManage-swift.xcworkspace文件打开工程。打开后可以看到集成的第三方库:
需要使用第三方库的时候,只需要导入头文件,直接使用就可以了。项目直接把第三方库交给了CocoaPod管理了。
一般iOS项目会使用MVC的设计模式进行开发,MVC的设计模式可以降低开发的耦合性、提高组件的重用性、提高可维护性,最重要的是可以使开发者条理清晰。Apple的UIKit等系统库都大量使用了MVC设计模式,所以本项目也将会在MVC的设计模式上进行开发。
首先需要整理项目目录,便于之后的开发和文件的分类。项目按照功能分类,在各个功能下分为三个模块:Model、Controller、View,在DeviceManager目录下创建好空文件夹,如下所示:
这里需要说明一下:
项目一般都会封装一层业务层的网络框架,这样可以统一请求网络请求接口,记录或打印网络日志,封装请求格式和解析格式等等。本项目底层网络框架采用AFNetworking,对AFNetworking进行了如下的业务封装:
NetworkTool类就是本项目对AFNetworking的一层业务封装,具体代码如下:
NetworkTool.swift(SDSY/SDSY/Classes/Tools(工具)/NetworkTool.swift):
import Foundation
import AFNetworking
// 定义枚举类型
enum HTTPRequestType : Int{
case GET = 0
case POST
}
class NetworkTools: AFHTTPSessionManager {
// 设计单例 let是线程安全的
static let shareInstance : NetworkTools = {
let tools = NetworkTools()
tools.responseSerializer.acceptableContentTypes?.insert("text/html")
return tools
}()
}
// 封装请求方法
extension NetworkTools {
func request(methodType : HTTPRequestType, urlString : String, parameters : [String : AnyObject], finished :@escaping (_ result : AnyObject?, _ error : Error?)-> ()) {
// 1 成功回调
let successCallBack = {(task :URLSessionDataTask, result : Any) in
finished(result as AnyObject?, nil)
}
// 2 失败回调
let failureCallBack = {(task : URLSessionDataTask?, error :Error) in
finished(nil, error)
}
if methodType == .GET {
// get请求
get(urlString, parameters: parameters, progress: nil, success: successCallBack, failure: failureCallBack)
}else {
// post请求
post(urlString, parameters: parameters, progress: nil, success: successCallBack, failure: failureCallBack)
}
}
}
注意到上面的几个宏定义,需要加入到Const.swift文件中:
import UIKit
let BASE_URL = "http://192.168.0.108:8080/DeviceManage/"
对以上宏定义进行解释:
网络框架已经将请求服务器返回的JSON字符串转换为了NSDictionary,如果我们之间使用NSDictionary来存取数据会十分的不方便。比如:每次读取或者写入时都需要使用Key-Value的方式进行,而Value的类型是id类型,非常的不直观。如果使用对象作为数据模型就会使开发更方便,出错率更低。所以项目需要一个将JSON字符串转化为JSON对象的类。
本项目的数据模型解析类的构造如下:BasaModel类是所有数据模型的父类,BasaModel负责解析JSON字符串为子类的属性。具体实现如下,BaseModel.h(SDSY/SDSY/Classes/Tools(工具)/BaseModel.swift):
import UIKit
import HandyJSON
class BaseModel: HandyJSON {
required init() {
}
}
1HandyJSON支持 JSON直接转Model,定义class时,有两点注意:
必须遵循HandyJSON协议
需要实现空的initializer (当然Struct结构体 可以不需要init())
User登录使用的Model为UserInfoModel。该Model类封装了如下功能:
UserInfoModel作为一个全局单例,控制用户的登录状态与用户登录信息。
UserInfoModel.swift(SDSY/SDSY/Classes/Login(登录)/Model/UserInfoModel.swift):
import Foundation
import SwiftyJSON
enum LoginType:Int {
case AutoLogin = 1 // 自动登录
case GeneralLogin = 2 // 普通账号密码登录
case NoToken = 3 // 不存在token
case PastToken = 4 // token过期
}
class UserInfoModel:NSObject,NSCoding{
// 单例 - 避免重复从沙盒加载归档文件
static var shareInstance = UserInfoModel()
var UserID:Int?
var UserName:String?
var UserPassword:String?
//获取数据
override init() {
super.init()
let fileData = NSMutableData(contentsOfFile: self.savePath())
if fileData != nil {
let unarchiver = NSKeyedUnarchiver(forReadingWith: fileData! as Data)
let model = unarchiver.decodeObject(forKey: "userKey") as! UserInfoModel
UserID = model.UserID
UserName = model.UserName
UserPassword = model.UserPassword
unarchiver.finishDecoding()
}
}
//MARK:-自定义构造函数
init(dic:[String:JSON])
{
super.init()
UserID = dic["UserID"]?.intValue
UserName = dic["UserName"]?.stringValue
UserPassword = dic["UserPassword"]?.stringValue
}
//归档的方法
func encode(with aCoder: NSCoder) {
aCoder.encode(UserID, forKey: "UserID")
aCoder.encode(UserName, forKey: "UserName")
aCoder.encode(UserPassword, forKey: "UserPassword")
}
//解档的方法
required init?(coder aDecoder: NSCoder) {
super.init()
UserID = aDecoder.decodeObject(forKey: "UserID") as! Int?
UserName = aDecoder.decodeObject(forKey: "UserName") as! String?
UserPassword = aDecoder.decodeObject(forKey: "UserPassword") as! String?
}
//检查是否已登录
func checkLogin() -> Bool{
// 1. 是否存在token
if(UserPassword == nil || UserPassword?.count == 0){
self.loginLog(type: LoginType.NoToken);
return false;
}
// 2. 自动登录成功
self.loginLog(type: LoginType.AutoLogin);
return true;
}
//输出日志信息
func loginLog(type:LoginType){
var loginType:String = ""
if(type == LoginType.AutoLogin){
// 自动登录
loginType = "自动登录";
}else if(type == LoginType.GeneralLogin) {
// 普通
loginType = "账号密码登录";
}else if (type == LoginType.NoToken) {
// 不存在token
loginType = "不存在token,自动登录失败";
}else if (type == LoginType.PastToken) {
// 不存在token
loginType = "不存在token,自动登录失败";
}
print("-------------------------------------------------")
print("-------------------登录服务器信息-------------------")
print("-------------------------------------------------")
print("登录类型: %@",loginType)
if self.UserID != nil {
print("expiration: \(self.UserID!)")
}
if self.UserName != nil {
print("stu_id: \(self.UserName!)")
}
if self.UserPassword != nil {
print("token: \(self.UserPassword!)")
}
print("保存路径: %@",self.savePath())
print("-------------------------------------------------")
print("-------------------------------------------------")
}
// 保存数据
func saveToFile(model:UserInfoModel){
let data = NSMutableData()
let archive = NSKeyedArchiver(forWritingWith: data)
archive.encode(model, forKey: "userKey")
archive.finishEncoding()
data.write(toFile: self.savePath(), atomically: true)
}
//获取保存路径
func savePath() ->String {
// 1、获得沙盒的根路径
let home = NSHomeDirectory() as NSString
// 2、获得Documents路径
let docPath = home.appendingPathComponent("Documents") as NSString
// 3、获取文本文件路径
return docPath.appendingPathComponent("UserInfo.plist") as String
}
//删除信息
func logout(){
let manager:FileManager = FileManager.default
// 1. 是否文件
if(!manager.fileExists(atPath: self.savePath())){
print("没有找到token文件")
return
}
// 2.删除token信息
do{
try manager.removeItem(atPath: self.savePath())
} catch{
print("登出失败")
}
// 3.释放模型
UserInfoModel.shareInstance = UserInfoModel.init() ;
}
}
需要实现的登录页面如下,用户输入学号和密码后,点击登录。APP调用登录接口,服务器根据登录学号与密码,返回相关登录信息,APP将登录信息解析为UserInfoModel模型:
本页面使用xib构建登录页面,Controller用来控制UI细节、网络请求和Model解析,首先创建xib:
import UIKit
import SwiftyJSON
import SVProgressHUD
class LoginViewController: UIViewController,UITextFieldDelegate,UIScrollViewDelegate {
// 学号id
@IBOutlet weak var idTextField: UITextField!
// 密码
@IBOutlet weak var passwdTextField: UITextField!
// 登录按钮
@IBOutlet weak var loginBtn: UIButton!
// label背景
@IBOutlet weak var labelBackView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// 检查是否已经登录,如果已经登录,则进入主界面
if (UserInfoModel.shareInstance.checkLogin() == true){
// 已登录
self.showMainViewController();
return;
}
// 调整登录按钮
self.loginBtn.layer.masksToBounds = true
self.loginBtn.layer.cornerRadius = 10
// 调整背景View
self.labelBackView.layer.masksToBounds = true
self.labelBackView.layer.cornerRadius = 10
self.labelBackView.layer.borderWidth = 0.5
self.labelBackView.layer.borderColor = UIColor.gray.cgColor
// textField
self.idTextField.delegate = self as UITextFieldDelegate;
self.passwdTextField.delegate = self as UITextFieldDelegate;
//测试账号自动填充
self.idTextField.text = "tom";
self.passwdTextField.text = "654321";
}
@IBAction func loginBtnTapped(_ sender: Any) {
self.login()
}
//登入
func login(){
SVProgressHUD.show()
let params = ["username":self.idTextField.text, "password": self.passwdTextField.text] // 请求参数
let loginUrl = BASE_URL+"loginValidate" // 请求地址
// 使用 AFNetworking 发送POST请求
NetworkTools.shareInstance.request(methodType: .POST, urlString: loginUrl, parameters: params as [String : AnyObject]) { (result : AnyObject?, error : Error?) in
if error != nil {
print(error!)
SVProgressHUD.dismiss()
SVProgressHUD.showError(withStatus: "web接口服务连接失败,请确保主机ip地址是否正确,然后打开tomcat服务器")
return
}
print(result!)
// 使用 SwiftyJSON 解析json -- 这里解析的是 jsonObject
// 如果要解析 jsonArray, SwiftyJSON 更加丝滑, 参考 http://www.hangge.com/blog/cache/detail_968.html
let json = JSON(result as Any)
if let dataDict = json["result"][0].dictionary {
// 字典转模型
let user : UserInfoModel = UserInfoModel.init(dic: (dataDict as [String : JSON] ))
// 设置用户模型
UserInfoModel.shareInstance.saveToFile(model: user)
self.showMainViewController();
}else{
SVProgressHUD.dismiss()
SVProgressHUD.showError(withStatus: "web接口服务连接失败,请确保主机ip地址是否正确,然后打开tomcat服务器")
}
}
}
//跳转到主界面
func showMainViewController(){
let appdelegate = UIApplication.shared.delegate as! AppDelegate
appdelegate.window?.rootViewController = MainViewController()
}
//UITextFieldDelegate协议
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if (textField.tag == 1) {
// 学号textField,点击next,密码textField聚焦
self.passwdTextField.becomeFirstResponder();
}else {
// 密码textField,点击return,直接登录
self.login();
self.idTextField.resignFirstResponder();
self.passwdTextField.resignFirstResponder();
}
return true;
}
//系统回调
override func touchesBegan(_ touches: Set
self.idTextField.resignFirstResponder();
self.passwdTextField.resignFirstResponder();
}
}
这里有三点需要注意:
1. 需要导入json解析框架SwiftyJSON
import SwiftyJSON
2.MainViewController的父类是UITabBarController,用来管理显示在主屏上的四个模块(首页、资讯、购物车、设置),在之后的章节会详细介绍。目前为了运行起来,可以先创建一个MainViewController类,继承于UITabBarController在/DeviceManage/DeviceManage/Classes目录下。
在App启动时,需要检查用户的登录状态,如果本地有用户登录的Token,并且Token未过期,代表当前用户的登录状态有效,展示主页;如果未能找到本地的用户信息,或者Token已失效,展示登录页面。本项目,将登录状态的检测与跳转的页面交给了LoginViewController类实现。在上面的LoginViewController.m的- (void)viewDidLoad的方法中有判断。所以,APP启动后的rootViewController为LoginViewController,待LoginViewController检查Token后,跳转对应的页面。
删除ViewController类,并在AppDelegate.swift文件中修改- (BOOL)application: didFinishLaunchingWithOptions:方法为:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
//设置提示框最长显示时间
SVProgressHUD.setMaximumDismissTimeInterval(1.0)
//设置导航条点击颜色为橘色
UINavigationBar.appearance().tintColor = UIColor.orange
//设置底部tabBar颜色为橘色
UITabBar.appearance().tintColor = UIColor.orange
//设置导航栏标题颜色
UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.orange]
//初始化窗体,设置第一个启动的Controller
window = UIWindow.init(frame: UIScreen.main.bounds)
window?.rootViewController = LoginViewController()
window?.makeKeyAndVisible()
return true
}
将rootViewController指向了LoginViewController。运行代码可以看到我们实现的界面了,并且能看见控制台如下输出:
在这里需要实现,点击底部的TabBarItem切换四个模块的主要页面(首页、资讯、搜索、设置)。首先创建四个空的类,在之后会实现四个模块的代码:
func setupViewControllers(){
// 1.设置首页导航控制器
let homeViewController:HomeViewController = HomeViewController()
let homeNavi:UINavigationController = UINavigationController.init(rootViewController: homeViewController)
self.addChild(homeNavi)
// 2.设置咨询导航控制器
let infoViewController:InfoViewController = InfoViewController()
let infoNavi:UINavigationController = UINavigationController.init(rootViewController: infoViewController)
self.addChild(infoNavi)
// 3.设置购物车导航控制器
let shoppingCartViewController:ShoppingCartViewController = ShoppingCartViewController()
let shopNavi:UINavigationController = UINavigationController.init(rootViewController: shoppingCartViewController)
self.addChild(shopNavi)
// 4.设置我的导航控制器
let mineViewController:MineViewController = MineViewController()
let mineNavi:UINavigationController = UINavigationController.init(rootViewController: mineViewController)
self.addChild(mineNavi)
}
创建HomeViewController,同时勾选also create xib file
来到HomeViewController.xib,创建一个uiview视图,和一个tableView视图,
3.添加宏判断,适配iphoneX系列
//屏幕尺寸定义和iPhoneX机型判断代码
let SCREEN_WIDTH = UIScreen.main.bounds.size.width
let SCREEN_HEIGHT = UIScreen.main.bounds.size.height
//判断是否是ipad
let isiPad = (UIDevice.current.userInterfaceIdiom == UIUserInterfaceIdiom.pad)
//判断iPhone4系列
let kiPhone4 = ((UIScreen.main.currentMode?.size.equalTo(CGSize.init(width: 640, height: 960)))!) && isiPad
//判断iPhone5系列
let kiPhone5 = ((UIScreen.main.currentMode?.size.equalTo(CGSize.init(width: 640, height: 1136)))!) && isiPad
//判断iPhone6系列
let kiPhone6 = ((UIScreen.main.currentMode?.size.equalTo(CGSize.init(width: 750, height: 1334)))!) && isiPad
//判断iphone6+系列
let kiPhone6Plus = ((UIScreen.main.currentMode?.size.equalTo(CGSize.init(width: 1242, height: 2208)))!) && isiPad
//判断iPhoneX
let IS_IPHONE_X = ((UIScreen.main.currentMode?.size.equalTo(CGSize.init(width: 1125, height: 2436)))!) && isiPad
//判断iPHoneXr
let IS_IPHONE_Xr = ((UIScreen.main.currentMode?.size.equalTo(CGSize.init(width: 828, height: 1792)))!) && isiPad
//判断iPhoneXs
let IS_IPHONE_Xs = ((UIScreen.main.currentMode?.size.equalTo(CGSize.init(width: 1125, height: 2436)))!) && isiPad
//判断iPhoneXs Max
let IS_IPHONE_Xs_Max = ((UIScreen.main.currentMode?.size.equalTo(CGSize.init(width: 1242, height: 2688)))!) && isiPad
//iPhoneX系列
let Height_StatusBar = ((IS_IPHONE_X == true || IS_IPHONE_Xr == true || IS_IPHONE_Xs == true || IS_IPHONE_Xs_Max == true) ? 44.0 : 20.0)
let Height_NavBar = ((IS_IPHONE_X == true || IS_IPHONE_Xr == true || IS_IPHONE_Xs == true || IS_IPHONE_Xs_Max == true) ? 88.0 : 64.0)
let Height_TabBar = ((IS_IPHONE_X == true || IS_IPHONE_Xr == true || IS_IPHONE_Xs == true || IS_IPHONE_Xs_Max == true) ? 83.0 : 49.0)
//1.设置顶部轮播图
self.bannerView = SDCycleScrollView.init(frame: CGRect.init(x: 0.0, y: Height_NavBar, width: Double(SCREEN_WIDTH), height: 200.0), delegate: self, placeholderImage: UIImage.init(named: "Error"))
4.创建设备分类按钮ClassifyButton类,借鉴与尚德书院活动分类
ClassifyButton用于显示设备分类(办公设备、生活实践等等),拥有一个居上的icon和一个在下的文字描述:
import UIKit
class ClassifyButton: UIButton {
// MARK:- 自定义初始化方法
init(frame : CGRect,title : String,image: UIImage) {
super.init(frame: frame)
// 设置Btn标题
setTitle(title, for: .normal)
// 设置title颜色
setTitleColor(UIColor.black, for: .normal)
// 设置title文字大小
titleLabel?.font = UIFont.systemFont(ofSize: 12)
// 设置Btn icon
setImage(image, for: .normal)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
// 1.调整image位置
if(self.imageView != nil){
var imageFrame:CGRect = self.imageView!.frame
imageFrame.origin.x = (self.frame.size.width - imageFrame.size.width) * 0.5
imageFrame.origin.y = 5
self.imageView!.frame = imageFrame
}
// 2.调整title位置
if(self.titleLabel != nil && self.imageView != nil){
self.titleLabel!.sizeToFit()
var titleFrame:CGRect = self.titleLabel!.frame
titleFrame.origin.x = (self.frame.size.width - titleFrame.size.width) * 0.5
titleFrame.origin.y = self.imageView!.frame.maxY + 5
self.titleLabel!.frame = titleFrame
}
}
}
5.新建deviceTableViewCell
添加一系列控件用于制作tableViewCell
编写回调方法didSet
var model : DeviceModel? {
didSet{
// nil值校验
guard model != nil else {
return
}
// 设备图片
if self.model?.DeviceName == "打印机" {
self.dev_image.image = UIImage.init(named: "printer")
}
else if self.model?.DeviceName == "耳机" {
self.dev_image.image = UIImage.init(named: "earphone")
}
else if self.model?.DeviceName == "鼠标" {
self.dev_image.image = UIImage.init(named: "mouse")
}
else if self.model?.DeviceName == "笔记本电脑" {
self.dev_image.image = UIImage.init(named: "computer")
}
else if self.model?.DeviceName == "U盘" {
self.dev_image.image = UIImage.init(named: "udisk")
}
else if self.model?.DeviceName == "头盔" {
self.dev_image.image = UIImage.init(named: "helmet")
}
// 设备名
self.dev_name.text = self.model?.DeviceName
self.dev_name.setNeedsLayout()
// 设备价格
self.dev_price.text = self.model?.DevicePrice
self.dev_name.setNeedsLayout()
}
}
6.编写购物车按钮的点击事件
//添加商品到购物车
@IBAction func addShopingcart(_ sender: Any) {
let parameters:NSDictionary = ["addDeviceID":self.model?.DeviceID as Any,"addBuyNum":"1",
"addUserID":UserInfoModel.shareInstance.UserID as Any]
let manager:AFHTTPSessionManager = AFHTTPSessionManager.init()
manager.responseSerializer = AFHTTPResponseSerializer.init()
manager.post(BASE_URL+"addShopingcart", parameters: parameters, progress: { (Progress) in
}, success: { (task:URLSessionDataTask, responseObject:Any?) in
if(self.model?.DeviceID != nil){
let str:String = "设备编号\(self.model!.DeviceID)加入购物车成功"
SVProgressHUD.showInfo(withStatus: str)
SVProgressHUD.dismiss(withDelay: 1)
}
})
}
7.运行结果
可以看到已经成功适配了iphoneX。
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
// 取出cell
guard let cell:InfoTableViewCell = tableView.cellForRow(at: indexPath) as? InfoTableViewCell else{
return
}
// 弹出咨询详情页
let infoDetailViewController:InfoDetailViewController = InfoDetailViewController()
guard let content = cell.model?.InformationContent! else {
return
}
infoDetailViewController.html = content
self.navigationController?.pushViewController(infoDetailViewController, animated: true)
}
首先给tableView添加约束,让table距底部有100的距离。
然后让右键点击底部的的view拖到上面那个tableView,添加VerticalSpacing约束
添加后效果如下
约束使用代码控制,使用xib拖线的方式
//高度51 + 底部导航栏
_tableViewBottom.constant = Height_TabBar + 51;
这样一来,无论是普通的TabBar(高度49),还是iphoneX系列的TableBar(83)都可以适配,效果图:
1.在xib文件中添加如下控件即可,因为是tableViewCell,控件大小相对固定,无需添加约束
2.设置 didSet方法,设置每个tableViewCell控件的内容
var model:ShopListModel? {
didSet{
// nil值校验
guard model != nil else {
return
}
// 商品名
self.shop_name.text = self.model?.Device?.DeviceName
self.shop_name.setNeedsLayout()
// 商品价格
self.shop_price.text = self.model?.Device?.DevicePrice
self.shop_price.setNeedsLayout()
// 设备图片
if self.model?.Device?.DeviceName == "打印机" {
self.shop_image.image = UIImage.init(named: "printer")
}
else if self.model?.Device?.DeviceName == "耳机" {
self.shop_image.image = UIImage.init(named: "earphone")
}
else if self.model?.Device?.DeviceName == "鼠标" {
self.shop_image.image = UIImage.init(named: "mouse")
}
else if self.model?.Device?.DeviceName == "笔记本电脑" {
self.shop_image.image = UIImage.init(named: "computer")
}
else if self.model?.Device?.DeviceName == "U盘" {
self.shop_image.image = UIImage.init(named: "udisk")
}
else if self.model?.Device?.DeviceName == "头盔" {
self.shop_image.image = UIImage.init(named: "helmet")
}
//商品数量
self.shop_num.text = String(self.model!.BuyNum!)
self.shop_num.setNeedsLayout()
//设置该商品是否被选中图像
if(self.model!.isChoice == false){
shop_choice.setImage(UIImage.init(named: "choice"), for: .normal)
}else{
shop_choice.setImage(UIImage.init(named: "choiced"), for: .normal)
}
}
}
3.以xib拖线的方式添加按钮点击事件
//增加购物车中商品数量
@IBAction func addShop(_ sender: Any) {
guard model != nil else {
return
}
if(model?.isChoice == false){
return
}
var curBuynum:Int = (model?.BuyNum)!
curBuynum = curBuynum+1
self.model!.BuyNum = curBuynum
print("设备编号\(self.model!.Device?.DeviceID ?? -1)购物车数量加1")
//刷新视图
self.shop_num.text = String(self.model!.BuyNum!)
self.updateMoneySum()
}
//减少购物车中商品
@IBAction func reduceShop(_ sender: Any) {
guard model != nil else {
return
}
if(model?.isChoice == false){
return
}
var curBuynum:Int = (model?.BuyNum)!
if(curBuynum > 0){
curBuynum = curBuynum-1
}
self.model!.BuyNum = curBuynum
print("设备编号\(self.model!.Device?.DeviceID ?? -1)购物车数量减1")
//刷新视图
self.shop_num.text = String(self.model!.BuyNum!)
self.updateMoneySum()
}
//选中或取消选中该商品
@IBAction func shopChoice(_ sender: Any) {
if(self.model!.isChoice == false){
self.model!.isChoice = true;
self.shop_choice.setImage(UIImage.init(named: "choiced"), for: .normal)
}
else{
self.model!.isChoice = false;
self.shop_choice.setImage(UIImage.init(named: "choice"), for: .normal)
}
updateMoneySum()
}
4.在自定义cell里 获取其控制器viewController,获取控制器viewController并计算总价格
extension ShopTableViewCell{
//获取控制器viewController并计算总价格
func updateMoneySum() {
let shoppingCartViewController:ShoppingCartViewController = self.viewController() as! ShoppingCartViewController
var moneySum:Int = 0;
for i in stride(from: shoppingCartViewController.shopArray.count-1, to: -1, by: -1) {
let model:ShopListModel = shoppingCartViewController.shopArray[i] as! ShopListModel
if(model.isChoice == true){
moneySum += model.BuyNum! * Int((model.Device?.DevicePrice)!)!
}
}
shoppingCartViewController.money.text = String(moneySum)
}
//在自定义cell里 获取其控制器viewController
func viewController() -> UIViewController? {
for view in sequence(first: self.superview, next: { $0?.superview }) {
if let responder = view?.next {
if responder.isKind(of: UIViewController.self){
return responder as? UIViewController
}
}
}
return nil
}
}
5.在tableView中指定按xib进行加载
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell :ShopTableViewCell? = tableView.dequeueReusableCell(withIdentifier: "CellID") as? ShopTableViewCell
if(cell == nil){
cell = Bundle.main.loadNibNamed("ShopTableViewCell", owner: nil, options: nil)?.first as? ShopTableViewCell
}
if let model = shopArray[indexPath.row] as? ShopListModel {
cell?.model = model
}
return cell!
}
HandyJSON另辟蹊径,采用Swift反射+内存赋值的方式来构造Model实例,保持原汁原味的Swift类定义。
1、pod引入
pod 'HandyJSON'
2、使用时,先头部import
import HandyJSON
1、HandyJSON支持 JSON直接转Model,定义class时,有两点注意:
必须遵循HandyJSON协议
需要实现空的initializer (当然Struct结构体 可以不需要init(),下文有说明)
2.为了方便使用,创建BaseModel继承HandyJSON
import UIKit
import HandyJSON
class BaseModel: HandyJSON {
required init() {
}
}
3.使用示例
import UIKit
class ShopModel: BaseModel {
var DeviceClassId:Int? //设备分类id
var DeviceID:Int? //设备id
var DeviceName:String? //设备名称
var DevicePrice:String? //设备价格
required init() {
}
}
SwiftyJSON是个使用Swift语言编写的开源库,可以让我们很方便地处理JSON数据(解析数据、生成数据)。下面这个网站详细说明了如何使用:
http://www.hangge.com/blog/cache/detail_968.html
使用示例
// 使用 SwiftyJSON 解析json -- 这里解析的是 jsonObject
// 如果要解析 jsonArray, SwiftyJSON 更加丝滑, 参考 http://www.hangge.com/blog/cache/detail_968.html
let json = JSON(result as Any)
guard let array = json["result"].array else{
ZJFLog(message: "获取数据出错")
// 正常结束刷新
self.tableView.mj_header.endRefreshing()
return
}
for dataDict in array{
let response = dataDict.dictionaryObject
// 字典转模型
guard let model:ShopListModel = ShopListModel.deserialize(from: response) else{
ZJFLog(message: "字典转模型出错")
continue
}
self.shopArray.add(model)
}