From 8a8e11cd8a11cedfa879afaed4655371c1adf002 Mon Sep 17 00:00:00 2001 From: caonongyun Date: Thu, 22 Nov 2018 22:32:04 +0800 Subject: [PATCH 01/19] =?UTF-8?q?=E4=B9=A6=E6=9E=B6=E9=87=87=E7=94=A8?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zhuishushenqi.xcodeproj/project.pbxproj | 12 + zhuishushenqi/App/ZSDatabase.swift | 1 + zhuishushenqi/App/ZSJSON.swift | 57 ++++ .../Controllers/ZSShelfViewController.swift | 40 +-- .../Root/Service/ZSShelfWebService.swift | 1 + zhuishushenqi/Splash/QSSplashScreen.swift | 42 +-- zhuishushenqi/TXTReader/BookDetail/.DS_Store | Bin 8196 -> 6148 bytes .../BookDetail/Models/BookShelf.json | 301 ++++++++++++++++++ .../BookDetail/Models/BookShelf.swift | 10 +- .../BookDetail/Models/ZSReadRecord.swift | 22 ++ 10 files changed, 446 insertions(+), 40 deletions(-) create mode 100644 zhuishushenqi/App/ZSJSON.swift create mode 100644 zhuishushenqi/TXTReader/BookDetail/Models/BookShelf.json create mode 100644 zhuishushenqi/TXTReader/BookDetail/Models/ZSReadRecord.swift diff --git a/zhuishushenqi.xcodeproj/project.pbxproj b/zhuishushenqi.xcodeproj/project.pbxproj index 80174c6..d03e022 100644 --- a/zhuishushenqi.xcodeproj/project.pbxproj +++ b/zhuishushenqi.xcodeproj/project.pbxproj @@ -78,6 +78,9 @@ 3DDEEB02214B5D59003D12DB /* UIFont+ZSExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DDEEB01214B5D59003D12DB /* UIFont+ZSExtension.m */; }; 3DE393D9219D505600890488 /* ZSBoughtInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DE393D8219D505500890488 /* ZSBoughtInfo.swift */; }; 3DE393DB219D514100890488 /* ZSBookBoughtViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DE393DA219D514100890488 /* ZSBookBoughtViewModel.swift */; }; + 3DE393E721A3B7B600890488 /* ZSReadRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DE393E621A3B7B600890488 /* ZSReadRecord.swift */; }; + 3DE393E921A3B84600890488 /* BookShelf.json in Resources */ = {isa = PBXBuildFile; fileRef = 3DE393E821A3B84600890488 /* BookShelf.json */; }; + 3DE393EB21A3EB2D00890488 /* ZSJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DE393EA21A3EB2D00890488 /* ZSJSON.swift */; }; 3DE77D2620C8E99500A86DF0 /* ZSBaseTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DE77D2520C8E99500A86DF0 /* ZSBaseTableViewController.swift */; }; 3DE77D2A20C90EA300A86DF0 /* ZSRootWebService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DE77D2920C90EA300A86DF0 /* ZSRootWebService.swift */; }; 3DF2D27820EB5773004E73B6 /* ZSChapterInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DF2D27720EB5773004E73B6 /* ZSChapterInfo.swift */; }; @@ -556,6 +559,9 @@ 3DDEEB01214B5D59003D12DB /* UIFont+ZSExtension.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIFont+ZSExtension.m"; sourceTree = ""; }; 3DE393D8219D505500890488 /* ZSBoughtInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZSBoughtInfo.swift; sourceTree = ""; }; 3DE393DA219D514100890488 /* ZSBookBoughtViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZSBookBoughtViewModel.swift; sourceTree = ""; }; + 3DE393E621A3B7B600890488 /* ZSReadRecord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZSReadRecord.swift; sourceTree = ""; }; + 3DE393E821A3B84600890488 /* BookShelf.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = BookShelf.json; sourceTree = ""; }; + 3DE393EA21A3EB2D00890488 /* ZSJSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZSJSON.swift; sourceTree = ""; }; 3DE77D2520C8E99500A86DF0 /* ZSBaseTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZSBaseTableViewController.swift; sourceTree = ""; }; 3DE77D2920C90EA300A86DF0 /* ZSRootWebService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZSRootWebService.swift; sourceTree = ""; }; 3DF2D27720EB5773004E73B6 /* ZSChapterInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZSChapterInfo.swift; sourceTree = ""; }; @@ -1407,6 +1413,7 @@ B2A7CD88218017380067D25B /* ZSMobileLogin.swift */, 3D252CDF219175FC0051B60D /* ZSDatabase.swift */, B25EB92B2194986C000D3657 /* ZSEncryptorAESUtils.swift */, + 3DE393EA21A3EB2D00890488 /* ZSJSON.swift */, B25EB92D2194999E000D3657 /* FBEncryptorAESUtils.h */, B25EB92E2194999E000D3657 /* FBEncryptorAESUtils.m */, B25EB93021949AF1000D3657 /* FBEncryptorAES.h */, @@ -2146,6 +2153,8 @@ B2C0DECE20D4CB340057DC84 /* PageInfo.swift */, B2C0DECF20D4CB340057DC84 /* BookDetail.swift */, B2C0DED020D4CB340057DC84 /* BookShelf.swift */, + 3DE393E821A3B84600890488 /* BookShelf.json */, + 3DE393E621A3B7B600890488 /* ZSReadRecord.swift */, B2C0DED120D4CB340057DC84 /* QSRecomment.swift */, B2C0DED220D4CB340057DC84 /* ChapterInfo.json */, B2C0DED320D4CB340057DC84 /* QSPage.swift */, @@ -2501,6 +2510,7 @@ 3D3AB5DC214E99FE00E9C246 /* fz-wbt.ttf in Resources */, B2C0DF4620D4CB350057DC84 /* UserfulCell.xib in Resources */, B2B4BBEA1E7EA4AB000CC201 /* EmptyView.xib in Resources */, + 3DE393E921A3B84600890488 /* BookShelf.json in Resources */, B20D74091EED7D250034516F /* QSIntroduceCell.xib in Resources */, B2C0DF3B20D4CB350057DC84 /* ChapterInfo.json in Resources */, B2B4BC1D1E7EA4AB000CC201 /* ThemeTopicCell.xib in Resources */, @@ -2686,6 +2696,7 @@ B29CFB75217B1DAB0006F294 /* ZSAccount.swift in Sources */, 3DD0840B21569902008E3B4A /* Speaker.swift in Sources */, 3D65504D21957B410064BA0C /* ZSChapterSelectView.swift in Sources */, + 3DE393EB21A3EB2D00890488 /* ZSJSON.swift in Sources */, 3D9325EC20B2C9120049CDBF /* ZSHomeViewModel.swift in Sources */, B2A39C4A2110453100D6308E /* ZSLocalShelfViewModel.swift in Sources */, B2C0DF6120D4CB350057DC84 /* BookDetailViewController.swift in Sources */, @@ -2847,6 +2858,7 @@ B252D498210EF3960091858E /* DELETEResponse.m in Sources */, B2C0DF3520D4CB350057DC84 /* QSChapter.swift in Sources */, B2C0DF1D20D4CB350057DC84 /* QSMoreSettingController.swift in Sources */, + 3DE393E721A3B7B600890488 /* ZSReadRecord.swift in Sources */, B2B4BBF31E7EA4AB000CC201 /* Date+Extension.swift in Sources */, 3DDB6CA92130F4BC00E8698D /* CTFrameParser.m in Sources */, B2C0DF7D20D4CB6D0057DC84 /* QSBookCommentProtocols.swift in Sources */, diff --git a/zhuishushenqi/App/ZSDatabase.swift b/zhuishushenqi/App/ZSDatabase.swift index fd78fb2..2166d8e 100644 --- a/zhuishushenqi/App/ZSDatabase.swift +++ b/zhuishushenqi/App/ZSDatabase.swift @@ -93,6 +93,7 @@ struct ZSDatabase { func updateInfo(updateInfo:UpdateInfo) { let item = TABLE_LAMP.filter(TABLE_LAMP_BOOKID == (updateInfo._id ?? "")) + do { if try db.run(item.update(TABLE_LAMP_LAST_CHAPTER <- (updateInfo.lastChapter ?? ""), TABLE_LAMP_LAST_UPDATE_TIME <- (updateInfo.updated ?? ""))) > 0 { print("书籍\(String(describing: updateInfo._id)) 更新成功") diff --git a/zhuishushenqi/App/ZSJSON.swift b/zhuishushenqi/App/ZSJSON.swift new file mode 100644 index 0000000..d345c61 --- /dev/null +++ b/zhuishushenqi/App/ZSJSON.swift @@ -0,0 +1,57 @@ +// +// ZSJSON.swift +// zhuishushenqi +// +// Created by caony on 2018/11/20. +// Copyright © 2018 QS. All rights reserved. +// + +import UIKit + +protocol ZSJSON { + func toJSONModel() -> Any? +} + +extension ZSJSON { + func toJSONModel() -> Any? { + let mirror = Mirror(reflecting: self) + if mirror.children.count > 0 { + var result : [String:Any] = [:] + for children in mirror.children { + let propertyNameString = children.label! + let value = children.value + if let jsonValue = value as? ZSJSON { + result[propertyNameString] = jsonValue.toJSONModel() + } + } + return result + } + return self + } +} + +extension Optional : ZSJSON { + func toJSONModel() -> Any? { + if let x = self { + if let value = x as? ZSJSON { + return value.toJSONModel() + } + } + return nil + } +} + +extension String : ZSJSON {} +extension Int : ZSJSON {} +extension Bool : ZSJSON {} +extension CGFloat : ZSJSON {} +extension Float : ZSJSON {} +extension Double : ZSJSON {} +extension Dictionary : ZSJSON { + func encode(obj:Any) -> Any? { + let mirror = Mirror(reflecting: obj) + + return nil + } +} +extension Array : ZSJSON {} diff --git a/zhuishushenqi/Root/Controllers/ZSShelfViewController.swift b/zhuishushenqi/Root/Controllers/ZSShelfViewController.swift index c355c7e..4c15705 100644 --- a/zhuishushenqi/Root/Controllers/ZSShelfViewController.swift +++ b/zhuishushenqi/Root/Controllers/ZSShelfViewController.swift @@ -183,8 +183,8 @@ class ZSShelfViewController: BaseViewController,Refreshable,UITableViewDataSourc } return viewModel.books.count } -// return viewModel.fetchBooks().count - return viewModel.books.count + return viewModel.fetchBooks().count +// return viewModel.books.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { @@ -200,12 +200,12 @@ class ZSShelfViewController: BaseViewController,Refreshable,UITableViewDataSourc cell.configureCell(model: item) } } else { -// let book = viewModel.fetchBooks()[indexPath.row] -// cell.configureCell(model: book) - let id = viewModel.booksID[indexPath.row] - if let item = viewModel.books[id] { - cell.configureCell(model: item) - } + let book = viewModel.fetchBooks()[indexPath.row] + cell.configureCell(model: book) +// let id = viewModel.booksID[indexPath.row] +// if let item = viewModel.books[id] { +// cell.configureCell(model: item) +// } } return cell } @@ -272,18 +272,18 @@ class ZSShelfViewController: BaseViewController,Refreshable,UITableViewDataSourc return } } -// let books = viewModel.fetchBooks() -// let viewController = ZSReaderViewController() -// viewController.viewModel.book = books[indexPath.row] -// self.present(viewController, animated: true, completion: nil) -// self.tableView.reloadRow(at: indexPath, with: .automatic) - let books = self.viewModel.books - if let model = books[viewModel.booksID[indexPath.row]] { - let viewController = ZSReaderViewController() - viewController.viewModel.book = model - self.present(viewController, animated: true, completion: nil) - self.tableView.reloadRow(at: indexPath, with: .automatic) - } + let books = viewModel.fetchBooks() + let viewController = ZSReaderViewController() + viewController.viewModel.book = books[indexPath.row] + self.present(viewController, animated: true, completion: nil) + self.tableView.reloadRow(at: indexPath, with: .automatic) +// let books = self.viewModel.books +// if let model = books[viewModel.booksID[indexPath.row]] { +// let viewController = ZSReaderViewController() +// viewController.viewModel.book = model +// self.present(viewController, animated: true, completion: nil) +// self.tableView.reloadRow(at: indexPath, with: .automatic) +// } } } diff --git a/zhuishushenqi/Root/Service/ZSShelfWebService.swift b/zhuishushenqi/Root/Service/ZSShelfWebService.swift index ad109d2..a7d5225 100644 --- a/zhuishushenqi/Root/Service/ZSShelfWebService.swift +++ b/zhuishushenqi/Root/Service/ZSShelfWebService.swift @@ -30,6 +30,7 @@ class ZSShelfWebService: ZSBaseService { zs_get(shelfApi.path, parameters: shelfApi.parameters).responseJSON { (response) in if let data = response.data { if let obj = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as? [String:Any] { + if let message = ZSShelfMessage.deserialize(from: obj?["message"] as? [String:Any]) { completion?(message) } diff --git a/zhuishushenqi/Splash/QSSplashScreen.swift b/zhuishushenqi/Splash/QSSplashScreen.swift index dac6a20..258a349 100644 --- a/zhuishushenqi/Splash/QSSplashScreen.swift +++ b/zhuishushenqi/Splash/QSSplashScreen.swift @@ -15,7 +15,7 @@ typealias SplashCallback = ()->Void class QSSplashScreen: NSObject { - var splashInfo:NSDictionary? + var splashInfo:[String:Any] = [:] var subject:PublishSubject! private var splashRootVC:QSSplashViewController? private var remainDelay:Int = 3 @@ -50,24 +50,30 @@ class QSSplashScreen: NSObject { QSLog("info:\(String(describing: USER_DEFAULTS.object(forKey: splashInfoKey)))") // first check network, load image from disk,if not reachable if Reachability(hostname: IMAGE_BASEURL)?.isReachable == false { - let splashInfo = USER_DEFAULTS.object(forKey: splashInfoKey) as? NSDictionary - // image not exist,skip - // searchPah exchange everytime you run your app - let imageName = splashInfo?[splashImageNameKey] as? String ?? "" - let imagePath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first?.appending("/\(imageName)") ?? "" - let image = UIImage(contentsOfFile: imagePath) - if let splashImage = image{ - self.perform(#selector(self.showSplash), with: nil, afterDelay: 1.0) - self.splashRootVC?.setSplashImage(image: splashImage) - }else{ - hide() + if let data:Data = UserDefaults.value(forKey: splashInfoKey) as? Data { + if let json = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as? [String:Any] { + let splashInfo = json + // image not exist,skip + // searchPah exchange everytime you run your app + let imageName = splashInfo?[splashImageNameKey] as? String ?? "" + let imagePath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first?.appending("/\(imageName)") ?? "" + let image = UIImage(contentsOfFile: imagePath) + if let splashImage = image { + self.perform(#selector(self.showSplash), with: nil, afterDelay: 1.0) + self.splashRootVC?.setSplashImage(image: splashImage) + }else{ + hide() + } + } + } else { + hide() } return } // request splash image QSNetwork.request(splashURL) { (response) in - let splash = response.json?["splash"] as? [NSDictionary] + let splash = response.json?["splash"] as? [[String:Any]] if (splash?.count ?? 0) > 0{ if let splashInfo = splash?[0] { // save splash info,download image and save it @@ -87,10 +93,10 @@ class QSSplashScreen: NSObject { QSNetwork.download(urlString) { (fileURL, response, error) in QSLog("\(fileURL?.path ?? "")") let splashImage = UIImage(contentsOfFile: fileURL?.path ?? "") - let mutableInfo:NSMutableDictionary = NSMutableDictionary(dictionary: self.splashInfo!) - mutableInfo.setValue(fileURL?.lastPathComponent ?? "", forKey: self.splashImageNameKey) - self.splashInfo = mutableInfo - USER_DEFAULTS.set(self.splashInfo, forKey: self.splashInfoKey) + self.splashInfo[self.splashImageNameKey] = fileURL?.lastPathComponent ?? "" + if let data = try? JSONSerialization.data(withJSONObject: self.splashInfo, options: JSONSerialization.WritingOptions.prettyPrinted) { + USER_DEFAULTS.set(data, forKey: self.splashInfoKey) + } self.perform(#selector(self.showSplash), with: nil, afterDelay: 1.0) if let image = splashImage { self.splashRootVC?.setSplashImage(image: image) @@ -108,7 +114,7 @@ class QSSplashScreen: NSObject { func getSplashURLString()->String { //according to screen dimension - let imageString = self.splashInfo?.object(forKey: "img") as? String ?? "" + let imageString = self.splashInfo["img"] as? String ?? "" return imageString } diff --git a/zhuishushenqi/TXTReader/BookDetail/.DS_Store b/zhuishushenqi/TXTReader/BookDetail/.DS_Store index b64934bc619b03d8f40d6317f840fde867512e59..a3398b69f29658733bdccbe7054bad5bee0a70b3 100644 GIT binary patch delta 120 zcmZp1XfcprU|?W$DortDU=RQ@Ie-{Mvv5r;6q~50$jJ?o2Z>FdARxXmcMdZn_v99V z`I|Qj&0*YFbbxU&I|qj#Gf)u_2!Is3f;4X|{LVa?U&a$;6ay2)SddK&o8x)rFarSM CffP{y delta 628 zcmZoMXmOBWU|?W$DortDU;r^WfEYvza8E20o2aMAEe(2MruzmGF3-N|HL>Y=I6i1x6 zIt6GXR#iyO!Kq3B-DR6su*_%N?9a2GnM;BjXtFCP?Q9n0_|80;U&M2=KMw~7F!_Lz L6~pFuo;l0_oUn@k diff --git a/zhuishushenqi/TXTReader/BookDetail/Models/BookShelf.json b/zhuishushenqi/TXTReader/BookDetail/Models/BookShelf.json new file mode 100644 index 0000000..a18994a --- /dev/null +++ b/zhuishushenqi/TXTReader/BookDetail/Models/BookShelf.json @@ -0,0 +1,301 @@ +//https://api.zhuishushenqi.com/v3/user/bookshelf/diff +//post parameter +{ + "books": "5b10fd1b5d144d1b68581805,5b3d9ea93da83a5661317542,5ac49176ba32357ab6eee0a8,5bc0575df7634e0d9cb4a945,5bc99e7a279e1b0da1c9d033,5aa25094db70a41e4ae382db,53671112aa662d1b1500158f,566a0609469c97325459f068,582062e13ceeccd3472e25bd,56453ca255c88f8f5ba36792", + "token": "rPcCW1GGh1hFPnSRJDjkwjtS" +} +//result +{ + "books": [{ + "_id": "5b3d9ea93da83a5661317542", + "author": "武陵年少时", + "cover": "/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2666061%2F2666061_60168061004140809ffe57244218426a.jpg%2F", + "title": "兴汉室", + "buytype": 0, + "allowMonthly": false, + "allowVoucher": true, + "hasCp": true, + "referenceSource": "default", + "updated": "2018-11-19T07:16:52.387Z", + "chaptersCount": 355, + "lastChapter": "第354章 当务之急", + "created": "2018-11-07T02:38:11.681Z", + "_le": false, + "contentType": "txt", + "superscript": "", + "sizetype": -1, + "_mm": false, + "readRecord": {}, + "advertRead": true, + "_gg": false, + "expired": 0, + "_ss": false, + "modifyTime": "2018-11-19T07:16:52.388Z" + }, { + "_id": "5bc0575df7634e0d9cb4a945", + "author": "耳东大树", + "cover": "/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F3316557%2F3316557_7253fb8192ef4062868cab38b6280ee3.jpg%2F", + "title": "穿越血色浪漫", + "buytype": 0, + "allowMonthly": false, + "allowVoucher": true, + "hasCp": true, + "referenceSource": "default", + "updated": "2018-11-19T14:54:22.784Z", + "chaptersCount": 94, + "lastChapter": "正文卷 第八十九章:七个和尚", + "created": "2018-11-02T11:46:23.917Z", + "_le": true, + "contentType": "txt", + "superscript": "", + "sizetype": -1, + "_mm": false, + "readRecord": { + "tocId": "5bc0575df7634e0d9cb4a947", + "tocName": "zhuishuvip", + "title": "正文卷 第一章:回到从前", + "order": 0, + "wordIndex": 0, + "updated": "2018-11-08T03:17:19.352Z", + "book": "5bc0575df7634e0d9cb4a945" + }, + "advertRead": true, + "_gg": false, + "expired": 0, + "_ss": false, + "modifyTime": "2018-11-19T14:54:22.784Z" + }, { + "_id": "5bc99e7a279e1b0da1c9d033", + "author": "七十二七", + "cover": "/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F3320834%2F3320834_12bd79f8270a447da24e498ef63ff626.jpg%2F", + "title": "从金黄市走出的训练家", + "buytype": 0, + "allowMonthly": false, + "allowVoucher": true, + "hasCp": true, + "referenceSource": "default", + "updated": "2018-11-19T02:04:22.369Z", + "chaptersCount": 66, + "lastChapter": "正文卷 第六十四章【请求,想法】", + "created": "2018-10-28T05:24:58.141Z", + "_le": true, + "contentType": "txt", + "superscript": "", + "sizetype": -1, + "_mm": false, + "readRecord": {}, + "advertRead": true, + "_gg": false, + "expired": 0, + "_ss": false, + "modifyTime": "2018-11-19T02:04:22.369Z" + }, { + "_id": "53671112aa662d1b1500158f", + "author": "六如和尚", + "cover": "/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F682805%2F682805_ad98924f53e74138a50e69208bd579be.png%2F", + "title": "偷香高手", + "buytype": 0, + "allowMonthly": true, + "allowVoucher": true, + "hasCp": true, + "referenceSource": "sogou", + "updated": "2018-11-19T08:55:53.443Z", + "chaptersCount": 1930, + "lastChapter": "第十卷 大宗师的黄昏 第1930章 灭顶之灾", + "created": "2018-10-27T07:10:56.442Z", + "_le": true, + "contentType": "txt", + "superscript": "", + "sizetype": -1, + "_mm": false, + "readRecord": {}, + "advertRead": true, + "_gg": false, + "expired": 0, + "_ss": false, + "modifyTime": "2018-11-19T08:55:53.443Z" + }, { + "_id": "582062e13ceeccd3472e25bd", + "author": "榕之子", + "cover": "/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1391972%2F1391972_9fa6b0bbdea0407c84a2414df247719b.jpg%2F", + "title": "造车", + "buytype": 2, + "allowMonthly": false, + "allowVoucher": true, + "hasCp": true, + "referenceSource": "default", + "updated": "2018-11-19T14:27:52.687Z", + "chaptersCount": 570, + "lastChapter": "第四卷 第一百十九章 投资考评", + "created": "2018-10-27T07:10:56.442Z", + "_le": false, + "contentType": "txt", + "superscript": "", + "sizetype": -1, + "_mm": false, + "readRecord": { + "tocId": "586387bc7280161d1eabdbd2", + "tocName": "zhuishuvip", + "title": "第1章 天王山之战", + "order": 0, + "wordIndex": 0, + "updated": "2018-11-06T06:51:48.573Z", + "book": "582062e13ceeccd3472e25bd" + }, + "advertRead": true, + "_gg": false, + "expired": 0, + "_ss": false, + "modifyTime": "2018-11-19T14:27:52.687Z" + }, { + "_id": "56453ca255c88f8f5ba36792", + "author": "堂皇的荒唐", + "cover": "/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F902768%2F902768_9bed914fcccd4b48b55f29e7057cb922.jpg%2F", + "title": "重生之电子风云", + "buytype": 2, + "allowMonthly": false, + "allowVoucher": true, + "hasCp": true, + "referenceSource": "default", + "updated": "2018-11-16T12:20:52.277Z", + "chaptersCount": 593, + "lastChapter": "第六卷 第598章 贫富两重天", + "created": "2018-10-27T07:10:56.442Z", + "_le": false, + "contentType": "txt", + "superscript": "", + "sizetype": -1, + "_mm": false, + "readRecord": {}, + "advertRead": true, + "_gg": false, + "expired": 0, + "_ss": false, + "modifyTime": "2018-11-16T12:20:52.277Z" + }, { + "_id": "566a0609469c97325459f068", + "author": "机器人布里茨", + "cover": "/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F856493%2F856493_6d3a8091bc294345abeed36e26c002a4.jpg%2F", + "title": "英雄联盟之决胜巅峰", + "buytype": 2, + "allowMonthly": false, + "allowVoucher": true, + "hasCp": true, + "referenceSource": "default", + "updated": "2018-11-19T09:26:52.699Z", + "chaptersCount": 2634, + "lastChapter": "第一千八百二十七章 拭目以待", + "created": "2018-08-19T06:38:45.490Z", + "_le": false, + "contentType": "txt", + "superscript": "", + "sizetype": -1, + "_mm": false, + "readRecord": {}, + "advertRead": true, + "_gg": false, + "expired": 0, + "_ss": false, + "modifyTime": "2018-11-19T09:26:52.699Z" + }, { + "_id": "5b10fd1b5d144d1b68581805", + "author": "林海听涛", + "cover": "/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2379309%2F2379309_eccf51f45dc14c079be9a399120b6da7.jpg%2F", + "title": "绿茵峥嵘", + "buytype": 0, + "allowMonthly": false, + "allowVoucher": true, + "hasCp": true, + "referenceSource": "default", + "updated": "2018-11-20T00:16:22.491Z", + "chaptersCount": 327, + "lastChapter": "正文卷 第三百二十五章 回敬他们", + "created": "2018-08-14T03:24:47.173Z", + "_le": false, + "contentType": "txt", + "superscript": "", + "sizetype": -1, + "_mm": false, + "readRecord": { + "tocId": "5b10fd1b5d144d1b68581807", + "tocName": "vip.zhuishushenqi.com", + "title": "正文卷 第三百一十七章 破密集防守的第三种方法", + "order": 318, + "wordIndex": 8, + "updated": "2018-11-18T10:18:48.631Z", + "book": "5b10fd1b5d144d1b68581805" + }, + "advertRead": true, + "_gg": false, + "expired": 0, + "_ss": false, + "modifyTime": "2018-11-20T00:16:22.491Z" + }, { + "_id": "5aa25094db70a41e4ae382db", + "author": "新海月1", + "cover": "/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2243833%2F2243833_4a67e416d2e1485987ed9825bc347a4a_default_cover.png%2F", + "title": "保加利亚帝国", + "buytype": 0, + "allowMonthly": false, + "allowVoucher": true, + "hasCp": true, + "referenceSource": "default", + "updated": "2018-11-19T13:59:22.613Z", + "chaptersCount": 499, + "lastChapter": "第六卷、新的时代 六十六章、同化——犹太人?", + "created": "2018-08-14T03:24:47.173Z", + "_le": true, + "contentType": "txt", + "superscript": "", + "sizetype": -1, + "_mm": false, + "readRecord": { + "tocId": "5acb131ee36bd0e811d270c5", + "tocName": "mix", + "title": "无畏舰时代 第五章、汽车工业的发展", + "order": 268, + "wordIndex": 4486, + "updated": "2018-11-08T07:30:11.636Z", + "book": "5aa25094db70a41e4ae382db" + }, + "advertRead": true, + "_gg": false, + "expired": 0, + "_ss": false, + "modifyTime": "2018-11-19T13:59:22.613Z" + }, { + "_id": "5ac49176ba32357ab6eee0a8", + "author": "仲渊2", + "cover": "/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2266163%2F2266163_7ffd0ca6a6544f5f90a557478d325ef3.jpg%2F", + "title": "鹰掠九天", + "buytype": 0, + "allowMonthly": false, + "allowVoucher": true, + "hasCp": true, + "referenceSource": "default", + "updated": "2018-11-19T16:24:22.245Z", + "chaptersCount": 737, + "lastChapter": "正文卷 第七百四十七章 训练科目,电磁弹射!", + "created": "2018-08-14T03:24:47.173Z", + "_le": false, + "contentType": "txt", + "superscript": "", + "sizetype": -1, + "_mm": false, + "readRecord": { + "tocId": "5ac49176ba32357ab6eee0aa", + "tocName": "zhuishuvip", + "title": "第1章 生日和除夕。", + "order": 0, + "wordIndex": 0, + "updated": "2018-11-02T16:20:33.620Z", + "book": "5ac49176ba32357ab6eee0a8" + }, + "advertRead": true, + "_gg": false, + "expired": 0, + "_ss": false, + "modifyTime": "2018-11-19T16:24:22.245Z" + }], + "ok": true +} diff --git a/zhuishushenqi/TXTReader/BookDetail/Models/BookShelf.swift b/zhuishushenqi/TXTReader/BookDetail/Models/BookShelf.swift index ce3a008..b74541b 100644 --- a/zhuishushenqi/TXTReader/BookDetail/Models/BookShelf.swift +++ b/zhuishushenqi/TXTReader/BookDetail/Models/BookShelf.swift @@ -7,9 +7,10 @@ // import UIKit +import HandyJSON @objc(BookShelf) -class BookShelf: NSObject { +class BookShelf: NSObject, HandyJSON { var _id:String? var title:String? var author:String? @@ -17,7 +18,12 @@ class BookShelf: NSObject { var allowMonthly:Bool? var allowVoucher:Bool? var updated:String? - var chaptersCount:NSNumber? + var chaptersCount:Int? var lastChapter:String? + var referenceSource:String? + var readRecord:ZSReadRecord? + var modifyTime:String? + required override init() {} } + diff --git a/zhuishushenqi/TXTReader/BookDetail/Models/ZSReadRecord.swift b/zhuishushenqi/TXTReader/BookDetail/Models/ZSReadRecord.swift new file mode 100644 index 0000000..a6f82a8 --- /dev/null +++ b/zhuishushenqi/TXTReader/BookDetail/Models/ZSReadRecord.swift @@ -0,0 +1,22 @@ +// +// ZSReadRecord.swift +// zhuishushenqi +// +// Created by caony on 2018/11/20. +// Copyright © 2018 QS. All rights reserved. +// + +import UIKit +import HandyJSON + +class ZSReadRecord: NSObject, HandyJSON { + var tocId:String? + var tocName:String? + var title:String? + var order:Int? + var wordIndex:Int? + var updated:String? + var book:String? + + required override init() {} +} From 3f5d3ee2b6d3ea1a84ca59715ab82955d9d53531 Mon Sep 17 00:00:00 2001 From: caonongyun Date: Mon, 26 Nov 2018 09:00:55 +0800 Subject: [PATCH 02/19] dev_db --- zhuishushenqi.xcodeproj/project.pbxproj | 12 + zhuishushenqi/App/AppDelegate.swift | 9 + zhuishushenqi/App/ZSDBManager.h | 29 +++ zhuishushenqi/App/ZSDBManager.m | 256 ++++++++++++++++++++ zhuishushenqi/App/ZSDBPropertyModel.h | 20 ++ zhuishushenqi/App/ZSDBPropertyModel.m | 13 + zhuishushenqi/Root/Models/QSHotModel.swift | 54 +++++ zhuishushenqi/zhuishushenqi-Bridge-Header.h | 1 + 8 files changed, 394 insertions(+) create mode 100644 zhuishushenqi/App/ZSDBManager.h create mode 100644 zhuishushenqi/App/ZSDBManager.m create mode 100644 zhuishushenqi/App/ZSDBPropertyModel.h create mode 100644 zhuishushenqi/App/ZSDBPropertyModel.m diff --git a/zhuishushenqi.xcodeproj/project.pbxproj b/zhuishushenqi.xcodeproj/project.pbxproj index d03e022..8143f21 100644 --- a/zhuishushenqi.xcodeproj/project.pbxproj +++ b/zhuishushenqi.xcodeproj/project.pbxproj @@ -202,6 +202,8 @@ B26286CA1EEA46DD005A1A8A /* QSIntroducePage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B26286C91EEA46DD005A1A8A /* QSIntroducePage.swift */; }; B263ACDF1EE679830096CE80 /* HomeListViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B263ACDD1EE679830096CE80 /* HomeListViewCell.swift */; }; B263E2E9211EBFEC001819FB /* SQLite+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B263E2E8211EBFEC001819FB /* SQLite+Extension.swift */; }; + B2662EBC21A7DAC5008AD5C6 /* ZSDBPropertyModel.m in Sources */ = {isa = PBXBuildFile; fileRef = B2662EBB21A7DAC5008AD5C6 /* ZSDBPropertyModel.m */; }; + B266C66A21A6FCC3006B5A15 /* ZSDBManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B266C66921A6FCC3006B5A15 /* ZSDBManager.m */; }; B278AA661F3954FF000A0D55 /* QSAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = B278AA651F3954FF000A0D55 /* QSAPI.swift */; }; B278AA8C1F395F30000A0D55 /* LookBookViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B278AA8A1F395F30000A0D55 /* LookBookViewController.swift */; }; B278AA8D1F395F30000A0D55 /* ReadHistoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B278AA8B1F395F30000A0D55 /* ReadHistoryViewController.swift */; }; @@ -711,6 +713,10 @@ B26286C91EEA46DD005A1A8A /* QSIntroducePage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QSIntroducePage.swift; sourceTree = ""; }; B263ACDD1EE679830096CE80 /* HomeListViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeListViewCell.swift; sourceTree = ""; }; B263E2E8211EBFEC001819FB /* SQLite+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SQLite+Extension.swift"; sourceTree = ""; }; + B2662EBA21A7DAC5008AD5C6 /* ZSDBPropertyModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ZSDBPropertyModel.h; sourceTree = ""; }; + B2662EBB21A7DAC5008AD5C6 /* ZSDBPropertyModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZSDBPropertyModel.m; sourceTree = ""; }; + B266C66821A6FCC3006B5A15 /* ZSDBManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ZSDBManager.h; sourceTree = ""; }; + B266C66921A6FCC3006B5A15 /* ZSDBManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZSDBManager.m; sourceTree = ""; }; B278AA651F3954FF000A0D55 /* QSAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QSAPI.swift; sourceTree = ""; }; B278AA8A1F395F30000A0D55 /* LookBookViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LookBookViewController.swift; sourceTree = ""; }; B278AA8B1F395F30000A0D55 /* ReadHistoryViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadHistoryViewController.swift; sourceTree = ""; }; @@ -1418,6 +1424,10 @@ B25EB92E2194999E000D3657 /* FBEncryptorAESUtils.m */, B25EB93021949AF1000D3657 /* FBEncryptorAES.h */, B25EB93121949AF1000D3657 /* FBEncryptorAES.m */, + B266C66821A6FCC3006B5A15 /* ZSDBManager.h */, + B266C66921A6FCC3006B5A15 /* ZSDBManager.m */, + B2662EBA21A7DAC5008AD5C6 /* ZSDBPropertyModel.h */, + B2662EBB21A7DAC5008AD5C6 /* ZSDBPropertyModel.m */, ); path = App; sourceTree = ""; @@ -2708,6 +2718,7 @@ B2414D9C1EA602ED005A5758 /* UIViewController+Alert.swift in Sources */, 3D2B4D0520EB6552008E3E81 /* ZSNoneAnimationViewController.swift in Sources */, B252D48C210EF3960091858E /* HTTPMessage.m in Sources */, + B266C66A21A6FCC3006B5A15 /* ZSDBManager.m in Sources */, B2C0DF6820D4CB350057DC84 /* QSCategoryReaderViewController.swift in Sources */, B2B4BBE41E7EA4AB000CC201 /* CommunityView.swift in Sources */, B2C0DF7C20D4CB6D0057DC84 /* QSBookCommentRouter.swift in Sources */, @@ -2826,6 +2837,7 @@ B2C0DF1C20D4CB350057DC84 /* QSTextRouter.swift in Sources */, B25EB93521949C0F000D3657 /* NSData+Base64.m in Sources */, B29B4F9F1E822992008852E3 /* QSHotModel.swift in Sources */, + B2662EBC21A7DAC5008AD5C6 /* ZSDBPropertyModel.m in Sources */, 3D5671FC2174CADD0049B2FF /* ZSBookCTLayoutModel.swift in Sources */, B2E072781F3AD99500C63347 /* Reader.swift in Sources */, B2C0DF2720D4CB350057DC84 /* UpdateInfo.swift in Sources */, diff --git a/zhuishushenqi/App/AppDelegate.swift b/zhuishushenqi/App/AppDelegate.swift index 6b256af..4e00d15 100644 --- a/zhuishushenqi/App/AppDelegate.swift +++ b/zhuishushenqi/App/AppDelegate.swift @@ -98,6 +98,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate { let books = database.queryBookshelf() QSLog("books:\(books)") + let testModel = ZSDBTestModel() + let subModel = ZSDBTestSubModel() + subModel.key = "IU6rIl2d2GWnEio" + testModel.id = "Yg5fsKPOvpii0qAH2lpmJhjFmRhfe4dshhjY5Oim2Y" + testModel.num = 1 + testModel.subModel = subModel + + ZSDBManager.share()?.getPropertys(testModel) + let cpContent = "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" let str = FBEncryptorAESUtils.getDecryptedStr(withKey: "inTv0kKl4pI1BMk2munvAg==", cipherText: cpContent) diff --git a/zhuishushenqi/App/ZSDBManager.h b/zhuishushenqi/App/ZSDBManager.h new file mode 100644 index 0000000..855749d --- /dev/null +++ b/zhuishushenqi/App/ZSDBManager.h @@ -0,0 +1,29 @@ +// +// ZSDBManager.h +// zhuishushenqi +// +// Created by caonongyun on 2018/11/22. +// Copyright © 2018年 QS. All rights reserved. +// + +#import +#import "ZSDBPropertyModel.h" + +@protocol ZSDBModel + +- (NSString *)tableName; +- (NSString *)primaryKey; +- (NSString *)foreignKey; +- (NSDictionary *)dbColumnMapping; +- (NSArray *)ignoredKeys; + +@end + +@interface ZSDBManager : NSObject + ++ (instancetype)share; + +- (NSArray *)getPropertys:(NSObject *)model; + +@end + diff --git a/zhuishushenqi/App/ZSDBManager.m b/zhuishushenqi/App/ZSDBManager.m new file mode 100644 index 0000000..6122d93 --- /dev/null +++ b/zhuishushenqi/App/ZSDBManager.m @@ -0,0 +1,256 @@ +// +// ZSDBManager.m +// zhuishushenqi +// +// Created by caonongyun on 2018/11/22. +// Copyright © 2018年 QS. All rights reserved. +// + +#import "ZSDBManager.h" +#import +#import + +/** SQLite五种数据类型 */ +#define SQLTEXT @"TEXT" +#define SQLINTEGER @"INTEGER" +#define SQLREAL @"REAL" +#define SQLBLOB @"BLOB" +#define SQLNULL @"NULL" +#define PrimaryKey @"primary key" + +#define primaryId @"pk" + +@interface ZSDBManager () + +@property (nonatomic, strong) FMDatabaseQueue *dbQueue; + +@end + +@implementation ZSDBManager + ++ (instancetype)share { + static ZSDBManager *share = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + share = [[ZSDBManager alloc] init]; + }); + return share; +} + +- (BOOL)isTableExist:(NSObject *)model { + __block BOOL res = NO; + [self.dbQueue inDatabase:^(FMDatabase *db) { + NSString *tableName = [model tableName]; + res = [db tableExists:tableName]; + }]; + return res; +} + +- (NSArray *)getColumnsFrom:(NSObject *)model { + NSMutableArray *columns = [NSMutableArray array]; + [self.dbQueue inDatabase:^(FMDatabase *db) { + NSString *tableName = NSStringFromClass(self.class); + FMResultSet *resultSet = [db getTableSchema:tableName]; + while ([resultSet next]) { + NSString *column = [resultSet stringForColumn:@"name"]; + [columns addObject:column]; + } + }]; + return [columns copy]; +} + ++ (NSString *)getColumnAndTypeString:(NSArray *)models { + NSMutableString *pars = [NSMutableString string]; + for (ZSDBPropertyModel *model in models) { + if (![model.type isEqualToString:NSStringFromProtocol(@protocol(ZSDBModel))]) { + if (model.mappingKey) { + [pars appendString:model.mappingKey]; + } else { + [pars appendString:model.originalKey]; + } + [pars appendString:model.type]; + NSInteger count = [models indexOfObject:model]; + if (count != models.count - 1) { + [pars appendString:@","]; + } + } + } + return pars; +} + ++ (BOOL)createTable:(NSObject *)model +{ + __block BOOL res = YES; + [ZSDBManager.share.dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) { + NSString *tableName = [model tableName]; + NSArray * propertys = [[ZSDBManager share]getPropertys:model]; + NSString *columeAndType = [self.class getColumnAndTypeString:propertys]; + NSString *sql = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@(%@);",tableName,columeAndType]; + if (![db executeUpdate:sql]) { + res = NO; + *rollback = YES; + return; + }; + + NSMutableArray *columns = [NSMutableArray array]; + FMResultSet *resultSet = [db getTableSchema:tableName]; + while ([resultSet next]) { + NSString *column = [resultSet stringForColumn:@"name"]; + [columns addObject:column]; + } + NSMutableArray *propertyStrings = @[].mutableCopy; + for (ZSDBPropertyModel *model in propertys) { + if (model.mappingKey) { + [propertyStrings addObject:model.mappingKey]; + } else { + [propertyStrings addObject:model.originalKey]; + } + } + + NSPredicate *filterPredicate = [NSPredicate predicateWithFormat:@"NOT (SELF IN %@)",columns]; + //过滤数组 + NSArray *resultArray = [propertyStrings filteredArrayUsingPredicate:filterPredicate]; + for (NSString *column in resultArray) { + NSUInteger index = [propertyStrings indexOfObject:column]; + NSString *proType = [[propertys objectAtIndex:index] type]; + if (![proType isEqualToString:NSStringFromProtocol(@protocol(ZSDBModel))]) { + NSString *fieldSql = [NSString stringWithFormat:@"%@ %@",column,proType]; + NSString *sql = [NSString stringWithFormat:@"ALTER TABLE %@ ADD COLUMN %@ ",[model tableName],fieldSql]; + if (![db executeUpdate:sql]) { + res = NO; + *rollback = YES; + return ; + } + } + } + }]; + + return res; +} + +//- (BOOL)saveOrUpdate:(NSObject *)model { +// NSString *primaryKey = [model primaryKey]; +// id primaryValue = [model valueForKey:primaryKey]; +// if ([primaryValue intValue] <= 0) { +// return [self save]; +// } +// return [self update]; +//} + +- (NSArray *)queryAll:(NSObject *)model { + NSLog(@"ZSDBModel---%s",__func__); + NSMutableArray *models = [NSMutableArray array]; + [self.dbQueue inDatabase:^(FMDatabase * _Nonnull db) { + NSString *tableName = [model tableName]; + NSString *sql = [NSString stringWithFormat:@"SELECT * FROM %@",tableName]; + FMResultSet *resultSet = [db executeQuery:sql]; + while ([resultSet next]) { + + } + }]; + return models; +} + +- (NSArray *)getPropertys:(NSObject *)model { + NSString *foreignKey; + NSString *primaryKey; + NSDictionary *mapping; + NSArray *ignoredKeys; + mapping = [model dbColumnMapping]; + primaryKey = [model primaryKey]; + foreignKey = [model foreignKey]; + ignoredKeys = [model ignoredKeys]; + NSMutableArray *propertys = @[].mutableCopy; + unsigned int outCount, i; + objc_property_t *properties = class_copyPropertyList([model class], &outCount); + for (i = 0; i < outCount; i++) { + objc_property_t property = properties[i]; + //获取属性名 + NSString *propertyName = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding]; + // 如果在忽略列表中,不处理 + if ([ignoredKeys containsObject:propertyName]) { + continue; + } + id propertyValue = [model valueForKey:propertyName]; + ZSDBPropertyModel *propertyModel = [[ZSDBPropertyModel alloc] init]; + propertyModel.originalKey = propertyName; + propertyModel.value = propertyValue; + + if (mapping[propertyName]) { + propertyModel.mappingKey = mapping[propertyName]; + } + if ([propertyName isEqualToString:primaryKey]) { + propertyModel.isPrimaryKey = YES; + } else { + propertyModel.isPrimaryKey = NO; + } + + if ([propertyValue conformsToProtocol:@protocol(ZSDBModel)]) { + propertyModel.type = [NSString stringWithFormat:@"%@",@protocol(ZSDBModel)]; + propertyModel.value = [self getPropertys:propertyValue]; + continue; + } + //获取属性类型等参数 + NSString *propertyType = [NSString stringWithCString: property_getAttributes(property) encoding:NSUTF8StringEncoding]; + /* + 各种符号对应类型,部分类型在新版SDK中有所变化,如long 和long long + c char C unsigned char + i int I unsigned int + l long L unsigned long + s short S unsigned short + d double D unsigned double + f float F unsigned float + q long long Q unsigned long long + B BOOL + @ 对象类型 //指针 对象类型 如NSString 是@“NSString” + + + 64位下long 和long long 都是Tq + SQLite 默认支持五种数据类型TEXT、INTEGER、REAL、BLOB、NULL + 因为在项目中用的类型不多,故只考虑了少数类型 + */ + if ([propertyType hasPrefix:@"T@\"NSString\""]) { + propertyModel.type = SQLTEXT; + } else if ([propertyType hasPrefix:@"T@\"NSData\""]) { + propertyModel.type = SQLBLOB; + } else if ([propertyType hasPrefix:@"Ti"]||[propertyType hasPrefix:@"TI"]||[propertyType hasPrefix:@"Ts"]||[propertyType hasPrefix:@"TS"]||[propertyType hasPrefix:@"TB"]||[propertyType hasPrefix:@"Tq"]||[propertyType hasPrefix:@"TQ"] || [propertyType hasPrefix:@"T@\"NSNumber\""]) { + propertyModel.type = SQLINTEGER; + } else { + propertyModel.type = SQLREAL; + } + } + return propertys; +} + ++ (NSString *)dbPathWithDirectoryName:(NSString *)directoryName +{ + NSString *docsdir = [NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSFileManager *filemanage = [NSFileManager defaultManager]; + if (directoryName == nil || directoryName.length == 0) { + docsdir = [docsdir stringByAppendingPathComponent:@"zhuishushenqi"]; + } else { + docsdir = [docsdir stringByAppendingPathComponent:directoryName]; + } + BOOL isDir; + BOOL exit =[filemanage fileExistsAtPath:docsdir isDirectory:&isDir]; + if (!exit || !isDir) { + [filemanage createDirectoryAtPath:docsdir withIntermediateDirectories:YES attributes:nil error:nil]; + } + NSString *dbpath = [docsdir stringByAppendingPathComponent:@"zssq.sqlite"]; + return dbpath; +} + ++ (NSString *)dbPath +{ + return [self dbPathWithDirectoryName:nil]; +} + +- (FMDatabaseQueue *)dbQueue +{ + if (_dbQueue == nil) { + _dbQueue = [[FMDatabaseQueue alloc] initWithPath:[self.class dbPath]]; + } + return _dbQueue; +} + +@end diff --git a/zhuishushenqi/App/ZSDBPropertyModel.h b/zhuishushenqi/App/ZSDBPropertyModel.h new file mode 100644 index 0000000..9372245 --- /dev/null +++ b/zhuishushenqi/App/ZSDBPropertyModel.h @@ -0,0 +1,20 @@ +// +// ZSDBPropertyModel.h +// zhuishushenqi +// +// Created by caonongyun on 2018/11/23. +// Copyright © 2018年 QS. All rights reserved. +// + +#import + +@interface ZSDBPropertyModel : NSObject + +@property (nonatomic, copy) NSString *originalKey; +@property (nonatomic, copy) NSString *mappingKey; +@property (nonatomic, strong) id value; +@property (nonatomic, copy) NSString *type; +@property (nonatomic, assign) BOOL isPrimaryKey; + +@end + diff --git a/zhuishushenqi/App/ZSDBPropertyModel.m b/zhuishushenqi/App/ZSDBPropertyModel.m new file mode 100644 index 0000000..ab7fc8b --- /dev/null +++ b/zhuishushenqi/App/ZSDBPropertyModel.m @@ -0,0 +1,13 @@ +// +// ZSDBPropertyModel.m +// zhuishushenqi +// +// Created by caonongyun on 2018/11/23. +// Copyright © 2018年 QS. All rights reserved. +// + +#import "ZSDBPropertyModel.h" + +@implementation ZSDBPropertyModel + +@end diff --git a/zhuishushenqi/Root/Models/QSHotModel.swift b/zhuishushenqi/Root/Models/QSHotModel.swift index 0da5912..87e6927 100644 --- a/zhuishushenqi/Root/Models/QSHotModel.swift +++ b/zhuishushenqi/Root/Models/QSHotModel.swift @@ -53,6 +53,60 @@ class QSHotTweet: NSObject ,HandyJSON{ } } +@objcMembers +class ZSDBTestModel:NSObject, ZSDBModel { + + var id:String? + var num:Int = 0 + var data:Data? + var subModel:ZSDBTestSubModel? + + func tableName() -> String! { + return "bookshelf" + } + + func primaryKey() -> String! { + return "" + } + + func foreignKey() -> String! { + return "" + } + + func dbColumnMapping() -> [String : String]! { + return [:] + } + + func ignoredKeys() -> [String]! { + return [] + } +} + +@objcMembers +class ZSDBTestSubModel:NSObject, ZSDBModel { + @objc dynamic var key:String? + + func tableName() -> String! { + return "record" + } + + func primaryKey() -> String! { + return "" + } + + func foreignKey() -> String! { + return "" + } + + func dbColumnMapping() -> [String : String]! { + return [:] + } + + func ignoredKeys() -> [String]! { + return [] + } +} + //{ // "user": { // "_id": "56ada4e2c911b9455cedeaee", diff --git a/zhuishushenqi/zhuishushenqi-Bridge-Header.h b/zhuishushenqi/zhuishushenqi-Bridge-Header.h index b4bd510..f77c4b8 100644 --- a/zhuishushenqi/zhuishushenqi-Bridge-Header.h +++ b/zhuishushenqi/zhuishushenqi-Bridge-Header.h @@ -34,5 +34,6 @@ #import "WechatAuthSDK.h" #import "WeiboSDK.h" #import "FBEncryptorAESUtils.h" +#import "ZSDBManager.h" #endif /* zhuishushenqi_Bridge_Header_h */ From d576355120eb7bdecebe7e9d28808753ed208556 Mon Sep 17 00:00:00 2001 From: caonongyun Date: Wed, 28 Nov 2018 16:13:01 +0800 Subject: [PATCH 03/19] db --- zhuishushenqi/App/ZSDBManager.m | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/zhuishushenqi/App/ZSDBManager.m b/zhuishushenqi/App/ZSDBManager.m index 6122d93..e021996 100644 --- a/zhuishushenqi/App/ZSDBManager.m +++ b/zhuishushenqi/App/ZSDBManager.m @@ -145,7 +145,24 @@ - (NSArray *)queryAll:(NSObject *)model { NSString *sql = [NSString stringWithFormat:@"SELECT * FROM %@",tableName]; FMResultSet *resultSet = [db executeQuery:sql]; while ([resultSet next]) { - + Class modelClass = [model class]; + NSObject *queryModel = [[modelClass alloc] init]; + NSArray *columns = [self getPropertys:queryModel]; + for (NSInteger i = 0; i< columns.count; i++) { + NSString *columnName = columns[i].mappingKey ? columns[i].mappingKey:columns[i].originalKey; + NSString *columnType = columns[i].type; + if ([columnType isEqualToString:SQLTEXT]) { + [queryModel setValue:[resultSet stringForColumn:columnName] forKey:columnName]; + } else if ([columnType isEqualToString:SQLBLOB]) { + [queryModel setValue:[resultSet dataForColumn:columnName] forKey:columnName]; + } else if ([columnName isEqualToString:NSStringFromProtocol(@protocol(ZSDBModel))]) { + + } else { + [queryModel setValue:[NSNumber numberWithLongLong:[resultSet longLongIntForColumn:columnName]] forKey:columnName]; + } + } + [models addObject:queryModel]; + FMDBRelease(queryModel); } }]; return models; From 2a03f20c5fc765a73ad51616bc01d11280066c3e Mon Sep 17 00:00:00 2001 From: caonongyun Date: Thu, 3 Jan 2019 00:41:48 +0800 Subject: [PATCH 04/19] =?UTF-8?q?=E4=B9=A6=E6=9E=B6=E5=88=B7=E6=96=B0?= =?UTF-8?q?=E5=8D=A1=E9=A1=BF=E9=97=AE=E9=A2=98=E4=BF=AE=E5=A4=8D&?= =?UTF-8?q?=E9=98=85=E8=AF=BB=E8=BF=87=E7=9A=84=E4=B9=A6=E7=B1=8D=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E7=BD=AE=E9=A1=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zhuishushenqi/App/BookManager.swift | 36 +-- zhuishushenqi/App/ZSDBManager.m | 285 +++++++++++++++++- zhuishushenqi/App/ZSDatabase.swift | 2 +- zhuishushenqi/Client/QSAPI.swift | 9 + zhuishushenqi/Extension/NSDate+Date.m | 19 +- .../RootViewController+FetchData.swift | 2 +- .../Controllers/ZSShelfViewController.swift | 42 +-- .../Root/Service/ZSRootWebService.swift | 4 +- .../Root/Service/ZSShelfWebService.swift | 6 +- .../Root/ViewModel/ZSShelfViewModel.swift | 19 +- .../BookDetail/Models/BookDetail.swift | 4 +- .../BookDetail/Models/BookShelf.swift | 86 +++++- .../BookDetail/Models/ZSReadRecord.swift | 27 +- 13 files changed, 477 insertions(+), 64 deletions(-) diff --git a/zhuishushenqi/App/BookManager.swift b/zhuishushenqi/App/BookManager.swift index 81fdab7..f171a26 100644 --- a/zhuishushenqi/App/BookManager.swift +++ b/zhuishushenqi/App/BookManager.swift @@ -40,7 +40,7 @@ public class ZSBookManager:NSObject { return booksInfo } set { - saveBooks(books: newValue) +// saveBooks(books: newValue) } } @@ -86,7 +86,7 @@ public class ZSBookManager:NSObject { self.books.removeValue(forKey: book._id) } - func update(updateInfo:[UpdateInfo]) { + func update(updateInfo:[BookShelf]) { for update in updateInfo { if let book = self.books[update._id ?? ""] { if let updateStr = update.updated { @@ -96,6 +96,7 @@ public class ZSBookManager:NSObject { } book.updateInfo = update self.updateBook(book: book) + } } } @@ -108,32 +109,23 @@ public class ZSBookManager:NSObject { } QSLog("\(book.title)更新成功") self.books[book._id] = book + self.saveBooks(book:book) } //MARK: - books // 保存书籍信息 - fileprivate func saveBooks(books:[String:BookDetail]) { -// var change:Bool = false -// if books.count == ZSBookManager._books.count { -// for (id,book) in books { -// let boook = ZSBookManager._books[id] -// if book.record?.chapter != boook?.record?.chapter || book.record?.page != boook?.record?.page { -// change = true -// } -// } -// if !change { -// return -// } -// } + fileprivate func saveBooks(book:BookDetail) { ZSBookManager._books = books - for book in books { + // 只更新这本书,防止多次重复无用更新 + ZSBookManager.calTime { let path = NSHomeDirectory().appending("/Documents/ZSBookShelf/Books") - let data = NSKeyedArchiver.archivedData(withRootObject: book.value) + let data = NSKeyedArchiver.archivedData(withRootObject: book) + print(data.count) try? FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil) - let filePath = path.appending("/\(book.key.md5())") + let filePath = path.appending("/\(book._id.md5())") let success = FileManager.default.createFile(atPath: filePath, contents: data, attributes: nil) if success { - QSLog("保存'\(book.value.title)'成功@_@") + QSLog("保存'\(book.title)'成功@_@") } } } @@ -256,7 +248,7 @@ public class BookManager:NSObject { } // 更新bookdetail的信息,bookdetail的数组与updateinfo数组是一一对应的 - func updateInfoUpdate(updateInfo:[UpdateInfo]){ + func updateInfoUpdate(updateInfo:[BookShelf]){ if updateInfo.count != books.allKeys().count { return } @@ -273,7 +265,7 @@ public class BookManager:NSObject { } //需要将对应的update信息赋给model - func updateToModel(updateModels:[UpdateInfo]){ + func updateToModel(updateModels:[BookShelf]){ for updateModel in updateModels { let id = updateModel._id ?? "" let book:BookDetail? = books[id] as? BookDetail @@ -288,7 +280,7 @@ public class BookManager:NSObject { } } - func anyUpdate(bookInfo:UpdateInfo?,updateInfo:UpdateInfo)->Bool{ + func anyUpdate(bookInfo:BookShelf?,updateInfo:BookShelf)->Bool{ if let updatedString = bookInfo?.updated { if updatedString != updateInfo.updated { return true diff --git a/zhuishushenqi/App/ZSDBManager.m b/zhuishushenqi/App/ZSDBManager.m index e021996..0f9a37a 100644 --- a/zhuishushenqi/App/ZSDBManager.m +++ b/zhuishushenqi/App/ZSDBManager.m @@ -137,6 +137,230 @@ + (BOOL)createTable:(NSObject *)model // return [self update]; //} +- (BOOL)save:(NSObject *)model +{ + NSString *tableName = [model tableName]; + NSMutableString *keyString = [NSMutableString string]; + NSMutableString *valueString = [NSMutableString string]; + NSMutableArray *insertValues = [NSMutableArray array]; + NSArray *columns = [self getPropertys:model]; + for (int i = 0; i < columns.count; i++) { + NSString *columnName = columns[i].mappingKey ? columns[i].mappingKey:columns[i].originalKey; + [keyString appendFormat:@"%@,", columnName]; + [valueString appendString:@"?,"]; + id value = [model valueForKey:columnName]; + if (!value) { + value = @""; + } + [insertValues addObject:value]; + } + + [keyString deleteCharactersInRange:NSMakeRange(keyString.length - 1, 1)]; + [valueString deleteCharactersInRange:NSMakeRange(valueString.length - 1, 1)]; + __block BOOL res = NO; + [self.dbQueue inDatabase:^(FMDatabase *db) { + NSString *sql = [NSString stringWithFormat:@"INSERT INTO %@(%@) VALUES (%@);", tableName, keyString, valueString]; + res = [db executeUpdate:sql withArgumentsInArray:insertValues]; + NSLog(res?@"插入成功":@"插入失败"); + }]; + return res; +} + +/** 批量保存用户对象 */ ++ (BOOL)saveObjects:(NSArray *)array +{ + __block BOOL res = YES; + // 如果要支持事务 + [ZSDBManager.share.dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) { + for (NSObject *model in array) { + NSString *tableName = [model tableName]; + NSMutableString *keyString = [NSMutableString string]; + NSMutableString *valueString = [NSMutableString string]; + NSMutableArray *insertValues = [NSMutableArray array]; + NSArray *columns = [ZSDBManager.share getPropertys:model]; + for (int i = 0; i < columns.count; i++) { + NSString *columnName = columns[i].mappingKey ? columns[i].mappingKey:columns[i].originalKey; + [keyString appendFormat:@"%@,", columnName]; + [valueString appendString:@"?,"]; + id value = [model valueForKey:columnName]; + if (!value) { + value = @""; + } + [insertValues addObject:value]; + } + [keyString deleteCharactersInRange:NSMakeRange(keyString.length - 1, 1)]; + [valueString deleteCharactersInRange:NSMakeRange(valueString.length - 1, 1)]; + + NSString *sql = [NSString stringWithFormat:@"INSERT INTO %@(%@) VALUES (%@);", tableName, keyString, valueString]; + BOOL flag = [db executeUpdate:sql withArgumentsInArray:insertValues]; + NSLog(flag?@"插入成功":@"插入失败"); + if (!flag) { + res = NO; + *rollback = YES; + return; + } + } + }]; + return res; +} + +/** 更新单个对象 */ +- (BOOL)update:(NSObject *)model +{ + __block BOOL res = NO; + [self.dbQueue inDatabase:^(FMDatabase *db) { + NSString *tableName = [model tableName]; + id primaryValue = [model valueForKey:[model primaryKey]]; + if (!primaryValue || primaryValue <= 0) { + return ; + } + NSMutableString *keyString = [NSMutableString string]; + NSMutableArray *updateValues = [NSMutableArray array]; + NSArray *columns = [ZSDBManager.share getPropertys:model]; + for (int i = 0; i < columns.count; i++) { + NSString *columnName = columns[i].mappingKey ? columns[i].mappingKey:columns[i].originalKey; + [keyString appendFormat:@" %@=?,", columnName]; + id value = [model valueForKey:columnName]; + if (!value) { + value = @""; + } + [updateValues addObject:value]; + } + + //删除最后那个逗号 + [keyString deleteCharactersInRange:NSMakeRange(keyString.length - 1, 1)]; + NSString *sql = [NSString stringWithFormat:@"UPDATE %@ SET %@ WHERE %@ = ?;", tableName, keyString, primaryId]; + [updateValues addObject:primaryValue]; + res = [db executeUpdate:sql withArgumentsInArray:updateValues]; + NSLog(res?@"更新成功":@"更新失败"); + }]; + return res; +} + +/** 批量更新用户对象*/ ++ (BOOL)updateObjects:(NSArray *)array +{ + __block BOOL res = YES; + // 如果要支持事务 + [ZSDBManager.share.dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) { + for (NSObject *model in array) { + id primaryValue = [model valueForKey:[model primaryKey]]; + if (!primaryValue || primaryValue <= 0) { + res = NO; + *rollback = YES; + return; + } + + NSMutableString *keyString = [NSMutableString string]; + NSMutableArray *updateValues = [NSMutableArray array]; + NSArray *columns = [ZSDBManager.share getPropertys:model]; + for (int i = 0; i < columns.count; i++) { + NSString *columnName = columns[i].mappingKey ? columns[i].mappingKey:columns[i].originalKey; + [keyString appendFormat:@" %@=?,", columnName]; + id value = [model valueForKey:columnName]; + if (!value) { + value = @""; + } + [updateValues addObject:value]; + } + + //删除最后那个逗号 + [keyString deleteCharactersInRange:NSMakeRange(keyString.length - 1, 1)]; + NSString *sql = [NSString stringWithFormat:@"UPDATE %@ SET %@ WHERE %@=?;", [model tableName], keyString, [model primaryKey]]; + [updateValues addObject:primaryValue]; + BOOL flag = [db executeUpdate:sql withArgumentsInArray:updateValues]; + NSLog(flag?@"更新成功":@"更新失败"); + if (!flag) { + res = NO; + *rollback = YES; + return; + } + } + }]; + + return res; +} + +/** 删除单个对象 */ +- (BOOL)deleteObject:(NSObject *)model +{ + __block BOOL res = NO; + [self.dbQueue inDatabase:^(FMDatabase *db) { + NSString *tableName = [model tableName]; + id primaryValue = [model valueForKey:[model primaryKey]]; + if (!primaryValue || primaryValue <= 0) { + return ; + } + NSString *sql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@ = ?",tableName,[model primaryKey]]; + res = [db executeUpdate:sql withArgumentsInArray:@[primaryValue]]; + NSLog(res?@"删除成功":@"删除失败"); + }]; + return res; +} + +/** 批量删除用户对象 */ ++ (BOOL)deleteObjects:(NSArray *)array +{ + __block BOOL res = YES; + // 如果要支持事务 + [ZSDBManager.share.dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) { + for (NSObject *model in array) { + NSString *tableName = [model tableName]; + id primaryValue = [model valueForKey:[model primaryKey]]; + if (!primaryValue || primaryValue <= 0) { + return ; + } + + NSString *sql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@ = ?",tableName,[model primaryKey]]; + BOOL flag = [db executeUpdate:sql withArgumentsInArray:@[primaryValue]]; + NSLog(flag?@"删除成功":@"删除失败"); + if (!flag) { + res = NO; + *rollback = YES; + return; + } + } + }]; + return res; +} + +/** 通过条件删除数据 */ ++ (BOOL)deleteObjectsByCriteria:(NSString *)criteria model:(NSObject *)model +{ + __block BOOL res = NO; + [ZSDBManager.share.dbQueue inDatabase:^(FMDatabase *db) { + NSString *tableName = [model tableName]; + NSString *sql = [NSString stringWithFormat:@"DELETE FROM %@ %@ ",tableName,criteria]; + res = [db executeUpdate:sql]; + NSLog(res?@"删除成功":@"删除失败"); + }]; + return res; +} + +/** 通过条件删除 (多参数)--2 */ ++ (BOOL)deleteObjectsWithModel:(NSObject *)model Format:(NSString *)format, ... +{ + va_list ap; + va_start(ap, format); + NSString *criteria = [[NSString alloc] initWithFormat:format locale:[NSLocale currentLocale] arguments:ap]; + va_end(ap); + + return [self deleteObjectsByCriteria:criteria model:model]; +} + +/** 清空表 */ ++ (BOOL)clearTable:(NSObject *)model +{ + __block BOOL res = NO; + [ZSDBManager.share.dbQueue inDatabase:^(FMDatabase *db) { + NSString *tableName = [model tableName]; + NSString *sql = [NSString stringWithFormat:@"DELETE FROM %@",tableName]; + res = [db executeUpdate:sql]; + NSLog(res?@"清空成功":@"清空失败"); + }]; + return res; +} + - (NSArray *)queryAll:(NSObject *)model { NSLog(@"ZSDBModel---%s",__func__); NSMutableArray *models = [NSMutableArray array]; @@ -156,7 +380,7 @@ - (NSArray *)queryAll:(NSObject *)model { } else if ([columnType isEqualToString:SQLBLOB]) { [queryModel setValue:[resultSet dataForColumn:columnName] forKey:columnName]; } else if ([columnName isEqualToString:NSStringFromProtocol(@protocol(ZSDBModel))]) { - + // 单独查询这个表即可 } else { [queryModel setValue:[NSNumber numberWithLongLong:[resultSet longLongIntForColumn:columnName]] forKey:columnName]; } @@ -168,6 +392,65 @@ - (NSArray *)queryAll:(NSObject *)model { return models; } +/** 查找某条数据 */ ++ (instancetype)findFirstByCriteria:(NSString *)criteria model:(NSObject *)model +{ + NSArray *results = [ZSDBManager findByCriteria:criteria model:model]; + if (results.count < 1) { + return nil; + } + + return [results firstObject]; +} + ++ (instancetype)findByPK:(int)inPk model:(NSObject *)model +{ + NSString *condition = [NSString stringWithFormat:@"WHERE %@=%d",primaryId,inPk]; + return [self findFirstByCriteria:condition model:model]; +} + ++ (NSArray *)findWithModel:(NSObject *)model Format:(NSString *)format, ... +{ + va_list ap; + va_start(ap, format); + NSString *criteria = [[NSString alloc] initWithFormat:format locale:[NSLocale currentLocale] arguments:ap]; + va_end(ap); + return [self findByCriteria:criteria model:model]; +} + +/** 通过条件查找数据 */ ++ (NSArray *)findByCriteria:(NSString *)criteria model:(NSObject *)model +{ + NSMutableArray *users = [NSMutableArray array]; + [ZSDBManager.share.dbQueue inDatabase:^(FMDatabase *db) { + NSString *tableName = [model tableName]; + NSString *sql = [NSString stringWithFormat:@"SELECT * FROM %@ %@",tableName,criteria]; + FMResultSet *resultSet = [db executeQuery:sql]; + while ([resultSet next]) { + NSObject *result = [[[model class] alloc] init]; + NSArray *columns = [ZSDBManager.share getPropertys:result]; + for (int i=0; i< columns.count; i++) { + NSString *columnName = columns[i].mappingKey ? columns[i].mappingKey:columns[i].originalKey; + NSString *columnType = columns[i].type; + if ([columnType isEqualToString:SQLTEXT]) { + [result setValue:[resultSet stringForColumn:columnName] forKey:columnName]; + } else if ([columnType isEqualToString:SQLBLOB]) { + [result setValue:[resultSet dataForColumn:columnName] forKey:columnName]; + } else if ([columnName isEqualToString:NSStringFromProtocol(@protocol(ZSDBModel))]) { + // 单独查询这个表即可 + } else { + [result setValue:[NSNumber numberWithLongLong:[resultSet longLongIntForColumn:columnName]] forKey:columnName]; + } + } + [users addObject:model]; + FMDBRelease(model); + } + }]; + + return users; +} + + - (NSArray *)getPropertys:(NSObject *)model { NSString *foreignKey; NSString *primaryKey; diff --git a/zhuishushenqi/App/ZSDatabase.swift b/zhuishushenqi/App/ZSDatabase.swift index 2166d8e..6f48c3c 100644 --- a/zhuishushenqi/App/ZSDatabase.swift +++ b/zhuishushenqi/App/ZSDatabase.swift @@ -75,7 +75,7 @@ struct ZSDatabase { for item in (try! db.prepare(TABLE_LAMP)) { QSLog("\(item)") let book = BookDetail() - let updateInfo = UpdateInfo() + let updateInfo = BookShelf() updateInfo.lastChapter = item[TABLE_LAMP_LAST_CHAPTER] updateInfo.updated = item[TABLE_LAMP_LAST_UPDATE_TIME] book.title = item[TABLE_LAMP_BOOKNAME] diff --git a/zhuishushenqi/Client/QSAPI.swift b/zhuishushenqi/Client/QSAPI.swift index bbc7c78..f20310d 100644 --- a/zhuishushenqi/Client/QSAPI.swift +++ b/zhuishushenqi/Client/QSAPI.swift @@ -110,6 +110,8 @@ enum QSAPI { case reviewPost(token:String,id:String,content:String) ///已购章节信息 case boughtChapters(id:String,token:String) + ///书架信息diff + case bookshelfdiff(books:String,token:String) } extension QSAPI:TargetType{ @@ -256,6 +258,10 @@ extension QSAPI:TargetType{ // https://api.zhuishushenqi.com/v2/purchase/book/5b10fd1b5d144d1b68581805/chapters/bought?token=rPcCW1GGh1hFPnSRJDjkwjtS pathComponent = "/v2/purchase/book/\(id)/chapters/bought" break + case .bookshelfdiff(_, _): +// https://api.zhuishushenqi.com/v3/user/bookshelf/diff + pathComponent = "/v3/user/bookshelf/diff" + break default: break } @@ -359,6 +365,9 @@ extension QSAPI:TargetType{ case let .boughtChapters(_, token): return ["token":token, ] + case let .bookshelfdiff(books, token): + return ["books":books, + "token":token] default: return nil } diff --git a/zhuishushenqi/Extension/NSDate+Date.m b/zhuishushenqi/Extension/NSDate+Date.m index 11799d8..d873440 100644 --- a/zhuishushenqi/Extension/NSDate+Date.m +++ b/zhuishushenqi/Extension/NSDate+Date.m @@ -21,7 +21,24 @@ + (NSDate*)getDateWithYear:(NSString *)year month:(NSString *)month day:(NSStrin [comps setMinute:[minute integerValue]]; [comps setSecond:[second integerValue]]; - return [calendar dateFromComponents:comps]; + NSDate *date = [calendar dateFromComponents:comps]; + NSTimeInterval timeInterval = [self offsetTimeIntervalFromCurrentTimeZoneForDate:date]; + return [NSDate dateWithTimeInterval:timeInterval sinceDate:date]; +} + ++ (NSTimeInterval)offsetTimeIntervalFromCurrentTimeZoneForDate:(NSDate *)anyDate { + //设置源日期时区 + NSTimeZone* sourceTimeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];//或GMT + //设置转换后的目标日期时区 + NSTimeZone* destinationTimeZone = [NSTimeZone localTimeZone]; + //得到源日期与世界标准时间的偏移量 + NSInteger sourceGMTOffset = [sourceTimeZone secondsFromGMTForDate:anyDate]; + //目标日期与本地时区的偏移量 + NSInteger destinationGMTOffset = [destinationTimeZone secondsFromGMTForDate:anyDate]; + //得到时间偏移量的差值 + NSTimeInterval interval = destinationGMTOffset - sourceGMTOffset; + + return interval; } diff --git a/zhuishushenqi/Root/Controllers/RootViewController+FetchData.swift b/zhuishushenqi/Root/Controllers/RootViewController+FetchData.swift index 937b3df..a82c169 100644 --- a/zhuishushenqi/Root/Controllers/RootViewController+FetchData.swift +++ b/zhuishushenqi/Root/Controllers/RootViewController+FetchData.swift @@ -68,7 +68,7 @@ extension RootViewController{ // 防止返回时卡顿,采用子线程 DispatchQueue.global().async { if let json:[Any] = response.json as? [Any] { - if let models = [UpdateInfo].deserialize(from: json) as? [UpdateInfo] { + if let models = [BookShelf].deserialize(from: json) as? [BookShelf] { BookManager.shared.updateToModel(updateModels: models) DispatchQueue.main.async { self.tableView.reloadData() diff --git a/zhuishushenqi/Root/Controllers/ZSShelfViewController.swift b/zhuishushenqi/Root/Controllers/ZSShelfViewController.swift index 4c15705..abc138b 100644 --- a/zhuishushenqi/Root/Controllers/ZSShelfViewController.swift +++ b/zhuishushenqi/Root/Controllers/ZSShelfViewController.swift @@ -183,8 +183,8 @@ class ZSShelfViewController: BaseViewController,Refreshable,UITableViewDataSourc } return viewModel.books.count } - return viewModel.fetchBooks().count -// return viewModel.books.count +// return viewModel.fetchBooks().count + return viewModel.books.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { @@ -200,12 +200,12 @@ class ZSShelfViewController: BaseViewController,Refreshable,UITableViewDataSourc cell.configureCell(model: item) } } else { - let book = viewModel.fetchBooks()[indexPath.row] - cell.configureCell(model: book) -// let id = viewModel.booksID[indexPath.row] -// if let item = viewModel.books[id] { -// cell.configureCell(model: item) -// } +// let book = viewModel.fetchBooks()[indexPath.row] +// cell.configureCell(model: book) + let id = viewModel.booksID[indexPath.row] + if let item = viewModel.books[id] { + cell.configureCell(model: item) + } } return cell } @@ -272,18 +272,20 @@ class ZSShelfViewController: BaseViewController,Refreshable,UITableViewDataSourc return } } - let books = viewModel.fetchBooks() - let viewController = ZSReaderViewController() - viewController.viewModel.book = books[indexPath.row] - self.present(viewController, animated: true, completion: nil) - self.tableView.reloadRow(at: indexPath, with: .automatic) -// let books = self.viewModel.books -// if let model = books[viewModel.booksID[indexPath.row]] { -// let viewController = ZSReaderViewController() -// viewController.viewModel.book = model -// self.present(viewController, animated: true, completion: nil) -// self.tableView.reloadRow(at: indexPath, with: .automatic) -// } +// let books = viewModel.fetchBooks() +// let viewController = ZSReaderViewController() +// viewController.viewModel.book = books[indexPath.row] +// self.present(viewController, animated: true, completion: nil) +// self.tableView.reloadRow(at: indexPath, with: .automatic) + let books = self.viewModel.books + if let model = books[viewModel.booksID[indexPath.row]] { + // 刷新id的排序,当前点击的书籍置顶 + viewModel.topBook(key: model._id) + let viewController = ZSReaderViewController() + viewController.viewModel.book = model + self.present(viewController, animated: true, completion: nil) + self.tableView.reloadData() + } } } diff --git a/zhuishushenqi/Root/Service/ZSRootWebService.swift b/zhuishushenqi/Root/Service/ZSRootWebService.swift index 67ed25b..4b3793d 100644 --- a/zhuishushenqi/Root/Service/ZSRootWebService.swift +++ b/zhuishushenqi/Root/Service/ZSRootWebService.swift @@ -34,8 +34,8 @@ final class ZSRootWebService:ZSBaseService { .observeOn(ConcurrentDispatchQueueScheduler(qos:.background)) .map { (_,responseData) in // json解析 - if let models = [UpdateInfo].deserialize(from: responseData as? [Any]) { - if let arr = models as? [UpdateInfo]{ + if let models = [BookShelf].deserialize(from: responseData as? [Any]) { + if let arr = models as? [BookShelf]{ BookManager.shared.updateInfoUpdate(updateInfo: arr) return BookManager.shared.books } diff --git a/zhuishushenqi/Root/Service/ZSShelfWebService.swift b/zhuishushenqi/Root/Service/ZSShelfWebService.swift index a7d5225..b32305f 100644 --- a/zhuishushenqi/Root/Service/ZSShelfWebService.swift +++ b/zhuishushenqi/Root/Service/ZSShelfWebService.swift @@ -9,14 +9,14 @@ import Foundation class ZSShelfWebService: ZSBaseService { - func fetchShelvesUpdate(for ids:[String],completion:@escaping ZSBaseCallback<[UpdateInfo]>) { + func fetchShelvesUpdate(for ids:[String],completion:@escaping ZSBaseCallback<[BookShelf]>) { let id = (ids as NSArray).componentsJoined(by: ",") let api = QSAPI.update(id: id) zs_get(api.path, parameters: api.parameters).responseJSON { (response) in if let data = response.data { if let obj = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as? [Any] { - if let models = [UpdateInfo].deserialize(from: obj) { - if let arr = models as? [UpdateInfo]{ + if let models = [BookShelf].deserialize(from: obj) { + if let arr = models as? [BookShelf]{ completion(arr) } } diff --git a/zhuishushenqi/Root/ViewModel/ZSShelfViewModel.swift b/zhuishushenqi/Root/ViewModel/ZSShelfViewModel.swift index 8d4847b..e2614d6 100644 --- a/zhuishushenqi/Root/ViewModel/ZSShelfViewModel.swift +++ b/zhuishushenqi/Root/ViewModel/ZSShelfViewModel.swift @@ -99,6 +99,17 @@ class ZSShelfViewModel:NSObject,ZSRefreshProtocol { } return exist } + + func topBook(key:String) { + var book_index = 0 + for index in 0.. 0 { shelvesWebService.fetchShelvesUpdate(for: booksID) { (updateInfo) in - if let info = updateInfo { - for update in info { - self.database.updateInfo(updateInfo: update) - } + if let info = updateInfo as? [BookShelf] { +// for update in info { +// self.database.updateInfo(updateInfo: update) +// } self.refreshStatus.value = .headerRefreshEnd ZSBookManager.shared.update(updateInfo: info) // BookManager.shared.updateInfoUpdate(updateInfo: info) diff --git a/zhuishushenqi/TXTReader/BookDetail/Models/BookDetail.swift b/zhuishushenqi/TXTReader/BookDetail/Models/BookDetail.swift index b769e05..f1f7ae8 100644 --- a/zhuishushenqi/TXTReader/BookDetail/Models/BookDetail.swift +++ b/zhuishushenqi/TXTReader/BookDetail/Models/BookDetail.swift @@ -157,7 +157,7 @@ class BookDetail: NSObject,NSCoding ,HandyJSON{ var book:QSBook! //更新信息 - var updateInfo:UpdateInfo? + var updateInfo:BookShelf? required init?(coder aDecoder: NSCoder) { @@ -177,7 +177,7 @@ class BookDetail: NSObject,NSCoding ,HandyJSON{ self.wordCount = aDecoder.decodeObject(forKey: "wordCount") as? String ?? "" self.updated = aDecoder.decodeObject(forKey: "updated") as? String ?? "" self.tags = aDecoder.decodeObject(forKey: "tags") as? NSArray - self.updateInfo = aDecoder.decodeObject(forKey: "updateInfo") as? UpdateInfo + self.updateInfo = aDecoder.decodeObject(forKey: "updateInfo") as? BookShelf self.chapter = aDecoder.decodeInteger(forKey:"chapter") self.page = aDecoder.decodeInteger(forKey:"page") self.sourceIndex = aDecoder.decodeInteger(forKey:"sourceIndex") diff --git a/zhuishushenqi/TXTReader/BookDetail/Models/BookShelf.swift b/zhuishushenqi/TXTReader/BookDetail/Models/BookShelf.swift index b74541b..99c65a9 100644 --- a/zhuishushenqi/TXTReader/BookDetail/Models/BookShelf.swift +++ b/zhuishushenqi/TXTReader/BookDetail/Models/BookShelf.swift @@ -10,20 +10,98 @@ import UIKit import HandyJSON @objc(BookShelf) -class BookShelf: NSObject, HandyJSON { +class BookShelf: NSObject, HandyJSON, NSCoding { + var _id:String? var title:String? var author:String? var cover:String? - var allowMonthly:Bool? - var allowVoucher:Bool? + var allowMonthly:String? + var allowVoucher:String? var updated:String? - var chaptersCount:Int? + var chaptersCount:String? var lastChapter:String? var referenceSource:String? var readRecord:ZSReadRecord? var modifyTime:String? + var created:String? + var contentType:String? + var superscript:String? + var sizetype:String? required override init() {} + + func encode(with aCoder: NSCoder) { + aCoder.encode(self._id, forKey: "_id") + aCoder.encode(self.title, forKey: "title") + aCoder.encode(self.author, forKey: "author") + aCoder.encode(self.cover, forKey: "cover") + aCoder.encode(self.allowMonthly, forKey: "allowMonthly") + aCoder.encode(self.allowVoucher, forKey: "allowVoucher") + aCoder.encode(self.updated, forKey: "updated") + aCoder.encode(self.chaptersCount, forKey: "chaptersCount") + aCoder.encode(self.lastChapter, forKey: "lastChapter") + aCoder.encode(self.referenceSource, forKey: "referenceSource") + aCoder.encode(self.readRecord, forKey: "readRecord") + aCoder.encode(self.modifyTime, forKey: "modifyTime") + aCoder.encode(self.created, forKey: "created") + aCoder.encode(self.contentType, forKey: "contentType") + aCoder.encode(self.superscript, forKey: "superscript") + aCoder.encode(self.sizetype, forKey: "sizetype") + + } + + required init?(coder aDecoder: NSCoder) { + self._id = aDecoder.decodeObject(forKey: "_id") as? String + self.title = aDecoder.decodeObject(forKey: "title") as? String + self.author = aDecoder.decodeObject(forKey: "author") as? String + self.cover = aDecoder.decodeObject(forKey: "cover") as? String + self.allowMonthly = aDecoder.decodeObject(forKey: "allowMonthly") as? String + self.allowVoucher = aDecoder.decodeObject(forKey: "allowVoucher") as? String + self.updated = aDecoder.decodeObject(forKey: "updated") as? String + self.chaptersCount = aDecoder.decodeObject(forKey: "chaptersCount") as? String + self.lastChapter = aDecoder.decodeObject(forKey: "lastChapter") as? String + self.referenceSource = aDecoder.decodeObject(forKey: "referenceSource") as? String + self.readRecord = aDecoder.decodeObject(forKey: "readRecord") as? ZSReadRecord + self.modifyTime = aDecoder.decodeObject(forKey: "modifyTime") as? String + self.created = aDecoder.decodeObject(forKey: "created") as? String + self.contentType = aDecoder.decodeObject(forKey: "contentType") as? String + self.superscript = aDecoder.decodeObject(forKey: "superscript") as? String + self.sizetype = aDecoder.decodeObject(forKey: "sizetype") as? String + + } } +//"_id": "5acf0f7c2eb0ad0dfb729d92", +//"author": "毒心萝卜", +//"cover": "/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2273645%2F2273645_5aa9d3087b88488286117e98d885c22a.jpg%2F", +//"title": "业界大忽悠", +//"buytype": 0, +//"allowMonthly": false, +//"allowVoucher": true, +//"hasCp": true, +//"referenceSource": "default", +//"updated": "2018-10-20T10:11:01.000Z", +//"chaptersCount": 266, +//"lastChapter": "第266章 挑选功法", +//"created": "2018-11-25T07:27:14.819Z", +//"_le": false, +//"contentType": "txt", +//"superscript": "", +//"sizetype": -1, +//"_mm": false, +//"readRecord": { +// "tocId": "5acf0f7c2eb0ad0dfb729d94", +// "tocName": "zhuishuvip", +// "title": "第229章 广告代言", +// "order": 228, +// "wordIndex": 252, +// "updated": "2018-11-28T01:46:42.585Z", +// "book": "5acf0f7c2eb0ad0dfb729d92" +//}, +//"advertRead": true, +//"_gg": false, +//"expired": 0, +//"_ss": false, +//"modifyTime": "2018-12-01T05:38:25.084Z" + diff --git a/zhuishushenqi/TXTReader/BookDetail/Models/ZSReadRecord.swift b/zhuishushenqi/TXTReader/BookDetail/Models/ZSReadRecord.swift index a6f82a8..435350f 100644 --- a/zhuishushenqi/TXTReader/BookDetail/Models/ZSReadRecord.swift +++ b/zhuishushenqi/TXTReader/BookDetail/Models/ZSReadRecord.swift @@ -9,14 +9,35 @@ import UIKit import HandyJSON -class ZSReadRecord: NSObject, HandyJSON { +class ZSReadRecord: NSObject, HandyJSON, NSCoding { var tocId:String? var tocName:String? var title:String? - var order:Int? - var wordIndex:Int? + var order:Int64? + var wordIndex:Int64? var updated:String? var book:String? required override init() {} + + func encode(with aCoder: NSCoder) { + aCoder.encode(self.tocId, forKey: "tocId") + aCoder.encode(self.tocName, forKey: "tocName") + aCoder.encode(self.title, forKey: "title") + aCoder.encode(self.order, forKey: "order") + aCoder.encode(self.wordIndex, forKey: "wordIndex") + aCoder.encode(self.updated, forKey: "updated") + aCoder.encode(self.book, forKey: "book") + + } + + required init?(coder aDecoder: NSCoder) { + self.tocId = aDecoder.decodeObject(forKey: "tocId") as? String + self.tocName = aDecoder.decodeObject(forKey: "tocName") as? String + self.title = aDecoder.decodeObject(forKey: "title") as? String + self.order = aDecoder.decodeInt64(forKey: "order") + self.wordIndex = aDecoder.decodeInt64(forKey: "wordIndex") + self.updated = aDecoder.decodeObject(forKey: "updated") as? String + self.book = aDecoder.decodeObject(forKey: "book") as? String + } } From 59470373342508a9cc28201579095b7a0dc853cf Mon Sep 17 00:00:00 2001 From: caonongyun Date: Thu, 3 Jan 2019 00:43:38 +0800 Subject: [PATCH 05/19] =?UTF-8?q?=E4=B9=A6=E6=9E=B6=E5=88=B7=E6=96=B0?= =?UTF-8?q?=E5=8D=A1=E9=A1=BF=E9=97=AE=E9=A2=98=E4=BF=AE=E5=A4=8D&?= =?UTF-8?q?=E9=98=85=E8=AF=BB=E8=BF=87=E7=9A=84=E4=B9=A6=E7=B1=8D=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E7=BD=AE=E9=A1=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3ae68e3..0e78812 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ **20181025: 本次功能变更: 添加登录后书架信息同步** **20181102: 本次功能变更: 添加自动签到功能,进入APP即可自动签到** +**20190102: 本次功能变更: 修复书架刷新卡顿&阅读过的书籍置顶(branch dev_db)** ---- From 5aa6e39fab481440cbd7b1eeca6f74f40c0de73b Mon Sep 17 00:00:00 2001 From: caonongyun Date: Thu, 3 Jan 2019 22:17:58 +0800 Subject: [PATCH 06/19] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=B9=A6=E7=B1=8D=E6=97=A0=E6=95=88=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zhuishushenqi.xcodeproj/project.pbxproj | 6 ++-- zhuishushenqi/App/BookManager.swift | 30 +++++++++++++++- .../Root/Controllers/RootViewController.swift | 1 + .../Controllers/ZSShelfViewController.swift | 1 + .../Root/ViewModel/ZSShelfViewModel.swift | 4 ++- zhuishushenqi/Root/Views/QSLaunchRecView.xib | 34 +++++++++---------- 6 files changed, 54 insertions(+), 22 deletions(-) diff --git a/zhuishushenqi.xcodeproj/project.pbxproj b/zhuishushenqi.xcodeproj/project.pbxproj index 8143f21..b343262 100644 --- a/zhuishushenqi.xcodeproj/project.pbxproj +++ b/zhuishushenqi.xcodeproj/project.pbxproj @@ -2420,7 +2420,7 @@ TargetAttributes = { B2BB5B951D8BDF8E00379217 = { CreatedOnToolsVersion = 7.3.1; - DevelopmentTeam = ZYDXKQKHVY; + DevelopmentTeam = L94HEL9RUT; LastSwiftMigration = 0810; ProvisioningStyle = Automatic; SystemCapabilities = { @@ -3167,7 +3167,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = ZYDXKQKHVY; + DEVELOPMENT_TEAM = L94HEL9RUT; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -3214,7 +3214,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = ZYDXKQKHVY; + DEVELOPMENT_TEAM = L94HEL9RUT; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", diff --git a/zhuishushenqi/App/BookManager.swift b/zhuishushenqi/App/BookManager.swift index f171a26..7c247f7 100644 --- a/zhuishushenqi/App/BookManager.swift +++ b/zhuishushenqi/App/BookManager.swift @@ -56,17 +56,37 @@ public class ZSBookManager:NSObject { } } + func topBook(key:String) { + var book_index = 0 + for index in 0.. Bool { var exist:Bool = false + var book_exist = false for id in self.ids { if book._id == id { exist = true } } - return exist + for item in self.books { + if item.key == book._id { + book_exist = true + } + } + + return exist && book_exist } + + //MARK: - 添加,默认添加到尾部 func addBook(book:BookDetail) { if existBook(book: book) { @@ -75,6 +95,14 @@ public class ZSBookManager:NSObject { } self.ids.append(book._id) self.books[book._id] = book + self.saveBooks(book: book) + } + + //MARK: - 添加多本书籍,一般推荐书籍或者从远程拉取大量书籍时使用 + func addBooks(books:[BookDetail]) { + for book in books { + self.addBook(book: book) + } } //MARK: - 删除 diff --git a/zhuishushenqi/Root/Controllers/RootViewController.swift b/zhuishushenqi/Root/Controllers/RootViewController.swift index 99e8c1b..1e2cf80 100644 --- a/zhuishushenqi/Root/Controllers/RootViewController.swift +++ b/zhuishushenqi/Root/Controllers/RootViewController.swift @@ -143,6 +143,7 @@ class RootViewController: UIViewController { QSNetwork.request(recURL) { (response) in if let books = response.json?["books"] { if let models = [BookDetail].deserialize(from: books as? [Any]) as? [BookDetail] { + ZSBookManager.shared.addBooks(books: models) BookManager.shared.modifyBookshelf(books: models) self.tableView.reloadData() } diff --git a/zhuishushenqi/Root/Controllers/ZSShelfViewController.swift b/zhuishushenqi/Root/Controllers/ZSShelfViewController.swift index abc138b..037253b 100644 --- a/zhuishushenqi/Root/Controllers/ZSShelfViewController.swift +++ b/zhuishushenqi/Root/Controllers/ZSShelfViewController.swift @@ -162,6 +162,7 @@ class ZSShelfViewController: BaseViewController,Refreshable,UITableViewDataSourc } } } else { + self.view.showTip(tip: "添加到书架成功") self.headerRefresh?.beginRefreshing() } diff --git a/zhuishushenqi/Root/ViewModel/ZSShelfViewModel.swift b/zhuishushenqi/Root/ViewModel/ZSShelfViewModel.swift index e2614d6..60691c7 100644 --- a/zhuishushenqi/Root/ViewModel/ZSShelfViewModel.swift +++ b/zhuishushenqi/Root/ViewModel/ZSShelfViewModel.swift @@ -30,7 +30,7 @@ class ZSShelfViewModel:NSObject,ZSRefreshProtocol { return ZSBookManager.shared.ids } set { - ZSBookManager.shared.ids = newValue +// ZSBookManager.shared.ids = newValue } } @@ -107,6 +107,7 @@ class ZSShelfViewModel:NSObject,ZSRefreshProtocol { book_index = index } } + ZSBookManager.shared.topBook(key: key) booksID.remove(at: book_index) booksID.insert(key, at: 0) } @@ -185,6 +186,7 @@ extension ZSShelfViewModel { if let bookDetail = book { self.booksID.append(item.id) self.books[item.id] = bookDetail + ZSBookManager.shared.addBook(book: bookDetail) completion(books) } }) diff --git a/zhuishushenqi/Root/Views/QSLaunchRecView.xib b/zhuishushenqi/Root/Views/QSLaunchRecView.xib index 618fc46..1966f22 100644 --- a/zhuishushenqi/Root/Views/QSLaunchRecView.xib +++ b/zhuishushenqi/Root/Views/QSLaunchRecView.xib @@ -1,11 +1,11 @@ - + - + @@ -19,19 +19,19 @@ - + - + - + - + @@ -85,7 +85,7 @@ - + - + @@ -121,7 +121,7 @@ - + @@ -85,7 +85,7 @@ - + - + @@ -121,7 +121,7 @@