diff --git a/Examples/Objective-C/NYSExampleObjC/AppDelegate/AppDelegate+AppService.m b/Examples/Objective-C/NYSExampleObjC/AppDelegate/AppDelegate+AppService.m index 05dfc51..5dec10f 100644 --- a/Examples/Objective-C/NYSExampleObjC/AppDelegate/AppDelegate+AppService.m +++ b/Examples/Objective-C/NYSExampleObjC/AppDelegate/AppDelegate+AppService.m @@ -50,6 +50,7 @@ - (void)initWindow { - (void)initNetwork { [[NYSKitManager sharedNYSKitManager] setHost:APP_BaseURL]; [[NYSKitManager sharedNYSKitManager] setToken:NUserInfo.token]; + [[NYSKitManager sharedNYSKitManager] setDataKey:@"data"]; [[NYSKitManager sharedNYSKitManager] setNormalCode:@"200,0"]; [[NYSKitManager sharedNYSKitManager] setTokenInvalidCode:@"500"]; [[NYSKitManager sharedNYSKitManager] setTokenInvalidMessage:@"验证失败,请先登录"]; diff --git a/Examples/Objective-C/Podfile.lock b/Examples/Objective-C/Podfile.lock index 8f506c3..645d01a 100644 --- a/Examples/Objective-C/Podfile.lock +++ b/Examples/Objective-C/Podfile.lock @@ -25,14 +25,14 @@ PODS: - JCore (>= 2.0.0) - Masonry (1.1.0) - MJRefresh (3.7.6) - - NYSKit (0.0.6): + - NYSKit (0.0.7): - AFNetworking (~> 4.0) - SVProgressHUD (~> 2.0) - NYSTK (0.0.8): - Masonry (>= 1.0.0) - - NYSUIKit (0.0.6): + - NYSUIKit (0.0.7): - MJRefresh (~> 3.7.6) - - NYSKit (~> 0.0.1) + - NYSKit (~> 0.0.7) - ReactiveObjC (3.1.1) - SVProgressHUD (2.3.1): - SVProgressHUD/Core (= 2.3.1) @@ -117,9 +117,9 @@ SPEC CHECKSUMS: JPush: 76668b765fcfd7c15f86b05ca0e5cdc01945ce23 Masonry: 678fab65091a9290e40e2832a55e7ab731aad201 MJRefresh: 2fe7fb43a5167ceda20bb7e63f130c04fd1814a5 - NYSKit: b632a9f33c4c19103f66ba3276b8d519ece9f123 + NYSKit: a2873b9901d83616c48d558320b14efcaac98635 NYSTK: 2a3ed92c57614cce6fc20ed21cf82db2d9146217 - NYSUIKit: 01e93c7f1e7482f8b2052c61dab3a4db036701f0 + NYSUIKit: 66e82bc87d032139b7cb7ce7654ac59356c9e922 ReactiveObjC: 011caa393aa0383245f2dcf9bf02e86b80b36040 SVProgressHUD: 4837c74bdfe2e51e8821c397825996a8d7de6e22 UMAPM: e69eb6542a7c98f31a0d177d31ecfa1a2ceee1c3 diff --git a/Examples/Swift/NYSExampleSwift.xcodeproj/project.pbxproj b/Examples/Swift/NYSExampleSwift.xcodeproj/project.pbxproj index e9c3d90..f2d40df 100644 --- a/Examples/Swift/NYSExampleSwift.xcodeproj/project.pbxproj +++ b/Examples/Swift/NYSExampleSwift.xcodeproj/project.pbxproj @@ -39,7 +39,6 @@ C82F2FC32B6E28A900A8F816 /* UIButton+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C82F2FC22B6E28A900A8F816 /* UIButton+Extension.swift */; }; C82F2FC82B6E39FC00A8F816 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C82F2FC72B6E39FC00A8F816 /* String+Extension.swift */; }; C83162A42B4CE2750014CFE1 /* TypeNameProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83162A32B4CE2750014CFE1 /* TypeNameProtocol.swift */; }; - C83162A72B4CE5160014CFE1 /* UIScrollView+RxSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = C83162A62B4CE5160014CFE1 /* UIScrollView+RxSwift.swift */; }; C83C18692B33E438002FD985 /* bill.json in Resources */ = {isa = PBXBuildFile; fileRef = C83C18652B33E438002FD985 /* bill.json */; }; C83C186A2B33E438002FD985 /* service.json in Resources */ = {isa = PBXBuildFile; fileRef = C83C18662B33E438002FD985 /* service.json */; }; C83C186B2B33E438002FD985 /* goods.json in Resources */ = {isa = PBXBuildFile; fileRef = C83C18672B33E438002FD985 /* goods.json */; }; @@ -76,6 +75,7 @@ C86DB21A2B3E8DBC002126F5 /* NYSLoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C86DB2162B3E8DBC002126F5 /* NYSLoginViewController.swift */; }; C86DB21F2B3E9E22002126F5 /* WRNavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = C86DB21D2B3E9E22002126F5 /* WRNavigationBar.swift */; }; C86DB2202B3E9E22002126F5 /* WRCustomNavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = C86DB21E2B3E9E22002126F5 /* WRCustomNavigationBar.swift */; }; + C87021042BC278C60056A806 /* UIView+RxSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = C87021032BC278C60056A806 /* UIView+RxSwift.swift */; }; C8713F4A2B69E5690090B289 /* PullUpController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8713F492B69E5690090B289 /* PullUpController.swift */; }; C8713F4E2B69EC420090B289 /* NYSPullerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8713F4C2B69EC420090B289 /* NYSPullerViewController.swift */; }; C8713F4F2B69EC420090B289 /* NYSPullerViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C8713F4D2B69EC420090B289 /* NYSPullerViewController.xib */; }; @@ -169,7 +169,6 @@ C82F2FC22B6E28A900A8F816 /* UIButton+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIButton+Extension.swift"; sourceTree = ""; }; C82F2FC72B6E39FC00A8F816 /* String+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Extension.swift"; sourceTree = ""; }; C83162A32B4CE2750014CFE1 /* TypeNameProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypeNameProtocol.swift; sourceTree = ""; }; - C83162A62B4CE5160014CFE1 /* UIScrollView+RxSwift.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScrollView+RxSwift.swift"; sourceTree = ""; }; C83C18652B33E438002FD985 /* bill.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = bill.json; sourceTree = ""; }; C83C18662B33E438002FD985 /* service.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = service.json; sourceTree = ""; }; C83C18672B33E438002FD985 /* goods.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = goods.json; sourceTree = ""; }; @@ -210,6 +209,7 @@ C86DB2162B3E8DBC002126F5 /* NYSLoginViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NYSLoginViewController.swift; sourceTree = ""; }; C86DB21D2B3E9E22002126F5 /* WRNavigationBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WRNavigationBar.swift; sourceTree = ""; }; C86DB21E2B3E9E22002126F5 /* WRCustomNavigationBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WRCustomNavigationBar.swift; sourceTree = ""; }; + C87021032BC278C60056A806 /* UIView+RxSwift.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+RxSwift.swift"; sourceTree = ""; }; C8713F492B69E5690090B289 /* PullUpController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PullUpController.swift; sourceTree = ""; }; C8713F4C2B69EC420090B289 /* NYSPullerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NYSPullerViewController.swift; sourceTree = ""; }; C8713F4D2B69EC420090B289 /* NYSPullerViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NYSPullerViewController.xib; sourceTree = ""; }; @@ -384,7 +384,7 @@ isa = PBXGroup; children = ( C87CAB742B46773600C84E8E /* Rx+Operators.swift */, - C83162A62B4CE5160014CFE1 /* UIScrollView+RxSwift.swift */, + C87021032BC278C60056A806 /* UIView+RxSwift.swift */, ); path = RxSwift; sourceTree = ""; @@ -989,6 +989,7 @@ C8ED6DE92B551939000F2268 /* NYSServiceCollectionViewCell.swift in Sources */, C8C5D2432B3E628600117F58 /* NYSBannerCollectionViewCell.swift in Sources */, C821AAB72B46B2CA003C0968 /* NYSToolBar.m in Sources */, + C87021042BC278C60056A806 /* UIView+RxSwift.swift in Sources */, C82F2FC12B6E265F00A8F816 /* UIImageView+Extension.swift in Sources */, C816B6662B4F7B6F00256E58 /* NYSWeaterData.swift in Sources */, C87CAB7D2B467C8E00C84E8E /* NYSUserInfo.swift in Sources */, @@ -1034,7 +1035,6 @@ C8A4BE312B4BBA1800152E14 /* UITableView+Extension.swift in Sources */, C8474E532B43DD54001DE04A /* NYSRootViewController.swift in Sources */, C8958BB02B6B5FE400693DAE /* NYSPreviewViewController.swift in Sources */, - C83162A72B4CE5160014CFE1 /* UIScrollView+RxSwift.swift in Sources */, C89E827B2B731986002BEC52 /* AppDelegate+Extension.swift in Sources */, C85D7E7C2B60F34300C4BC93 /* NYSImageItemView.swift in Sources */, C8ED6DDB2B51494D000F2268 /* NYSRootWebViewController.swift in Sources */, @@ -1222,7 +1222,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = F9J739W8Y4; + DEVELOPMENT_TEAM = Y24AM9NS72; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "$(SRCROOT)/NYSExampleSwift/Supporting Files/PrefixHeader.pch"; GENERATE_INFOPLIST_FILE = YES; @@ -1237,7 +1237,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = com.nys.example.swift; + PRODUCT_BUNDLE_IDENTIFIER = com.nys.example.swiftDEV; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/NYSExampleSwift/Supporting Files/Bridging-Header.h"; @@ -1256,7 +1256,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = F9J739W8Y4; + DEVELOPMENT_TEAM = Y24AM9NS72; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "$(SRCROOT)/NYSExampleSwift/Supporting Files/PrefixHeader.pch"; GENERATE_INFOPLIST_FILE = YES; @@ -1271,7 +1271,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = com.nys.example.swift; + PRODUCT_BUNDLE_IDENTIFIER = com.nys.example.swiftDEV; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/NYSExampleSwift/Supporting Files/Bridging-Header.h"; diff --git a/Examples/Swift/NYSExampleSwift/Extension/RxSwift/UIScrollView+RxSwift.swift b/Examples/Swift/NYSExampleSwift/Extension/RxSwift/UIScrollView+RxSwift.swift deleted file mode 100644 index a419012..0000000 --- a/Examples/Swift/NYSExampleSwift/Extension/RxSwift/UIScrollView+RxSwift.swift +++ /dev/null @@ -1,72 +0,0 @@ -// -// UIScrollView+RxSwift.swift -// NYSAppSwift -// -// Created by Nico http://github.com/niyongsheng -// Copyright © 2023 NYS. ALL rights reserved. -// - -import Foundation -import RxSwift -import RxCocoa -import MJRefresh - -/// 供ViewModel使用 -enum MJRefreshAction { - /// 开始刷新 - case begainRefresh - /// 停止刷新 - case stopRefresh - /// 开始加载更多 - case begainLoadmore - /// 停止加载更多 - case stopLoadmore - /// 显示无更多数据 - case showNomoreData - /// 重置无更多数据 - case resetNomoreData -} - -// MARK: - Refresh -extension Reactive where Base: UIScrollView { - - /// 执行的操作类型 - var refreshAction: Binder { - - return Binder(base) { (target, action) in - - switch action { - case .begainRefresh: - if let header = target.mj_header { - header.beginRefreshing() - } - if let header = target.refreshControl { - header.beginRefreshing() - } - case .stopRefresh: - if let header = target.mj_header { - header.endRefreshing() - } - if let header = target.refreshControl { - header.endRefreshing() - } - case .begainLoadmore: - if let footer = target.mj_footer { - footer.beginRefreshing() - } - case .stopLoadmore: - if let footer = target.mj_footer { - footer.endRefreshing() - } - case .showNomoreData: - if let footer = target.mj_footer { - footer.endRefreshingWithNoMoreData() - } - case .resetNomoreData: - if let footer = target.mj_footer { - footer.resetNoMoreData() - } - } - } - } -} diff --git a/Examples/Swift/NYSExampleSwift/Extension/RxSwift/UIView+RxSwift.swift b/Examples/Swift/NYSExampleSwift/Extension/RxSwift/UIView+RxSwift.swift new file mode 100644 index 0000000..33daa4a --- /dev/null +++ b/Examples/Swift/NYSExampleSwift/Extension/RxSwift/UIView+RxSwift.swift @@ -0,0 +1,149 @@ +// +// UIView+RxSwift.swift +// NYSAppSwift +// +// Created by Nico http://github.com/niyongsheng +// Copyright © 2023 NYS. ALL rights reserved. +// + +import Foundation +import RxSwift +import RxCocoa +import MJRefresh + +/// 供ViewModel使用 +enum MJRefreshAction { + /// 开始刷新 + case begainRefresh + /// 停止刷新 + case stopRefresh + /// 开始加载更多 + case begainLoadmore + /// 停止加载更多 + case stopLoadmore + /// 显示无更多数据 + case showNomoreData + /// 重置无更多数据 + case resetNomoreData +} + +// MARK: - UIScrollView Refresh +extension Reactive where Base: UIScrollView { + + /// 执行的操作类型 + var refreshAction: Binder { + + return Binder(base) { (target, action) in + + switch action { + case .begainRefresh: + if let header = target.mj_header { + header.beginRefreshing() + } + if let header = target.refreshControl { + header.beginRefreshing() + } + case .stopRefresh: + if let header = target.mj_header { + header.endRefreshing() + } + if let header = target.refreshControl { + header.endRefreshing() + } + case .begainLoadmore: + if let footer = target.mj_footer { + footer.beginRefreshing() + } + case .stopLoadmore: + if let footer = target.mj_footer { + footer.endRefreshing() + } + case .showNomoreData: + if let footer = target.mj_footer as? MJRefreshAutoNormalFooter { + footer.setTitle("没有更多了", for: MJRefreshState.noMoreData) + footer.endRefreshingWithNoMoreData() + } + case .resetNomoreData: + if let footer = target.mj_footer { + footer.resetNoMoreData() + } + } + } + } +} + + +// MARK: - NYSBaseViewController Refresh +extension Reactive where Base: NYSBaseViewController { + + /// 执行的操作类型 + var refreshAction: Binder { + + return Binder(base) { (target, action) in + + switch action { + case .begainRefresh: + if let header = target.tableView.mj_header { + header.beginRefreshing() + } + if let header = target.tableView.refreshControl { + header.beginRefreshing() + } + if let header = target.collectionView.mj_header { + header.beginRefreshing() + } + if let header = target.collectionView.refreshControl { + header.beginRefreshing() + } + target.emptyError = NSError(code: .codeUnKnow, description: "加载中...", reason: "", suggestion: "重试", placeholderImg: "icon_loading_nys") + case .stopRefresh: + if let header = target.tableView.mj_header { + header.endRefreshing() + } + if let header = target.tableView.refreshControl { + header.endRefreshing() + } + if let header = target.collectionView.mj_header { + header.endRefreshing() + } + if let header = target.collectionView.refreshControl { + header.endRefreshing() + } + target.emptyError = NSError(code: .codeUnKnow, description: "没有更多了", reason: "", suggestion: "重试", placeholderImg: "icon_error_nys") + case .begainLoadmore: + if let footer = target.tableView.mj_footer { + footer.beginRefreshing() + } + if let footer = target.collectionView.mj_footer { + footer.beginRefreshing() + } + target.emptyError = NSError(code: .codeUnKnow, description: "加载中...", reason: "", suggestion: "重试", placeholderImg: "icon_loading_nys") + case .stopLoadmore: + if let footer = target.tableView.mj_footer { + footer.endRefreshing() + } + if let footer = target.collectionView.mj_footer { + footer.endRefreshing() + } + target.emptyError = NSError(code: .codeUnKnow, description: "没有更多了", reason: "", suggestion: "重试", placeholderImg: "icon_error_nys") + case .showNomoreData: + if let footer = target.tableView.mj_footer as? MJRefreshAutoNormalFooter { + footer.setTitle("没有更多了", for: MJRefreshState.noMoreData) + footer.endRefreshingWithNoMoreData() + } + if let footer = target.collectionView.mj_footer as? MJRefreshAutoNormalFooter { + footer.setTitle("没有更多了", for: MJRefreshState.noMoreData) + footer.endRefreshingWithNoMoreData() + } + target.emptyError = NSError(code: .codeUnKnow, description: "没有更多了", reason: "", suggestion: "重试", placeholderImg: "icon_error_nys") + case .resetNomoreData: + if let footer = target.tableView.mj_footer { + footer.resetNoMoreData() + } + if let footer = target.collectionView.mj_footer { + footer.resetNoMoreData() + } + } + } + } +} diff --git a/Examples/Swift/NYSExampleSwift/Manager/M/AppManager.swift b/Examples/Swift/NYSExampleSwift/Manager/M/AppManager.swift index 9a0550e..5f68604 100644 --- a/Examples/Swift/NYSExampleSwift/Manager/M/AppManager.swift +++ b/Examples/Swift/NYSExampleSwift/Manager/M/AppManager.swift @@ -77,11 +77,13 @@ extension AppManager { /// 登入 func loginHandler(loginType: AppLoginType, params: [String: Any], completion: AppManagerCompletion) { - NYSNetRequest.mockRequest(withParameters: "login_data.json", - isCheck: true, + NYSNetRequest.mockRequest(with: .GET, + url: "login_data.json", + parameters: nil, remark: "登录", success: { [weak self] response in - if let token = response?["token"] as? String { + let respDict = response as? [String: Any] + if let token = respDict?["token"] as? String { self?.token = token completion?(true, nil, nil) } else { @@ -124,13 +126,15 @@ extension AppManager { return } - NYSNetRequest.mockRequest(withParameters: "userinfo_data.json", - isCheck: true, + NYSNetRequest.mockRequest(with: .GET, + url: "userinfo_data.json", + parameters: nil, remark: "重载用户信息", success: { [weak self] response in do { - let userinfo = try response?.decoded() as NYSUserInfo? + let respDict = response as? [String: Any] + let userinfo = try respDict?.decoded() as NYSUserInfo? self?.userInfo = userinfo ?? NYSUserInfo() let tagSet: Set = Set(userinfo!.tagArr) diff --git a/Examples/Swift/NYSExampleSwift/Modules/Account/C/NYSAccountViewController.swift b/Examples/Swift/NYSExampleSwift/Modules/Account/C/NYSAccountViewController.swift index 7c12c4f..0af7622 100644 --- a/Examples/Swift/NYSExampleSwift/Modules/Account/C/NYSAccountViewController.swift +++ b/Examples/Swift/NYSExampleSwift/Modules/Account/C/NYSAccountViewController.swift @@ -75,7 +75,7 @@ class NYSAccountViewController: NYSRootViewController, UITextViewDelegate { protocolT.delegate = self protocolT.attributedText = attString - self.view.addSubview(self.checkBox) + self.contenView.addSubview(self.checkBox) } override func configTheme() { @@ -92,7 +92,7 @@ class NYSAccountViewController: NYSRootViewController, UITextViewDelegate { NYSTools.shakeAnimation(self.checkBox.layer) tipV.message = "请勾选" tipV.autoDismiss(animated: true, atTimeInterval: 2) - tipV.presentPointing(at: self.checkBox, in: view, animated: true) + tipV.presentPointing(at: self.checkBox, in: contenView, animated: true) return } self.navigationController?.pushViewController(NYSLoginViewController(), animated: true) diff --git a/Examples/Swift/NYSExampleSwift/Modules/Account/C/NYSLoginViewController.swift b/Examples/Swift/NYSExampleSwift/Modules/Account/C/NYSLoginViewController.swift index 9bf7eb0..51b4664 100644 --- a/Examples/Swift/NYSExampleSwift/Modules/Account/C/NYSLoginViewController.swift +++ b/Examples/Swift/NYSExampleSwift/Modules/Account/C/NYSLoginViewController.swift @@ -37,6 +37,11 @@ class NYSLoginViewController: NYSRootViewController { self.loginBtn.backgroundColor = NAppThemeColor self.accountView.addCornerRadius(NAppRadius/2, borderWidth: 1, borderColor: NAppThemeColor) self.passwordView.addCornerRadius(NAppRadius/2, borderWidth: 1, borderColor: NAppThemeColor) + +#if DEBUG + accountTF.text = "18888888888" + passwordTF.text = "123456" +#endif } override func configTheme() { @@ -50,7 +55,7 @@ class NYSLoginViewController: NYSRootViewController { } @IBAction func loginBtnOnclicked(_ sender: NYSLoadingButton) { - sender.start(LoadingType(rawValue: 2)) + sender.start(.INDICATOR) AppManager.shared.loginHandler(loginType: .unknown, params: ["": ""]) { isSuccess, userInfo, error in if isSuccess { diff --git a/Examples/Swift/NYSExampleSwift/Modules/Mine/V/C/Setting/NYSThirdPartyViewController.swift b/Examples/Swift/NYSExampleSwift/Modules/Mine/V/C/Setting/NYSThirdPartyViewController.swift index 09e95c7..f3a5260 100644 --- a/Examples/Swift/NYSExampleSwift/Modules/Mine/V/C/Setting/NYSThirdPartyViewController.swift +++ b/Examples/Swift/NYSExampleSwift/Modules/Mine/V/C/Setting/NYSThirdPartyViewController.swift @@ -31,7 +31,7 @@ class NYSThirdPartyViewController: NYSRootViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) -// self.tableView.reloadData(animationType: .alpha) +// self.tableView.reloadData(animationType: .moveSpring) } override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { diff --git a/Examples/Swift/NYSExampleSwift/Modules/Mission/V/NYSMissionViewController.swift b/Examples/Swift/NYSExampleSwift/Modules/Mission/V/NYSMissionViewController.swift index a486775..93384e7 100644 --- a/Examples/Swift/NYSExampleSwift/Modules/Mission/V/NYSMissionViewController.swift +++ b/Examples/Swift/NYSExampleSwift/Modules/Mission/V/NYSMissionViewController.swift @@ -155,7 +155,7 @@ extension NYSMissionViewController { vm.weatherRefresh.bind(to: self.tableView.rx.refreshAction).disposed(by: bag) vm.weatherSubject.subscribe(onNext: { [weak self] (item: NYSWeater) in self?.dataSourceArr.insert(item, at: 0) - self?.tableView.reloadData(animationType: .rote) + self?.tableView.reloadData(animationType: .moveSpring) }, onError: { (error) in print("Error: \(error)") }).disposed(by: bag) diff --git a/Examples/Swift/NYSExampleSwift/Modules/Mission/VM/NYSMissionViewModel.swift b/Examples/Swift/NYSExampleSwift/Modules/Mission/VM/NYSMissionViewModel.swift index 174fa1a..4e3abf5 100644 --- a/Examples/Swift/NYSExampleSwift/Modules/Mission/VM/NYSMissionViewModel.swift +++ b/Examples/Swift/NYSExampleSwift/Modules/Mission/VM/NYSMissionViewModel.swift @@ -20,13 +20,14 @@ class NYSMissionViewModel: NYSRootViewModel { /// - Parameter headerRefresh: 是否头部刷新 func fetchWeatherData(headerRefresh: Bool, parameters: [String: Any]?) { NYSNetRequest.jsonNoCheckNetworkRequest( - with: NYSNetRequestType(GET.rawValue), + with: .GET, url: Api_Weather_Url, parameters: parameters, remark: "天气数据", success: { [weak self] response in - if response!["errcode"] as? Int == 100 { - let msg = response!["errmsg"] as! String + let respDict = response as? [String: Any] + if respDict!["errcode"] as? Int == 100 { + let msg = respDict!["errmsg"] as! String AlertManager.shared.showAlert(title: msg) self?.errorSubject.onNext(NYSError(domain: msg, code: -1, userInfo: nil)) return @@ -50,8 +51,9 @@ class NYSMissionViewModel: NYSRootViewModel { /// Mock天气数据 func mockWeatherData(headerRefresh: Bool, parameters: String) { - NYSNetRequest.mockRequest(withParameters: parameters, - isCheck: false, + NYSNetRequest.mockRequest(with: .GET, + url: parameters, + parameters: nil, remark: "天气数据", success: { [weak self] response in do { diff --git a/Examples/Swift/NYSExampleSwift/Modules/Service/VM/NYSServiceViewModel.swift b/Examples/Swift/NYSExampleSwift/Modules/Service/VM/NYSServiceViewModel.swift index 0ddd2d9..2941d36 100644 --- a/Examples/Swift/NYSExampleSwift/Modules/Service/VM/NYSServiceViewModel.swift +++ b/Examples/Swift/NYSExampleSwift/Modules/Service/VM/NYSServiceViewModel.swift @@ -17,14 +17,14 @@ class NYSServiceViewModel: NYSRootViewModel { /// Mock数据 func mockServiceData(headerRefresh: Bool, parameters: String) { - NYSNetRequest.mockRequest(withParameters: parameters, - isCheck: true, + NYSNetRequest.mockRequest(with: .GET, + url: parameters, + parameters: nil, remark: nil, success: { [weak self] response in do { -// let jsonData = try JSONSerialization.data(withJSONObject: response?["list"] as Any, options: []) -// let items = try [NYSService].decoded(from: jsonData) - let items = try [NYSService].decoded(from: response?["list"] as! [Any]) + let respDict = response as? [String: Any] + let items = try [NYSService].decoded(from: respDict?["list"] as! [Any]) if headerRefresh { self?.serviceItems.onNext(items) self?.serviceRefresh.onNext(.stopRefresh) diff --git a/Examples/Swift/NYSExampleSwift/RootClass/NYSRootViewController.swift b/Examples/Swift/NYSExampleSwift/RootClass/NYSRootViewController.swift index 2b66bf5..24d426c 100644 --- a/Examples/Swift/NYSExampleSwift/RootClass/NYSRootViewController.swift +++ b/Examples/Swift/NYSExampleSwift/RootClass/NYSRootViewController.swift @@ -44,6 +44,14 @@ class NYSRootViewController: NYSBaseViewController { super.bindViewModel() } + override func headerRereshing() { + self.emptyError = NSError(code: .codeUnKnow, description: "加载中...", reason: "", suggestion: "重试", placeholderImg: "icon_loading_nys") + } + + override func footerRereshing() { + self.emptyError = NSError(code: .codeUnKnow, description: "加载中...", reason: "", suggestion: "重试", placeholderImg: "icon_loading_nys") + } + } extension NYSRootViewController { diff --git a/Examples/Swift/NYSExampleSwift/Supporting Files/AppDelegate.swift b/Examples/Swift/NYSExampleSwift/Supporting Files/AppDelegate.swift index 14cd8d8..4174165 100644 --- a/Examples/Swift/NYSExampleSwift/Supporting Files/AppDelegate.swift +++ b/Examples/Swift/NYSExampleSwift/Supporting Files/AppDelegate.swift @@ -85,6 +85,7 @@ extension AppDelegate { func initNetwork() { NYSKitManager.shared().host = Api_Base_Url NYSKitManager.shared().token = AppManager.shared.token + NYSKitManager.shared().dataKey = "data" NYSKitManager.shared().normalCode = "200,0" NYSKitManager.shared().tokenInvalidCode = "500" NYSKitManager.shared().msgKey = "msg" diff --git a/Examples/Swift/Podfile.lock b/Examples/Swift/Podfile.lock index 1d59384..8bba0c7 100644 --- a/Examples/Swift/Podfile.lock +++ b/Examples/Swift/Podfile.lock @@ -52,12 +52,12 @@ PODS: - Kingfisher (7.10.1) - lottie-ios (2.5.3) - MJRefresh (3.7.6) - - NYSKit (0.0.6): + - NYSKit (0.0.7): - AFNetworking (~> 4.0) - SVProgressHUD (~> 2.0) - - NYSUIKit (0.0.6): + - NYSUIKit (0.0.7): - MJRefresh (~> 3.7.6) - - NYSKit (~> 0.0.1) + - NYSKit (~> 0.0.7) - RxCocoa (6.6.0): - RxRelay (= 6.6.0) - RxSwift (= 6.6.0) @@ -160,8 +160,8 @@ SPEC CHECKSUMS: Kingfisher: bc5abe80a8e0144537ef1dd5a0b2621b04f7f439 lottie-ios: a50d5c0160425cd4b01b852bb9578963e6d92d31 MJRefresh: 2fe7fb43a5167ceda20bb7e63f130c04fd1814a5 - NYSKit: b632a9f33c4c19103f66ba3276b8d519ece9f123 - NYSUIKit: 01e93c7f1e7482f8b2052c61dab3a4db036701f0 + NYSKit: a2873b9901d83616c48d558320b14efcaac98635 + NYSUIKit: 66e82bc87d032139b7cb7ce7654ac59356c9e922 RxCocoa: 44a80de90e25b739b5aeaae3c8c371a32e3343cc RxRelay: 45eaa5db8ee4fb50e5ebd57deec0159e97fa51e6 RxSwift: a4b44f7d24599f674deebd1818eab82e58410632 diff --git a/NYSKit.podspec b/NYSKit.podspec index ebf733c..0b902ce 100644 --- a/NYSKit.podspec +++ b/NYSKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'NYSKit' - s.version = '0.0.6' + s.version = '0.0.7' s.platform = :ios, '13.0' s.summary = 'iOS scaffold core framework.' s.homepage = 'https://github.com/niyongsheng/NYSKit' diff --git a/NYSKit/NYSKit.h b/NYSKit/NYSKit.h index 0f258b7..f1cdb62 100644 --- a/NYSKit/NYSKit.h +++ b/NYSKit/NYSKit.h @@ -22,5 +22,6 @@ FOUNDATION_EXPORT const unsigned char NYSKitVersionString[]; #import #import #import +#import #import #import diff --git a/NYSKit/NYSKitManager.h b/NYSKit/NYSKitManager.h index e1d55f0..60a95cd 100644 --- a/NYSKit/NYSKitManager.h +++ b/NYSKit/NYSKitManager.h @@ -11,22 +11,27 @@ + (NYSKitManager *_Nonnull)sharedNYSKitManager; -#pragma mark - 网络请求配置 +#pragma mark - 网络请求参数配置 /// 请求地址 @property (nonatomic, strong) NSString * _Nonnull host; -/// 授权令牌 +/// token令牌 @property (nonatomic, strong) NSString * _Nullable token; -/// 正常返回代码 +/// 正常返回代码(多个值以','分割) @property (nonatomic, strong) NSString * _Nonnull normalCode; -/// 令牌失效错误码 +/// 统一的数据Key(不设置返回所有字段) +@property (nonatomic, strong) NSString * _Nonnull dataKey; +/// 错误信息Key +@property (nonatomic, strong) NSString * _Nonnull msgKey; +/// 是否Toast错误信息 default:NO +@property (nonatomic, assign) BOOL isAlwaysShowErrorMsg; + +/// token令牌失效错误码 @property (nonatomic, strong) NSString * _Nonnull tokenInvalidCode; +/// token令牌失效错误信息 @property (nonatomic, strong) NSString * _Nonnull tokenInvalidMessage; /// 被踢/其他设备登录-错误码 @property (nonatomic, strong) NSString * _Nonnull kickedCode; -/// 错误信息Key -@property (nonatomic, strong) NSString * _Nonnull msgKey; -/// 总是Toast错误信息 -@property (nonatomic, assign) BOOL isAlwaysShowErrorMsg; + #pragma mark - Other diff --git a/NYSKit/NYSKitManager.m b/NYSKit/NYSKitManager.m index a3b0893..92cca2f 100644 --- a/NYSKit/NYSKitManager.m +++ b/NYSKit/NYSKitManager.m @@ -46,4 +46,18 @@ - (NSString *)msgKey { return _msgKey; } +- (NSString *)dataKey { + if (!_dataKey) { + _dataKey = @""; + } + return _dataKey; +} + +- (NSString *)tokenInvalidMessage { + if (!_tokenInvalidMessage) { + _tokenInvalidMessage = @""; + } + return _tokenInvalidMessage; +} + @end diff --git a/NYSKit/NYSNetRequest.h b/NYSKit/NYSNetRequest.h index 872e812..f39ccb0 100644 --- a/NYSKit/NYSNetRequest.h +++ b/NYSKit/NYSNetRequest.h @@ -6,6 +6,7 @@ // #import +#import // 被踢下线 #define NNotificationOnKick @"KNotificationOnKick" @@ -14,14 +15,14 @@ // 网络状态 #define NNotificationNetworkChange @"KNotificationNetworkChange" -typedef enum : NSUInteger { +typedef NS_ENUM(NSInteger, NYSNetRequestType) { GET = 0, POST, DELETE, PUT -} NYSNetRequestType; +}; -typedef void(^NYSNetRequestSuccess)(NSDictionary * _Nullable response); +typedef void(^NYSNetRequestSuccess)(id _Nullable response); typedef void(^NYSNetRequestFailed)(NSError * _Nullable error); @interface NYSNetRequest : NSObject @@ -29,51 +30,69 @@ typedef void(^NYSNetRequestFailed)(NSError * _Nullable error); /// Form表单网络请求 + (void)requestNetworkWithType:(NYSNetRequestType)type url:(NSString * _Nonnull)url parameters:(id _Nullable)parameters remark:(NSString * _Nullable)remark success:(NYSNetRequestSuccess _Nullable)success failed:(NYSNetRequestFailed _Nullable)failed; +/// Form表单网络请求 +/// 不校验接口返回数据的合法性 ++ (void)requestNoCheckNetworkWithType:(NYSNetRequestType)type url:(NSString * _Nonnull)url parameters:(id _Nullable)parameters remark:(NSString * _Nullable)remark success:(NYSNetRequestSuccess _Nullable)success failed:(NYSNetRequestFailed _Nullable)failed; + /// JSON传参网络请求 + (void)jsonNetworkRequestWithType:(NYSNetRequestType)type url:(NSString * _Nonnull)url parameters:(id _Nullable)parameters remark:(NSString * _Nullable)remark success:(NYSNetRequestSuccess _Nullable)success failed:(NYSNetRequestFailed _Nullable)failed; -/// JSON传参网络请求(不统一检查接口返回数据的合法性) +/// JSON传参网络请求 +/// 不校验接口返回数据的合法性 + (void)jsonNoCheckNetworkRequestWithType:(NYSNetRequestType)type url:(NSString * _Nonnull)url parameters:(id _Nullable)parameters remark:(NSString * _Nullable)remark success:(NYSNetRequestSuccess _Nullable)success failed:(NYSNetRequestFailed _Nullable)failed; +/// JSON传参网络请求 +/// 自定义数据序列化方式responseSerializer ++ (void)jsonRequestWithType:(NYSNetRequestType)type + url:(NSString * _Nonnull)url + parameters:(id _Nullable)parameters + responseSerializer:(id _Nonnull)responseSerializer + isCheck:(BOOL)isCheck + remark:(NSString * _Nullable)remark + success:(NYSNetRequestSuccess _Nullable)success + failed:(NYSNetRequestFailed _Nullable)failed; + /// 文件上传 + (void)uploadImagesWithType:(NYSNetRequestType)type - url:(NSString * _Nonnull)url + url:(NSString * _Nonnull)url parameters:(id _Nullable)parameters - name:(NSString * _Nonnull)name + name:(NSString * _Nonnull)name files:(NSArray * _Nonnull)files - fileNames:(NSArray *_Nullable)fileNames - imageScale:(CGFloat)imageScale - imageType:(NSString * _Nullable)imageType - remark:(id _Nullable)remark - progress:(nullable void (^)(NSProgress * _Nonnull))process - success:(NYSNetRequestSuccess _Nullable )success + fileNames:(NSArray * _Nullable)fileNames + imageScale:(CGFloat)imageScale + imageType:(NSString * _Nullable)imageType + remark:(NSString * _Nullable)remark + responseSerializer:(id _Nonnull)responseSerializer + progress:(nullable void (^)(NSProgress * _Nonnull))process + success:(NYSNetRequestSuccess _Nullable )success failed:(NYSNetRequestFailed _Nullable )failed; /// 阿里云OSS图片上传 + (void)ossUploadImageWithuUrlStr:(NSString * _Nonnull)urlStr - parameters:(id _Nullable)parameters - name:(NSString * _Nonnull)name - image:(UIImage * _Nonnull)image - imageName:(NSString * _Nonnull)imageName - imageScale:(CGFloat)imageScale - imageType:(NSString * _Nullable)imageType - remark:(id _Nullable)remark - progress:(nullable void (^)(NSProgress * _Nullable))process - success:(NYSNetRequestSuccess _Nullable )success - failed:(NYSNetRequestFailed _Nullable )failed; + parameters:(id _Nullable)parameters + name:(NSString * _Nonnull)name + image:(UIImage * _Nonnull)image + imageName:(NSString * _Nonnull)imageName + imageScale:(CGFloat)imageScale + imageType:(NSString * _Nullable)imageType + remark:(id _Nullable)remark + progress:(nullable void (^)(NSProgress * _Nullable))process + success:(NYSNetRequestSuccess _Nullable )success + failed:(NYSNetRequestFailed _Nullable )failed; #pragma mark - Mock /// Mock网络请求 /// - Parameters: -/// - parameters: 参数:文件名xxx.json || 路径xx/xx/xxx.txt -/// - isCheck: 是否校验 +/// - type: 请求方式 +/// - url: 路径:xxx.json || xx/xx/xxx.json +/// - parameters: 参数 /// - remark: 备注 /// - success: 读取成功回调 /// - failed: 读取失败回调 -+ (void)mockRequestWithParameters:(NSString * _Nonnull)parameters isCheck:(BOOL)isCheck remark:(NSString * _Nullable)remark success:(NYSNetRequestSuccess _Nullable)success failed:(NYSNetRequestFailed _Nullable)failed; ++ (void)mockRequestWithType:(NYSNetRequestType)type url:(NSString * _Nonnull)url parameters:(id _Nullable)parameters remark:(NSString * _Nullable)remark success:(NYSNetRequestSuccess _Nullable)success failed:(NYSNetRequestFailed _Nullable)failed; /// JSON样式编码 /// - Parameter dict: 字典 -+ (NSString *)jsonPrettyStringEncoded:(NSDictionary *)dict; ++ (NSString * _Nonnull)jsonPrettyStringEncoded:(NSDictionary * _Nonnull)dict; @end diff --git a/NYSKit/NYSNetRequest.m b/NYSKit/NYSNetRequest.m index 218b44f..49179fa 100644 --- a/NYSKit/NYSNetRequest.m +++ b/NYSKit/NYSNetRequest.m @@ -9,11 +9,10 @@ #import "NYSKitPublicHeader.h" #import "NYSTools.h" #import -#import #define isShowTimes NO #define TimeoutInterval 15 -#define ShowDelayLoading 4.5f +#define ShowDelayLoading 1.5f #define MockDelayLoading 0.5f @interface NYSNetRequest () @@ -35,7 +34,6 @@ + (AFHTTPSessionManager *)sharedManager { [contentTypes addObject:@"application/json"]; [contentTypes addObject:@"application/octet-stream"]; manager.responseSerializer.acceptableContentTypes = contentTypes; - manager.responseSerializer = [AFJSONResponseSerializer serializer]; [manager.requestSerializer setTimeoutInterval:TimeoutInterval]; [[AFNetworkReachabilityManager sharedManager] startMonitoring]; @@ -48,10 +46,15 @@ + (AFHTTPSessionManager *)sharedManager { + (NSDictionary *)headers { NSMutableDictionary *headerDic = [NSMutableDictionary dictionary]; - NSString *identifierStr = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; + NSString *uuid = [NYSTools getDeviceIdentifier]; + [headerDic setValue:uuid forKey:@"x-device-imei"]; + NSString *language = [[NSBundle mainBundle] preferredLocalizations].firstObject; // @"zh_CN" + [headerDic setValue:language forKey:@"Accept-hips-Language"]; - [headerDic setValue:identifierStr forKey:@"identifier"]; - [headerDic setValue:[[NYSKitManager sharedNYSKitManager] token] forKey:@"token"]; + NSString *tokenStr = [[NYSKitManager sharedNYSKitManager] token]; + if (![NYSTools isBlankString:tokenStr]) { + [headerDic setValue:[NSString stringWithFormat:@"Bearer %@", tokenStr] forKey:@"Authorization"]; + } [headerDic setValue:[[UIDevice currentDevice] systemName] forKey:@"deviceSystemName"]; [headerDic setValue:[[UIDevice currentDevice] systemVersion] forKey:@"systemVersion"]; [headerDic setValue:[[UIDevice currentDevice] localizedModel] forKey:@"localizedModel"]; @@ -61,9 +64,41 @@ + (NSDictionary *)headers { } #pragma mark - Form表单网络请求 -+ (void)requestNetworkWithType:(NYSNetRequestType)type url:(NSString * _Nonnull)url parameters:(id)parameters remark:(NSString *)remark success:(NYSNetRequestSuccess _Nullable )success failed:(NYSNetRequestFailed _Nullable )failed { ++ (void)requestNetworkWithType:(NYSNetRequestType)type + url:(NSString * _Nonnull)url + parameters:(id)parameters + remark:(NSString *)remark + success:(NYSNetRequestSuccess _Nullable )success + failed:(NYSNetRequestFailed _Nullable )failed { + [self requestNetworkWithType:type url:url parameters:parameters isCheck:YES remark:remark success:success failed:failed]; +} + ++ (void)requestNoCheckNetworkWithType:(NYSNetRequestType)type + url:(NSString * _Nonnull)url + parameters:(id)parameters + remark:(NSString *)remark + success:(NYSNetRequestSuccess _Nullable )success + failed:(NYSNetRequestFailed _Nullable )failed { + [self requestNetworkWithType:type url:url parameters:parameters isCheck:NO remark:remark success:success failed:failed]; +} + ++ (void)requestNetworkWithType:(NYSNetRequestType)type + url:(NSString * _Nonnull)url + parameters:(id)parameters + isCheck:(BOOL)isCheck + remark:(NSString *)remark + success:(NYSNetRequestSuccess _Nullable )success + failed:(NYSNetRequestFailed _Nullable )failed { NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970]; + AFHTTPResponseSerializer *serializer = [AFJSONResponseSerializer serializer]; + /** + NSMutableIndexSet *acceptableStatusCodes = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 2)]; + [acceptableStatusCodes addIndex:401]; // 添加需要认为是成功的状态码,即使状态码出错也继续解析数据 + serializer.acceptableStatusCodes = acceptableStatusCodes; + */ + [self sharedManager].responseSerializer = serializer; + NSDictionary *header = [self headers]; NSString *urlStr = [[[NYSKitManager sharedNYSKitManager] host] stringByAppendingString:url]; if ([url containsString:@"http"]) { @@ -74,12 +109,16 @@ + (void)requestNetworkWithType:(NYSNetRequestType)type url:(NSString * _Nonnull) case GET: { [[self sharedManager] GET:urlStr parameters:parameters headers:header progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { handelLog(remark, urlStr, @"GET", header, parameters, responseObject, NO, timeStamp); - handelResponse(parameters, failed, remark, responseObject, success, urlStr); + if (isCheck) { + handelResponse(parameters, failed, remark, responseObject, success, urlStr); + } else { + if (success) success(responseObject); + } } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { if (failed) { failed(error); - handelError(error); + handelError(task, error); } }]; } @@ -88,12 +127,16 @@ + (void)requestNetworkWithType:(NYSNetRequestType)type url:(NSString * _Nonnull) case POST: { [[self sharedManager] POST:urlStr parameters:parameters headers:header progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { handelLog(remark, urlStr, @"POST", header, parameters, responseObject, NO, timeStamp); - handelResponse(parameters, failed, remark, responseObject, success, urlStr); + if (isCheck) { + handelResponse(parameters, failed, remark, responseObject, success, urlStr); + } else { + if (success) success(responseObject); + } } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { if (failed) { failed(error); - handelError(error); + handelError(task, error); } }]; } @@ -102,12 +145,16 @@ + (void)requestNetworkWithType:(NYSNetRequestType)type url:(NSString * _Nonnull) case PUT: { [[self sharedManager] PUT:urlStr parameters:parameters headers:header success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { handelLog(remark, urlStr, @"PUT", header, parameters, responseObject, NO, timeStamp); - handelResponse(parameters, failed, remark, responseObject, success, urlStr); + if (isCheck) { + handelResponse(parameters, failed, remark, responseObject, success, urlStr); + } else { + if (success) success(responseObject); + } } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { if (failed) { failed(error); - handelError(error); + handelError(task, error); } }]; } @@ -116,12 +163,16 @@ + (void)requestNetworkWithType:(NYSNetRequestType)type url:(NSString * _Nonnull) case DELETE: { [[self sharedManager] DELETE:urlStr parameters:parameters headers:header success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { handelLog(remark, urlStr, @"DELETE", header, parameters, responseObject, NO, timeStamp); - handelResponse(parameters, failed, remark, responseObject, success, urlStr); + if (isCheck) { + handelResponse(parameters, failed, remark, responseObject, success, urlStr); + } else { + if (success) success(responseObject); + } } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { if (failed) { failed(error); - handelError(error); + handelError(task, error); } }]; } @@ -134,22 +185,24 @@ + (void)requestNetworkWithType:(NYSNetRequestType)type url:(NSString * _Nonnull) #pragma mark - 文件上传 + (void)uploadImagesWithType:(NYSNetRequestType)type - url:(NSString * _Nonnull)url + url:(NSString * _Nonnull)url parameters:(id)parameters - name:(NSString *)name - files:(NSArray *)files - fileNames:(NSArray *)fileNames - imageScale:(CGFloat)imageScale - imageType:(NSString *)imageType - remark:(id)remark - progress:(nullable void (^)(NSProgress * _Nonnull))process - success:(NYSNetRequestSuccess _Nullable )success - failed:(NYSNetRequestFailed _Nullable )failed { + name:(NSString *)name + files:(NSArray *)files + fileNames:(NSArray *)fileNames + imageScale:(CGFloat)imageScale + imageType:(NSString *)imageType + remark:(NSString *)remark + responseSerializer:(id _Nonnull)responseSerializer + progress:(nullable void (^)(NSProgress * _Nonnull))process + success:(NYSNetRequestSuccess _Nullable )success + failed:(NYSNetRequestFailed _Nullable )failed { NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970]; NSDictionary *header = [self headers]; NSString *urlStr = [[[NYSKitManager sharedNYSKitManager] host] stringByAppendingString:url]; + [self sharedManager].responseSerializer = responseSerializer; [[self sharedManager] POST:urlStr parameters:parameters headers:header constructingBodyWithBlock:^(id _Nonnull formData) { for (NSUInteger i = 0; i < files.count; i++) { // 图片经过等比压缩后得到的二进制文件 @@ -164,7 +217,7 @@ + (void)uploadImagesWithType:(NYSNetRequestType)type name:name fileName:fileNames ? [NSString stringWithFormat:@"%@.%@",fileNames[i],imageType?:@"png"] : imageFileName mimeType:[NSString stringWithFormat:@"image/%@",imageType ?: @"png"]]; - + } } progress:^(NSProgress * _Nonnull uploadProgress) { @@ -182,36 +235,36 @@ + (void)uploadImagesWithType:(NYSNetRequestType)type [SVProgressHUD dismiss]; if (failed) { failed(error); - handelError(error); + handelError(task, error); } }]; } #pragma mark - 阿里云OSS图片上传 + (void)ossUploadImageWithuUrlStr:(NSString *)urlStr - parameters:(id)parameters - name:(NSString *)name - image:(UIImage *)image - imageName:(NSString *)imageName - imageScale:(CGFloat)imageScale - imageType:(NSString *)imageType - remark:(id)remark - progress:(nullable void (^)(NSProgress * _Nonnull))process - success:(NYSNetRequestSuccess _Nullable )success - failed:(NYSNetRequestFailed _Nullable )failed { + parameters:(id)parameters + name:(NSString *)name + image:(UIImage *)image + imageName:(NSString *)imageName + imageScale:(CGFloat)imageScale + imageType:(NSString *)imageType + remark:(id)remark + progress:(nullable void (^)(NSProgress * _Nonnull))process + success:(NYSNetRequestSuccess _Nullable )success + failed:(NYSNetRequestFailed _Nullable )failed { NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970]; [[self sharedManager] POST:urlStr parameters:parameters headers:nil constructingBodyWithBlock:^(id _Nonnull formData) { - - NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; - formatter.dateFormat = @"yyyy_MM_ddHH:mm:ss"; - NSString *tempName = [formatter stringFromDate:[NSDate date]]; - - NSData *imageData = UIImageJPEGRepresentation(image, 0.65f); - [formData appendPartWithFileData:imageData - name:name - fileName:imageName ? [NSString stringWithFormat:@"%@.%@", imageName, imageType ?:@"png"] : [NSString stringWithFormat:@"%@.%@", tempName, imageType] - mimeType:[NSString stringWithFormat:@"image/%@",imageType ?: @"png"]]; + + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; + formatter.dateFormat = @"yyyy_MM_ddHH:mm:ss"; + NSString *tempName = [formatter stringFromDate:[NSDate date]]; + + NSData *imageData = UIImageJPEGRepresentation(image, 0.65f); + [formData appendPartWithFileData:imageData + name:name + fileName:imageName ? [NSString stringWithFormat:@"%@.%@", imageName, imageType ?:@"png"] : [NSString stringWithFormat:@"%@.%@", tempName, imageType] + mimeType:[NSString stringWithFormat:@"image/%@",imageType ?: @"png"]]; } progress:^(NSProgress * _Nonnull uploadProgress) { //上传进度 @@ -225,21 +278,38 @@ + (void)ossUploadImageWithuUrlStr:(NSString *)urlStr } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { if (failed) { failed(error); - handelError(error); + handelError(task, error); } }]; } #pragma mark - JSON传参网络请求 -+ (void)jsonNetworkRequestWithType:(NYSNetRequestType)type url:(NSString * _Nonnull)url parameters:(id)parameters remark:(NSString * _Nullable)remark success:(NYSNetRequestSuccess)success failed:(NYSNetRequestFailed)failed { - [self jsonRequestWithType:type url:url parameters:parameters isCheck:YES remark:remark success:success failed:failed]; ++ (void)jsonNetworkRequestWithType:(NYSNetRequestType)type + url:(NSString * _Nonnull)url + parameters:(id)parameters + remark:(NSString * _Nullable)remark + success:(NYSNetRequestSuccess)success + failed:(NYSNetRequestFailed)failed { + [self jsonRequestWithType:type url:url parameters:parameters responseSerializer:[AFJSONResponseSerializer serializer] isCheck:YES remark:remark success:success failed:failed]; } -+ (void)jsonNoCheckNetworkRequestWithType:(NYSNetRequestType)type url:(NSString * _Nonnull)url parameters:(id)parameters remark:(NSString * _Nullable)remark success:(NYSNetRequestSuccess)success failed:(NYSNetRequestFailed)failed { - [self jsonRequestWithType:type url:url parameters:parameters isCheck:NO remark:remark success:success failed:failed]; ++ (void)jsonNoCheckNetworkRequestWithType:(NYSNetRequestType)type + url:(NSString * _Nonnull)url + parameters:(id)parameters + remark:(NSString * _Nullable)remark + success:(NYSNetRequestSuccess)success + failed:(NYSNetRequestFailed)failed { + [self jsonRequestWithType:type url:url parameters:parameters responseSerializer:[AFJSONResponseSerializer serializer] isCheck:NO remark:remark success:success failed:failed]; } -+ (void)jsonRequestWithType:(NYSNetRequestType)type url:(NSString * _Nonnull)url parameters:(id)parameters isCheck:(BOOL)isCheck remark:(NSString * _Nullable)remark success:(NYSNetRequestSuccess)success failed:(NYSNetRequestFailed)failed { ++ (void)jsonRequestWithType:(NYSNetRequestType)type + url:(NSString * _Nonnull)url + parameters:(id)parameters + responseSerializer:(id _Nonnull)responseSerializer + isCheck:(BOOL)isCheck + remark:(NSString * _Nullable)remark + success:(NYSNetRequestSuccess)success + failed:(NYSNetRequestFailed)failed { [self sharedManager]; NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970]; @@ -273,9 +343,13 @@ + (void)jsonRequestWithType:(NYSNetRequestType)type url:(NSString * _Nonnull)url [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; // 设置cookie NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - [request setValue:[NSString stringWithFormat:@"%@=%@", [defaults objectForKey:@"cookie.name"], [defaults objectForKey:@"cookie.value"]] forHTTPHeaderField:@"Cookie"]; + NSString *cookie = [defaults objectForKey:@"cookie.name"]; + NSString *cookieValue = [defaults objectForKey:@"cookie.value"]; + if (cookie && cookieValue) + [request setValue:[NSString stringWithFormat:@"%@=%@", cookie, cookieValue] forHTTPHeaderField:@"Cookie"]; AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; + manager.responseSerializer = responseSerializer; NSURLSessionDataTask *task = [manager dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil @@ -283,7 +357,7 @@ + (void)jsonRequestWithType:(NYSNetRequestType)type url:(NSString * _Nonnull)url [SVProgressHUD dismissWithDelay:1.0f]; [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(showLoadingAnimation) object:nil]; - handelLog(remark, urlStr, @"POST", [request allHTTPHeaderFields], parameters, responseObject, YES, timeStamp); + handelLog(remark, urlStr, method, [request allHTTPHeaderFields], parameters, responseObject, YES, timeStamp); if (!error) { // 获取cookie NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage]; @@ -299,16 +373,14 @@ + (void)jsonRequestWithType:(NYSNetRequestType)type url:(NSString * _Nonnull)url if (isCheck) { handelResponse(parameters, failed, remark, responseObject, success, urlStr); } else { - if (success) { - success(responseObject); - } + if (success) success(responseObject); } } else { DBGLog(@"\n[%@]\n%@", @"❌错误", error.localizedDescription); if (failed) { failed(error); - handelError(error); + handelError(task, error); } } }]; @@ -317,15 +389,16 @@ + (void)jsonRequestWithType:(NYSNetRequestType)type url:(NSString * _Nonnull)url } #pragma mark - Mock -+ (void)mockRequestWithParameters:(NSString * _Nonnull)parameters isCheck:(BOOL)isCheck remark:(NSString * _Nullable)remark success:(NYSNetRequestSuccess _Nullable)success failed:(NYSNetRequestFailed _Nullable)failed { ++ (void)mockRequestWithType:(NYSNetRequestType)type url:(NSString * _Nonnull)url parameters:(id)parameters remark:(NSString * _Nullable)remark success:(NYSNetRequestSuccess _Nullable)success failed:(NYSNetRequestFailed _Nullable)failed { + // url: 路径:文件名xxx.json || 路径xx/xx/xxx.json NSString *pattern = @"/|\\"; // 使用正则表达式判断是否包含斜杠或反斜杠 NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:nil]; - NSTextCheckingResult *isPath = [regex firstMatchInString:parameters options:0 range:NSMakeRange(0, parameters.length)]; + NSTextCheckingResult *isPath = [regex firstMatchInString:url options:0 range:NSMakeRange(0, url.length)]; NSString *filePath = nil; if (isPath) { - filePath = parameters; + filePath = url; } else { - NSArray *file = [parameters componentsSeparatedByString:@"."]; + NSArray *file = [url componentsSeparatedByString:@"."]; filePath = [[NSBundle mainBundle] pathForResource:file.firstObject ofType:file.lastObject]; } NSData *jsonData = [NSData dataWithContentsOfFile:filePath]; @@ -336,17 +409,11 @@ + (void)mockRequestWithParameters:(NSString * _Nonnull)parameters isCheck:(BOOL) DBGLog(@"\n[%@]\n%@", @"❌错误", error.localizedDescription); if (failed) { failed(error); - handelError(error); + handelError(nil, error); } } else { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(MockDelayLoading * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - if (isCheck) { - handelResponse(parameters, failed, remark, jsonDictionary, success, @"Mock"); - } else { - DBGLog(@"%@->📩:\nMock参数:\n%@\n[Data]:\n%@", remark, parameters, [NYSNetRequest jsonPrettyStringEncoded:jsonDictionary]); - if (success) - success(jsonDictionary); - } + handelResponse(parameters, failed, remark, jsonDictionary, success, @"Mock"); }); } } else { @@ -370,39 +437,54 @@ + (NSString *)jsonPrettyStringEncoded:(NSDictionary *)dict { #pragma mark - 响应体处理 static void handelResponse(id parameters, NYSNetRequestFailed _Nullable failed, NSString *remark, id _Nullable responseObject, NYSNetRequestSuccess _Nullable success, NSString * _Nonnull url) { - if ([responseObject isKindOfClass:NSData.class]) { - success(responseObject); + // 非字典类型不作合法性校验 + if (![responseObject isKindOfClass:NSDictionary.class]) { + if (success) success(responseObject); return; } - NSInteger code = [[responseObject objectForKey:@"code"] integerValue]; + NSString *msg = @"unknown error"; // 错误信息 for (NSString *key in [[[NYSKitManager sharedNYSKitManager] msgKey] componentsSeparatedByString:@","]) { NSString *message = [responseObject objectForKey:key]; - if (![NYSTools stringIsNull:message]) { + if (![NYSTools isBlankString:message]) { msg = message; break; } } + // 通过判断字典keys获取api状态值 + NSInteger code = -1; + if ([[(NSDictionary *)responseObject allKeys] containsObject:@"failed"]) { + code = [[responseObject objectForKey:@"failed"] boolValue] ? -1 : 0; + } else if ([[(NSDictionary *)responseObject allKeys] containsObject:@"code"]) { + code = [[responseObject objectForKey:@"code"] integerValue]; + } else if ([[(NSDictionary *)responseObject allKeys] containsObject:@"status"]) { + code = [[responseObject objectForKey:@"status"] integerValue]; + } else { + if (success) success(responseObject); + return; + } + NSArray *normalCodeArray = [[[NYSKitManager sharedNYSKitManager] normalCode] componentsSeparatedByString:@","]; BOOL isNormal = [normalCodeArray containsObject:[NSString stringWithFormat:@"%ld", code]]; if (isNormal) { // 正常返回 - NSDictionary *data = [responseObject objectForKey:@"data"]; if (success) { - success(data); - return; + NSString *dataKey = [[NYSKitManager sharedNYSKitManager] dataKey]; + [NYSTools isBlankString:dataKey] ? success(responseObject) : success(responseObject[dataKey]); } + return; + } else if (code == [[[NYSKitManager sharedNYSKitManager] kickedCode] integerValue]) { // 强制下线 [[NSNotificationCenter defaultCenter] postNotificationName:NNotificationOnKick object:msg]; } else if (code == [[[NYSKitManager sharedNYSKitManager] tokenInvalidCode] integerValue]) { // token失效 - if ([msg containsString:[[NYSKitManager sharedNYSKitManager] tokenInvalidMessage]]) { // 防止后端token失效的code不唯一 + NSString *tokenInvalidMessage = [[NYSKitManager sharedNYSKitManager] tokenInvalidMessage]; + if ([msg containsString:tokenInvalidMessage] || [NYSTools isBlankString:tokenInvalidMessage]) { // 防止后端token失效的code不唯一 [[NSNotificationCenter defaultCenter] postNotificationName:NNotificationTokenInvalidation object:msg]; } -// [NYSTools showBottomToast:msg]; } else { - // 错误Toast + // Err Msg Toast if ([[NYSKitManager sharedNYSKitManager] isAlwaysShowErrorMsg]) [NYSTools showBottomToast:msg]; } @@ -414,25 +496,34 @@ static void handelResponse(id parameters, NYSNetRequestFailed _Nullable failed, } #pragma mark - 错误码处理 -static void handelError(NSError * _Nullable error) { +static void handelError(NSURLSessionDataTask * _Nullable task, NSError * _Nullable error) { + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)task.response; + NSInteger statusCode = httpResponse.statusCode; + NSString *msg = nil; switch (error.code) { case -1001: - msg = @"请求超时,请检查网络!"; + msg = @"Time Out"; break; case -1004: - msg = @"无法连接到服务器"; + msg = @"Unable Connect To Server"; break; case -1009: - msg = @"网络不可用"; + msg = @"Network Unavailable"; break; case -1011: - msg = @"服务暂时不可用"; + msg = @"Server Unavailable"; break; default: msg = error.localizedDescription; } - [NYSTools showBottomToast:msg]; + + if (statusCode == 401 || [error.localizedDescription containsString:@"401"]) { // unauthorized + [[NSNotificationCenter defaultCenter] postNotificationName:NNotificationTokenInvalidation object:msg]; + + } else { + [NYSTools showBottomToast:msg]; + } #ifdef DEBUG NSLog(@"❌%@", error); #endif diff --git a/NYSKit/NYSRSAObjC.h b/NYSKit/NYSRSAObjC.h new file mode 100644 index 0000000..8ac4e0c --- /dev/null +++ b/NYSKit/NYSRSAObjC.h @@ -0,0 +1,46 @@ +// +// RSAObjC.h +// +// NYSKit http://github.com/niyongsheng +// Copyright © 2019 NYS. ALL rights reserved. +// + +#import + +@interface NYSRSAObjC : NSObject + +/** + * -------RSA 字符串公钥加密------- + @param plaintext 明文,待加密的字符串 + @param pubKey 公钥字符串 + @return 密文,加密后的字符串 + */ ++ (NSString *)encrypt:(NSString *)plaintext PublicKey:(NSString *)pubKey; + +/** + * -------RSA 公钥文件加密------- + @param plaintext 明文,待加密的字符串 + @param path 公钥文件路径,p12或pem格式 + @return 密文,加密后的字符串 + */ ++ (NSString *)encrypt:(NSString *)plaintext KeyFilePath:(NSString *)path; + +/** + * -------RSA 私钥字符串解密------- + @param ciphertext 密文,需要解密的字符串 + @param privKey 私钥字符串 + @return 明文,解密后的字符串 + */ ++ (NSString *)decrypt:(NSString *)ciphertext PrivateKey:(NSString *)privKey; + +/** + * -------RSA 私钥文件解密------- + @param ciphertext 密文,需要解密的字符串 + @param path 私钥文件路径,p12或pem格式(pem私钥需为pcks8格式) + @param pwd 私钥文件的密码 + @return 明文,解密后的字符串 + */ ++ (NSString *)decrypt:(NSString *)ciphertext KeyFilePath:(NSString *)path FilePwd:(NSString *)pwd; + + +@end diff --git a/NYSKit/NYSRSAObjC.m b/NYSKit/NYSRSAObjC.m new file mode 100644 index 0000000..fb60b5c --- /dev/null +++ b/NYSKit/NYSRSAObjC.m @@ -0,0 +1,527 @@ +// +// RSAObjC.m +// +// NYSKit http://github.com/niyongsheng +// Copyright © 2019 NYS. ALL rights reserved. +// + +#import "NYSRSAObjC.h" +#import + +@implementation NYSRSAObjC + +static NSString *base64_encode_data(NSData *data){ + data = [data base64EncodedDataWithOptions:0]; + NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + return ret; +} + +static NSData *base64_decode(NSString *str){ + NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters]; + return data; +} + +/** + * -------RSA 字符串公钥加密------- + @param plaintext 明文,待加密的字符串 + @param pubKey 公钥字符串 + @return 密文,加密后的字符串 + */ ++ (NSString *)encrypt:(NSString *)plaintext PublicKey:(NSString *)pubKey{ + if (plaintext.length == 0 || pubKey.length == 0) { + return nil; + } + NSData *data = [self encryptData:[plaintext dataUsingEncoding:NSUTF8StringEncoding] publicKey:pubKey]; + NSString *ret = base64_encode_data(data); + return ret; +} + +/** + * -------RSA 公钥文件加密------- + @param plaintext 明文,待加密的字符串 + @param path 公钥文件路径,p12或pem格式 + @return 密文,加密后的字符串 + */ ++ (NSString *)encrypt:(NSString *)plaintext KeyFilePath:(NSString *)path{ + if (plaintext.length == 0 || path.length == 0) { + return nil; + } + NSString *result = nil; + if ([path hasSuffix:@".pem"]) { + NSString *pubKey = [self readPubKeyFromPem:path]; + NSData *data = [self encryptData:[plaintext dataUsingEncoding:NSUTF8StringEncoding] publicKey:pubKey]; + result = base64_encode_data(data); + }else{ + SecKeyRef pubKeyRef = [self getPublicKeyRefWithContentsOfFile:path]; + result = [self encryptString:plaintext publicKeyRef:pubKeyRef]; + if (pubKeyRef) CFRelease(pubKeyRef); + } + return result; +} + +/** + * -------RSA 字符串私钥解密------- + @param ciphertext 密文,需要解密的字符串 + @param privKey 私钥字符串 + @return 明文,解密后的字符串 + */ ++ (NSString *)decrypt:(NSString *)ciphertext PrivateKey:(NSString *)privKey{ + if (ciphertext.length == 0 || privKey.length == 0) { + return nil; + } + + NSData *data = [[NSData alloc] initWithBase64EncodedString:ciphertext options:NSDataBase64DecodingIgnoreUnknownCharacters]; + data = [self decryptData:data privateKey:privKey]; + NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + + return ret; +} + +/** + * -------RSA 私钥文件解密------- + @param ciphertext 密文,需要解密的字符串 + @param path 私钥文件路径,p12或pem格式(pem私钥需为pcks8格式) + @param pwd 私钥文件的密码 + @return 明文,解密后的字符串 + */ ++ (NSString *)decrypt:(NSString *)ciphertext KeyFilePath:(NSString *)path FilePwd:(NSString *)pwd{ + if (ciphertext.length == 0 || path.length == 0) { + return nil; + } + if (!pwd) pwd = @""; + + NSString *result = nil; + if ([path hasSuffix:@".pem"]) { + NSString *privKey = [self readPrivKeyFromPem:path]; + NSData *data = [[NSData alloc] initWithBase64EncodedString:ciphertext options:NSDataBase64DecodingIgnoreUnknownCharacters]; + data = [self decryptData:data privateKey:privKey]; + result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + }else{ + result = [self decryptString:ciphertext privateKeyRef:[self getPrivateKeyRefWithContentsOfFile:path password:pwd]]; + } + return result; +} + ++ (NSString *)readPubKeyFromPem:(NSString *)filePath{ + NSString *pemStr = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; + if (pemStr.length == 0) { + return nil; + } + NSString *header = @"-----BEGIN PUBLIC KEY-----"; + NSString *footer = @"-----END PUBLIC KEY-----"; + pemStr = [pemStr stringByReplacingOccurrencesOfString:header withString:@""]; + pemStr = [pemStr stringByReplacingOccurrencesOfString:footer withString:@""]; + pemStr = [pemStr stringByReplacingOccurrencesOfString:@"\r" withString:@""]; + pemStr = [pemStr stringByReplacingOccurrencesOfString:@"\n" withString:@""]; + pemStr = [pemStr stringByReplacingOccurrencesOfString:@"\t" withString:@""]; + pemStr = [pemStr stringByReplacingOccurrencesOfString:@" " withString:@""]; + return pemStr; +} + ++ (NSString *)readPrivKeyFromPem:(NSString *)filePath{ + NSString *pemStr = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; + if (pemStr.length == 0) { + return nil; + } + NSString *header = @"-----BEGIN RSA PRIVATE KEY-----"; + NSString *footer = @"-----END RSA PRIVATE KEY-----"; + NSString *header_pkcs8 = @"-----BEGIN PRIVATE KEY-----"; + NSString *footer_pkcs8 = @"-----END PRIVATE KEY-----"; + pemStr = [pemStr stringByReplacingOccurrencesOfString:header withString:@""]; + pemStr = [pemStr stringByReplacingOccurrencesOfString:footer withString:@""]; + pemStr = [pemStr stringByReplacingOccurrencesOfString:header_pkcs8 withString:@""]; + pemStr = [pemStr stringByReplacingOccurrencesOfString:footer_pkcs8 withString:@""]; + pemStr = [pemStr stringByReplacingOccurrencesOfString:@"\r" withString:@""]; + pemStr = [pemStr stringByReplacingOccurrencesOfString:@"\n" withString:@""]; + pemStr = [pemStr stringByReplacingOccurrencesOfString:@"\t" withString:@""]; + pemStr = [pemStr stringByReplacingOccurrencesOfString:@" " withString:@""]; + return pemStr; +} + ++ (SecKeyRef)getPublicKeyRefWithContentsOfFile:(NSString *)filePath{ + NSData *certData = [NSData dataWithContentsOfFile:filePath]; + if (!certData) { + return NULL; + } + SecCertificateRef cert = SecCertificateCreateWithData(NULL, (CFDataRef)certData); + SecKeyRef key = NULL; + SecTrustRef trust = NULL; + SecPolicyRef policy = NULL; + if (cert != NULL) { + policy = SecPolicyCreateBasicX509(); + if (policy) { + if (SecTrustCreateWithCertificates((CFTypeRef)cert, policy, &trust) == noErr) { + SecTrustResultType result; + if (SecTrustEvaluate(trust, &result) == noErr) { + key = SecTrustCopyPublicKey(trust); + } + } + } + } + if (policy) CFRelease(policy); + if (trust) CFRelease(trust); + if (cert) CFRelease(cert); + return key; +} + ++ (NSString *)encryptString:(NSString *)str publicKeyRef:(SecKeyRef)publicKeyRef{ + if(!publicKeyRef){ + return nil; + } + if(![str dataUsingEncoding:NSUTF8StringEncoding]){ + return nil; + } + NSData *data = [self encryptData:[str dataUsingEncoding:NSUTF8StringEncoding] withKeyRef:publicKeyRef]; + NSString *ret = base64_encode_data(data); + return ret; +} + ++ (SecKeyRef)getPrivateKeyRefWithContentsOfFile:(NSString *)filePath password:(NSString*)password{ + NSData *p12Data = [NSData dataWithContentsOfFile:filePath]; + if (!p12Data) { + return NULL; + } + + SecKeyRef privateKeyRef = NULL; + CFArrayRef rawItems = NULL; + NSDictionary *options = @{(id)kSecImportExportPassphrase:password}; + + OSStatus securityError = SecPKCS12Import((__bridge CFDataRef)p12Data, (__bridge CFDictionaryRef)options, &rawItems); + if (securityError != errSecSuccess) { + if (rawItems) CFRelease(rawItems); + return NULL; + } + + NSArray *items = (NSArray*)CFBridgingRelease(rawItems); + if (items.count > 0) { + NSDictionary *firstItem = items[0]; + SecIdentityRef identity = (SecIdentityRef)CFBridgingRetain(firstItem[(id)kSecImportItemIdentity]); + securityError = SecIdentityCopyPrivateKey(identity, &privateKeyRef); + if (identity) CFRelease(identity); + if (securityError != errSecSuccess) privateKeyRef = NULL; + } + + return privateKeyRef; +} + ++ (NSString *)decryptString:(NSString *)str privateKeyRef:(SecKeyRef)privKeyRef{ + NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters]; + if (!privKeyRef) { + return nil; + } + data = [self decryptData:data withKeyRef:privKeyRef]; + NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + return ret; +} + ++ (NSData *)encryptData:(NSData *)data publicKey:(NSString *)pubKey{ + if(!data || !pubKey){ + return nil; + } + SecKeyRef keyRef = [self addPublicKey:pubKey]; + NSData *enData = [self encryptData:data withKeyRef:keyRef]; + if (keyRef) CFRelease(keyRef); + + return enData; +} + ++ (SecKeyRef)addPublicKey:(NSString *)key{ + NSRange spos = [key rangeOfString:@"-----BEGIN PUBLIC KEY-----"]; + NSRange epos = [key rangeOfString:@"-----END PUBLIC KEY-----"]; + if(spos.location != NSNotFound && epos.location != NSNotFound){ + NSUInteger s = spos.location + spos.length; + NSUInteger e = epos.location; + NSRange range = NSMakeRange(s, e-s); + key = [key substringWithRange:range]; + } + key = [key stringByReplacingOccurrencesOfString:@"\r" withString:@""]; + key = [key stringByReplacingOccurrencesOfString:@"\n" withString:@""]; + key = [key stringByReplacingOccurrencesOfString:@"\t" withString:@""]; + key = [key stringByReplacingOccurrencesOfString:@" " withString:@""]; + + // This will be base64 encoded, decode it. + NSData *data = base64_decode(key); + data = [self stripPublicKeyHeader:data]; + if(!data){ + return nil; + } + + //a tag to read/write keychain storage + NSString *tag = @"RSAUtil_PubKey"; + NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]]; + + // Delete any old lingering key with the same tag + NSMutableDictionary *publicKey = [[NSMutableDictionary alloc] init]; + [publicKey setObject:(__bridge id) kSecClassKey forKey:(__bridge id)kSecClass]; + [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; + [publicKey setObject:d_tag forKey:(__bridge id)kSecAttrApplicationTag]; + SecItemDelete((__bridge CFDictionaryRef)publicKey); + + // Add persistent version of the key to system keychain + [publicKey setObject:data forKey:(__bridge id)kSecValueData]; + [publicKey setObject:(__bridge id) kSecAttrKeyClassPublic forKey:(__bridge id) + kSecAttrKeyClass]; + [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id) + kSecReturnPersistentRef]; + + CFTypeRef persistKey = nil; + OSStatus status = SecItemAdd((__bridge CFDictionaryRef)publicKey, &persistKey); + if (persistKey != nil){ + CFRelease(persistKey); + } + if ((status != noErr) && (status != errSecDuplicateItem)) { + return nil; + } + + [publicKey removeObjectForKey:(__bridge id)kSecValueData]; + [publicKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef]; + [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef]; + [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; + + // Now fetch the SecKeyRef version of the key + SecKeyRef keyRef = nil; + status = SecItemCopyMatching((__bridge CFDictionaryRef)publicKey, (CFTypeRef *)&keyRef); + if(status != noErr){ + return nil; + } + return keyRef; +} + ++ (NSData *)stripPublicKeyHeader:(NSData *)d_key{ + // Skip ASN.1 public key header + if (d_key == nil) return(nil); + + unsigned long len = [d_key length]; + if (!len) return(nil); + + unsigned char *c_key = (unsigned char *)[d_key bytes]; + unsigned int idx = 0; + + if (c_key[idx++] != 0x30) return(nil); + + if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1; + else idx++; + + // PKCS #1 rsaEncryption szOID_RSA_RSA + static unsigned char seqiod[] = + { 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00 }; + if (memcmp(&c_key[idx], seqiod, 15)) return(nil); + + idx += 15; + + if (c_key[idx++] != 0x03) return(nil); + + if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1; + else idx++; + + if (c_key[idx++] != '\0') return(nil); + + return ([NSData dataWithBytes:&c_key[idx] length:len - idx]); +} + ++ (NSData *)encryptData:(NSData *)data withKeyRef:(SecKeyRef)keyRef{ + if(!keyRef){ + return nil; + } + const uint8_t *srcbuf = (const uint8_t *)[data bytes]; + size_t srclen = (size_t)data.length; + + size_t block_size = SecKeyGetBlockSize(keyRef) * sizeof(uint8_t); + void *outbuf = malloc(block_size); + size_t src_block_size = block_size - 11; + + NSMutableData *ret = [[NSMutableData alloc] init]; + for(int idx=0; idx src_block_size){ + data_len = src_block_size; + } + + size_t outlen = block_size; + OSStatus status = noErr; + status = SecKeyEncrypt(keyRef, + kSecPaddingPKCS1, + srcbuf + idx, + data_len, + outbuf, + &outlen + ); + if (status != 0) { + NSLog(@"SecKeyEncrypt fail. Error Code: %d", (int)status); + ret = nil; + break; + }else{ + [ret appendBytes:outbuf length:outlen]; + } + } + + free(outbuf); + return ret; +} + ++ (NSData *)decryptData:(NSData *)data privateKey:(NSString *)privKey{ + if(!data || !privKey){ + return nil; + } + SecKeyRef keyRef = [self addPrivateKey:privKey]; + NSData *deData = [self decryptData:data withKeyRef:keyRef]; + if (keyRef) CFRelease(keyRef); + + return deData; +} + ++ (SecKeyRef)addPrivateKey:(NSString *)key{ + NSRange spos = [key rangeOfString:@"-----BEGIN RSA PRIVATE KEY-----"]; + NSRange epos = [key rangeOfString:@"-----END RSA PRIVATE KEY-----"]; + if(spos.location != NSNotFound && epos.location != NSNotFound){ + NSUInteger s = spos.location + spos.length; + NSUInteger e = epos.location; + NSRange range = NSMakeRange(s, e-s); + key = [key substringWithRange:range]; + } + key = [key stringByReplacingOccurrencesOfString:@"\r" withString:@""]; + key = [key stringByReplacingOccurrencesOfString:@"\n" withString:@""]; + key = [key stringByReplacingOccurrencesOfString:@"\t" withString:@""]; + key = [key stringByReplacingOccurrencesOfString:@" " withString:@""]; + + // This will be base64 encoded, decode it. + NSData *data = base64_decode(key); + data = [self stripPrivateKeyHeader:data]; + if(!data){ + return NULL; + } + + //a tag to read/write keychain storage + NSString *tag = @"RSAUtil_PrivKey"; + NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]]; + + // Delete any old lingering key with the same tag + NSMutableDictionary *privateKey = [[NSMutableDictionary alloc] init]; + [privateKey setObject:(__bridge id) kSecClassKey forKey:(__bridge id)kSecClass]; + [privateKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; + [privateKey setObject:d_tag forKey:(__bridge id)kSecAttrApplicationTag]; + SecItemDelete((__bridge CFDictionaryRef)privateKey); + + // Add persistent version of the key to system keychain + [privateKey setObject:data forKey:(__bridge id)kSecValueData]; + [privateKey setObject:(__bridge id) kSecAttrKeyClassPrivate forKey:(__bridge id) + kSecAttrKeyClass]; + [privateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id) + kSecReturnPersistentRef]; + + CFTypeRef persistKey = NULL; + OSStatus status = SecItemAdd((__bridge CFDictionaryRef)privateKey, &persistKey); + if (persistKey) CFRelease(persistKey); + + if ((status != noErr) && (status != errSecDuplicateItem)) { + return NULL; + } + + [privateKey removeObjectForKey:(__bridge id)kSecValueData]; + [privateKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef]; + [privateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef]; + [privateKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; + + // Now fetch the SecKeyRef version of the key + SecKeyRef keyRef = nil; + status = SecItemCopyMatching((__bridge CFDictionaryRef)privateKey, (CFTypeRef *)&keyRef); + if(status != noErr){ + return NULL; + } + return keyRef; +} + ++ (NSData *)stripPrivateKeyHeader:(NSData *)d_key{ + // Skip ASN.1 private key header + if (d_key == nil) return(nil); + + unsigned long len = [d_key length]; + if (!len) return(nil); + + unsigned char *c_key = (unsigned char *)[d_key bytes]; + unsigned int idx = 22; //magic byte at offset 22 + + if (0x04 != c_key[idx++]) return nil; + + //calculate length of the key + unsigned int c_len = c_key[idx++]; + int det = c_len & 0x80; + if (!det) { + c_len = c_len & 0x7f; + } else { + int byteCount = c_len & 0x7f; + if (byteCount + idx > len) { + //rsa length field longer than buffer + return nil; + } + unsigned int accum = 0; + unsigned char *ptr = &c_key[idx]; + idx += byteCount; + while (byteCount) { + accum = (accum << 8) + *ptr; + ptr++; + byteCount--; + } + c_len = accum; + } + + return [d_key subdataWithRange:NSMakeRange(idx, c_len)]; +} + ++ (NSData *)decryptData:(NSData *)data withKeyRef:(SecKeyRef)keyRef{ + if(!keyRef){ + return nil; + } + const uint8_t *srcbuf = (const uint8_t *)[data bytes]; + size_t srclen = (size_t)data.length; + + size_t block_size = SecKeyGetBlockSize(keyRef) * sizeof(uint8_t); + UInt8 *outbuf = malloc(block_size); + size_t src_block_size = block_size; + + NSMutableData *ret = [[NSMutableData alloc] init]; + for(int idx=0; idx src_block_size){ + data_len = src_block_size; + } + + size_t outlen = block_size; + OSStatus status = noErr; + status = SecKeyDecrypt(keyRef, + kSecPaddingNone, + srcbuf + idx, + data_len, + outbuf, + &outlen + ); + if (status != 0) { + NSLog(@"SecKeyEncrypt fail. Error Code: %d", (int)status); + ret = nil; + break; + }else{ + //the actual decrypted data is in the middle, locate it! + int idxFirstZero = -1; + int idxNextZero = (int)outlen; + for ( int i = 0; i < outlen; i++ ) { + if ( outbuf[i] == 0 ) { + if ( idxFirstZero < 0 ) { + idxFirstZero = i; + } else { + idxNextZero = i; + break; + } + } + } + + [ret appendBytes:&outbuf[idxFirstZero+1] length:idxNextZero-idxFirstZero-1]; + } + } + + free(outbuf); + return ret; +} + +@end diff --git a/NYSKit/NYSTools.h b/NYSKit/NYSTools.h index 574ded2..9bc1d5e 100644 --- a/NYSKit/NYSTools.h +++ b/NYSKit/NYSTools.h @@ -119,7 +119,7 @@ typedef void (^NYSToolsDismissCompletion)(void); /// YES null NO !null /// @param string str -+ (BOOL)stringIsNull:(id)string; ++ (BOOL)isBlankString:(id)string; /// 拼音转换 /// @param str content @@ -158,9 +158,27 @@ typedef void (^NYSToolsDismissCompletion)(void); + (void)dismissWithDelay:(NSTimeInterval)delay completion:(NYSToolsDismissCompletion)completion; #pragma mark - 自动根据已安装的地图app跳转导航 +/* +LSApplicationQueriesSchemes + + iosamap + baidumap + +*/ + (void)navigateToAddress:(NSString *)address coordinate:(CLLocationCoordinate2D)coordinate viewController:(UIViewController *)viewController; ++ (void)openAppSetting; ++ (void)openURL:(NSString *)url; ++ (void)callPhoneWithNumber:(NSString *)number; ++ (void)sendEmailWithAddress:(NSString *)address; + #pragma mark - 其他 +/// 获取设备唯一标识(APP重装会改变) ++ (NSString *)getDeviceIdentifier; + +/// 获取IDFA ++ (NSString *)getIDFA; + /** 系统分享 @param items 需要分享的类目,可以包括文字,图片,网址 diff --git a/NYSKit/NYSTools.m b/NYSKit/NYSTools.m index 15a1d07..48488e9 100644 --- a/NYSKit/NYSTools.m +++ b/NYSKit/NYSTools.m @@ -8,6 +8,8 @@ #import "NYSTools.h" #import "NYSKitPublicHeader.h" #import +#import +#import #import @implementation NYSTools @@ -309,7 +311,7 @@ + (NSString *)nullToString:(id)string { /// YES null NO !null /// @param string str -+ (BOOL)stringIsNull:(id)string { ++ (BOOL)isBlankString:(id)string { if ([string isEqual:@"NULL"] || [string isKindOfClass:[NSNull class]] || [string isEqual:[NSNull null]] || [string isEqual:NULL] || [[string class] isSubclassOfClass:[NSNull class]] || string == nil || string == NULL || [string isKindOfClass:[NSNull class]] || [[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length]==0 || [string isEqualToString:@""] || [string isEqualToString:@"(null)"]) { return YES; } else { @@ -329,7 +331,7 @@ + (NSString *)transformToPinyin:(NSString *)str { /// 姓名加* /// @param string 姓名 + (NSString *)nameStringAsteriskHandle:(NSString *)string { - if ([self stringIsNull:string]) { + if ([self isBlankString:string]) { return @"*"; } @@ -351,24 +353,15 @@ + (NSString *)nameStringAsteriskHandle:(NSString *)string { /// 号码加* /// @param string 号码 + (NSString *)phoneStringAsteriskHandle:(NSString *)string { - if ([self stringIsNull:string]) { + if ([self isBlankString:string]) { return @"*"; - } - - if (string.length < 7) { - NSString *preStr = [string substringToIndex:4]; - return [preStr stringByAppendingString:@"***"]; - } - - if (6 < string.length && string.length <= 11) { - NSString *preStr = [string substringToIndex:3]; - NSString *sufStr = [string substringFromIndex:7]; - return [NSString stringWithFormat:@"%@****%@", preStr, sufStr]; - + } else if (string.length <= 6) { + return string; } else { -// NSString *mStr = [string substringWithRange:NSMakeRange(2, 4)]; - NSString *preStr = [string substringToIndex:4]; - return [preStr stringByAppendingString:@"****"]; + NSRange middleRange = NSMakeRange(3, string.length - 6); + NSString *middleString = [@"" stringByPaddingToLength:middleRange.length withString:@"*" startingAtIndex:0]; + NSString *result = [string stringByReplacingCharactersInRange:middleRange withString:middleString]; + return result; } } @@ -395,6 +388,7 @@ + (void)showToast:(NSString *)msg image:(UIImage *)image { + (void)showToast:(NSString *)msg image:(UIImage *)image offset:(UIOffset)offset { [SVProgressHUD setHapticsEnabled:YES]; + [SVProgressHUD setShouldTintImages:NO]; [SVProgressHUD setMinimumDismissTimeInterval:1.5]; [SVProgressHUD setFont:[UIFont systemFontOfSize:12]]; [SVProgressHUD setDefaultMaskType:SVProgressHUDMaskTypeNone]; @@ -410,6 +404,7 @@ + (void)showIconToast:(NSString *)msg isSuccess:(BOOL)isSuccess { + (void)showIconToast:(NSString *)msg isSuccess:(BOOL)isSuccess offset:(UIOffset)offset { [SVProgressHUD setHapticsEnabled:YES]; + [SVProgressHUD setShouldTintImages:YES]; [SVProgressHUD setMinimumDismissTimeInterval:1.5]; [SVProgressHUD setFont:[UIFont systemFontOfSize:12]]; [SVProgressHUD setDefaultMaskType:SVProgressHUDMaskTypeNone]; @@ -487,7 +482,49 @@ + (void)navigateToAddress:(NSString *)address coordinate:(CLLocationCoordinate2D [viewController.navigationController presentViewController:alert animated:YES completion:nil]; } ++ (void)openAppSettings { + NSURL *appSettingsURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; + if ([[UIApplication sharedApplication] canOpenURL:appSettingsURL]) { + [[UIApplication sharedApplication] openURL:appSettingsURL options:@{} completionHandler:nil]; + } +} + ++ (void)openURL:(NSString *)url { + NSURL *URL = [NSURL URLWithString:url]; + if ([[UIApplication sharedApplication] canOpenURL:URL]) { + [[UIApplication sharedApplication] openURL:URL options:@{} completionHandler:nil]; + } +} + ++ (void)callPhoneWithNumber:(NSString *)number { + NSString *phoneNumber = [@"tel:" stringByAppendingString:number]; + NSURL *phoneURL = [NSURL URLWithString:phoneNumber]; + if ([[UIApplication sharedApplication] canOpenURL:phoneURL]) { + [[UIApplication sharedApplication] openURL:phoneURL options:@{} completionHandler:nil]; + } +} + ++ (void)sendEmailWithAddress:(NSString *)address { + NSString *emailAddress = [@"mailto:" stringByAppendingString:address]; + NSURL *emailURL = [NSURL URLWithString:emailAddress]; + if ([[UIApplication sharedApplication] canOpenURL:emailURL]) { + [[UIApplication sharedApplication] openURL:emailURL options:@{} completionHandler:nil]; + } +} + #pragma mark - 其他 +/// 获取设备唯一标识(APP重装会改变) ++ (NSString *)getDeviceIdentifier { + UIDevice *device = [UIDevice currentDevice]; + return [device identifierForVendor].UUIDString; +} + +/// 获取IDFA ++ (NSString *)getIDFA { + NSString *idfaStr = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString]; + return idfaStr; +} + /** 系统分享 @param items 需要分享的类目,可以包括文字,图片,网址 diff --git a/NYSUIKit.podspec b/NYSUIKit.podspec index fb4c1b6..dddfe6f 100644 --- a/NYSUIKit.podspec +++ b/NYSUIKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'NYSUIKit' - s.version = '0.0.6' + s.version = '0.0.7' s.platform = :ios, '13.0' s.summary = 'iOS scaffold UI framework.' s.homepage = 'https://github.com/niyongsheng/NYSKit' @@ -14,7 +14,7 @@ Pod::Spec.new do |s| 'NYSUIKit/Resources/load_error.html', 'NYSUIKit/Resources/douyuFont.otf' ] - s.dependency 'NYSKit', '~> 0.0.1' + s.dependency 'NYSKit', '~> 0.0.7' s.dependency 'MJRefresh', '~> 3.7.6' s.requires_arc = true end diff --git a/NYSUIKit/BaseClass/NYSBaseObject.h b/NYSUIKit/BaseClass/NYSBaseObject.h index 59407f4..5aaa3e5 100644 --- a/NYSUIKit/BaseClass/NYSBaseObject.h +++ b/NYSUIKit/BaseClass/NYSBaseObject.h @@ -12,6 +12,9 @@ NS_ASSUME_NONNULL_BEGIN @interface NYSBaseObject : NSObject ++ (NSDictionary *)modelCustomPropertyMapper; + ++ (NSDictionary *)modelContainerPropertyGenericClass; @end diff --git a/NYSUIKit/BaseClass/NYSBaseObject.m b/NYSUIKit/BaseClass/NYSBaseObject.m index 7318b08..4fd4f47 100644 --- a/NYSUIKit/BaseClass/NYSBaseObject.m +++ b/NYSUIKit/BaseClass/NYSBaseObject.m @@ -28,7 +28,7 @@ + (NSDictionary *)modelContainerPropertyGenericClass { - (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic { // 处理字符串为null 改为@"" for (NSString * key in [self bk_properties_string]) { - if ([NYSTools stringIsNull:[self valueForKey:key]]) { + if ([NYSTools isBlankString:[self valueForKey:key]]) { [self setValue:@"" forKey:key]; } } diff --git a/NYSUIKit/BaseClass/NYSBaseTabBarController.h b/NYSUIKit/BaseClass/NYSBaseTabBarController.h index 86cce97..afabe2a 100644 --- a/NYSUIKit/BaseClass/NYSBaseTabBarController.h +++ b/NYSUIKit/BaseClass/NYSBaseTabBarController.h @@ -24,6 +24,8 @@ typedef NS_ENUM(NSInteger, NYSBaseTabBarInteractionEffectStyle) { /// 是否重置tabBarItem样式 @property (nonatomic, assign) BOOL isResetTabBarItemStyle; +- (void)setRoundedCornerWithCorners:(UIRectCorner)corners cornerRadius:(CGFloat)cornerRadius; + @end NS_ASSUME_NONNULL_END diff --git a/NYSUIKit/BaseClass/NYSBaseTabBarController.m b/NYSUIKit/BaseClass/NYSBaseTabBarController.m index d5f841d..64a4800 100644 --- a/NYSUIKit/BaseClass/NYSBaseTabBarController.m +++ b/NYSUIKit/BaseClass/NYSBaseTabBarController.m @@ -64,6 +64,17 @@ - (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size { return image; } +- (void)setRoundedCornerWithCorners:(UIRectCorner)corners cornerRadius:(CGFloat)cornerRadius { + if (!self.tabBar) { + return; + } + + CAShapeLayer *maskLayer = [CAShapeLayer layer]; + maskLayer.path = [UIBezierPath bezierPathWithRoundedRect:self.tabBar.bounds byRoundingCorners:cornerRadius cornerRadii:CGSizeMake(cornerRadius, cornerRadius)].CGPath; + self.tabBar.layer.mask = maskLayer; +} + + #pragma mark - UITabBarControllerDelegate - (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController { diff --git a/NYSUIKit/BaseClass/NYSBaseViewController.h b/NYSUIKit/BaseClass/NYSBaseViewController.h index a76aea0..f3a76c2 100644 --- a/NYSUIKit/BaseClass/NYSBaseViewController.h +++ b/NYSUIKit/BaseClass/NYSBaseViewController.h @@ -9,6 +9,7 @@ #import "NSError+NYS.h" NS_ASSUME_NONNULL_BEGIN + /// 导航栏按钮回调 typedef void(^NYSNavItemCompletion)(UIButton *sender, NSInteger index); typedef NS_ENUM(NSInteger, NYSNavItemAlignment) { @@ -17,12 +18,11 @@ typedef NS_ENUM(NSInteger, NYSNavItemAlignment) { }; @interface NYSBaseViewController : UIViewController -{ - /// tabview style. default:UITableViewStylePlain - UITableViewStyle _tableviewStyle; -} + /// 主数据源 @property (nonatomic, strong) NSMutableArray *dataSourceArr; +@property (nonatomic, assign) NSInteger pageNum; +@property (nonatomic, assign) UITableViewStyle tableviewStyle; @property (nonatomic, strong) UITableView *tableView; @property (nonatomic, strong) UICollectionView *collectionView; @@ -37,6 +37,7 @@ typedef NS_ENUM(NSInteger, NYSNavItemAlignment) { @property (nonatomic, assign) BOOL isUseUIRefreshControl; /// Empty \ Error info @property (nonatomic, strong) NSError *emptyError; +@property (nonatomic, strong) UIImageView *backgroundImageView; /** Theme UI VM, allow overridden */ - (void)configTheme; @@ -59,6 +60,10 @@ typedef NS_ENUM(NSInteger, NYSNavItemAlignment) { - (void)addNavigationItems:(NSArray *)buttonArray alignment:(NYSNavItemAlignment)alignment completion:(NYSNavItemCompletion)completion; #pragma mark - tableview delegate / dataSource +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; +- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section; +- (nullable NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView; +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath; - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath; diff --git a/NYSUIKit/BaseClass/NYSBaseViewController.m b/NYSUIKit/BaseClass/NYSBaseViewController.m index 7cbfc5e..50ae1c0 100644 --- a/NYSUIKit/BaseClass/NYSBaseViewController.m +++ b/NYSUIKit/BaseClass/NYSBaseViewController.m @@ -12,12 +12,10 @@ #import "NYSUIKitPublicHeader.h" #import "UIImage+NYS.h" -#import "UIButton+NYS.h" +#import "UIControl+NYS.h" #import "NSBundle+NYSFramework.h" #import "UIScrollView+EmptyDataSet.h" -#import - #define NYSTopHeight [UIApplication sharedApplication].windows.firstObject.windowScene.statusBarManager.statusBarFrame.size.height + self.navigationController.navigationBar.frame.size.height @interface NYSBaseViewController () @@ -33,6 +31,7 @@ @interface NYSBaseViewController () @end + @implementation NYSBaseViewController #pragma mark - Life cycle @@ -45,20 +44,19 @@ - (void)viewDidLoad { // 默认使用系统刷新样式 [self setIsUseUIRefreshControl:YES]; - // 默认tableview样式 - _tableviewStyle = UITableViewStylePlain; - // 默认占位信息 [self addObserver:self forKeyPath:@"dataSource" options:NSKeyValueObservingOptionNew context:nil]; // KVO self.emptyError = [NSError errorCode:NSNYSErrorCodeUnKnow description:[NSBundle nys_localizedStringForKey:@"NoData"] reason:@"" suggestion:[NSBundle nys_localizedStringForKey:@"Retry"] - placeholderImg:@"error"]; - // VM - [self bindViewModel]; + placeholderImg:@"icon_error_nys"]; + self.pageNum = 1; + // UI [self setupUI]; + // VM + [self bindViewModel]; } - (void)viewWillAppear:(BOOL)animated { @@ -92,7 +90,7 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N description:[NSBundle nys_localizedStringForKey:@"NoData"] reason:@"" suggestion:[NSBundle nys_localizedStringForKey:@"Retry"] - placeholderImg:@"error"]; + placeholderImg:@"icon_error_nys"]; } #pragma mark - UI @@ -101,13 +99,13 @@ - (void)setupUI { self.isShowLiftBack = YES; /** - // 关闭拓展全屏布局,等效于automaticallyAdjustsScrollViewInsets = NO; - self.edgesForExtendedLayout = UIRectEdgeNone; - if ([self respondsToSelector:@selector(edgesForExtendedLayout)]) { - self.navigationController.navigationBar.translucent = YES; - self.automaticallyAdjustsScrollViewInsets = YES; - } - */ + // 关闭拓展全屏布局,等效于automaticallyAdjustsScrollViewInsets = NO; + self.edgesForExtendedLayout = UIRectEdgeNone; + if ([self respondsToSelector:@selector(edgesForExtendedLayout)]) { + self.navigationController.navigationBar.translucent = YES; + self.automaticallyAdjustsScrollViewInsets = YES; + } + */ } - (void)bindViewModel {} - (void)setCustomStatusBarStyle:(UIStatusBarStyle)StatusBarStyle { @@ -173,8 +171,9 @@ - (UITableView *)tableView { if (@available(iOS 15.0, *)) { _tableView.sectionHeaderTopPadding = 0; } + if (_backgroundImageView) _tableView.backgroundColor = [UIColor clearColor]; - _tableView.estimatedRowHeight = 0; + _tableView.estimatedRowHeight = 1; _tableView.estimatedSectionHeaderHeight = 0; _tableView.estimatedSectionFooterHeight = 0; _tableView.rowHeight = UITableViewAutomaticDimension; @@ -259,6 +258,10 @@ - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } +- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { + return nil; +} + - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.dataSourceArr.count; } @@ -292,6 +295,7 @@ - (UICollectionView *)collectionView { _collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; _collectionView.contentInset = UIEdgeInsetsMake(NYSTopHeight, 0, 0, 0); } + if (_backgroundImageView) _collectionView.backgroundColor = [UIColor clearColor]; _collectionView.delegate = self; _collectionView.dataSource = self; @@ -378,6 +382,10 @@ - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collection return nil; } +- (nullable NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView { + return nil; +} + - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { [collectionView deselectItemAtIndexPath:indexPath animated:true]; } @@ -388,7 +396,7 @@ - (void)headerRereshing { description:[NSBundle nys_localizedStringForKey:@"Loading"] reason:@"" suggestion:@"" - placeholderImg:@"linkedin_binding_magnifier"]; + placeholderImg:@"icon_loading_nys"]; __weak __typeof(self)weakSelf = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ @@ -406,7 +414,7 @@ - (void)headerRereshing { description:[NSBundle nys_localizedStringForKey:@"NoData"] reason:@"" suggestion:[NSBundle nys_localizedStringForKey:@"Retry"] - placeholderImg:@"error"]; + placeholderImg:@"icon_error_nys"]; }); } @@ -415,7 +423,7 @@ - (void)footerRereshing { description:[NSBundle nys_localizedStringForKey:@"Loading"] reason:@"" suggestion:@"" - placeholderImg:@"linkedin_binding_magnifier"]; + placeholderImg:@"icon_loading_nys"]; __weak __typeof(self)weakSelf = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ @@ -429,17 +437,19 @@ - (void)footerRereshing { description:[NSBundle nys_localizedStringForKey:@"NoData"] reason:@"" suggestion:[NSBundle nys_localizedStringForKey:@"Retry"] - placeholderImg:@"error"]; + placeholderImg:@"icon_error_nys"]; }); } #pragma mark - DZNEmptyDataSetSource - (UIImage *)imageForEmptyDataSet:(UIScrollView *)scrollView { - NSString *placeholderStr = self.emptyError.userInfo[@"NSLocalizedPlaceholderImageName"]; - if ([NYSTools stringIsNull:placeholderStr]) { - return [NYSUIKitUtilities imageNamed:@"error"]; + id image = self.emptyError.userInfo[@"NSLocalizedPlaceholderImage"]; + if (image && [image isKindOfClass:UIImage.class]) { + return image; + } else if (image && [image isKindOfClass:NSString.class]) { + return [NYSUIKitUtilities imageNamed:image]; } else { - return [NYSUIKitUtilities imageNamed:placeholderStr]; + return [NYSUIKitUtilities imageNamed:@"error"]; } } @@ -463,7 +473,7 @@ - (NSAttributedString *)descriptionForEmptyDataSet:(UIScrollView *)scrollView { } - (NSAttributedString *)buttonTitleForEmptyDataSet:(UIScrollView *)scrollView forState:(UIControlState)state { - NSString *str = self.emptyError.localizedRecoverySuggestion; + NSString *str = self.emptyError.localizedRecoverySuggestion; NSMutableAttributedString *buttonAttStr = [[NSMutableAttributedString alloc] initWithString:str]; [buttonAttStr addAttribute:NSForegroundColorAttributeName value:NAppThemeColor range:NSMakeRange(0, str.length)]; [buttonAttStr addAttribute:NSFontAttributeName value:[UIFont boldSystemFontOfSize:17] range:NSMakeRange(0, str.length)]; @@ -494,7 +504,7 @@ - (void)emptyDataSet:(UIScrollView *)scrollView didTapButton:(UIButton *)button } else if (scrollView.mj_footer) { [self footerRereshing]; } else { - [NYSTools showBottomToast:@"没有实现刷新方法"]; + [NYSTools log:@"没有实现刷新方法"]; } } @@ -509,6 +519,16 @@ - (void)setEmptyError:(NSError *)emptyError { } } +- (void)setBackgroundImageView:(UIImageView *)backgroundImageView { + _backgroundImageView = backgroundImageView; + + if (_backgroundImageView) { + [self.view insertSubview:_backgroundImageView atIndex:0]; + if (_tableView) _tableView.backgroundColor = [UIColor clearColor]; + if (_collectionView) _collectionView.backgroundColor = [UIColor clearColor]; + } +} + #pragma mark - 是否显示返回按钮 - (void)setIsShowLiftBack:(BOOL)isShowLiftBack { _isShowLiftBack = isShowLiftBack; @@ -538,10 +558,10 @@ - (void)setIsShowLiftBack:(BOOL)isShowLiftBack { } - (void)backBtnOnclicked:(UIButton *)sender { - if (self.presentingViewController) { - [self dismissViewControllerAnimated:YES completion:nil]; - } else { + if (self.navigationController.childViewControllers.count > 1) { [self.navigationController popViewControllerAnimated:YES]; + } else { + [self dismissViewControllerAnimated:YES completion:nil]; } } @@ -595,7 +615,7 @@ - (void)addNavigationItems:(NSArray *)buttonArray alignment:(NYSNavI NSMutableArray *items = [[NSMutableArray alloc] init]; for (int i = 0; i < buttonArray.count; i ++) { UIButton *button = buttonArray[i]; - [button handleControlEvent:UIControlEventTouchUpInside withBlock:^(UIButton *button) { + [button addBlockForControlEvents:UIControlEventTouchUpInside block:^(id sender) { if (completion) completion(button, button.tag); }]; diff --git a/NYSUIKit/Category/NSError+NYS.h b/NYSUIKit/Category/NSError+NYS.h index 0f3dfa6..cb39836 100644 --- a/NYSUIKit/Category/NSError+NYS.h +++ b/NYSUIKit/Category/NSError+NYS.h @@ -31,8 +31,8 @@ typedef NS_ENUM(NSInteger, NSNYSErrorCode){ /// @param description 描述 /// @param reason 原因 /// @param suggestion 建议 -/// @param imageName 图片名key:@"NSLocalizedPlaceholderImageName" (Framework中的图片资源) -+ (NSError*)errorCode:(NSNYSErrorCode)code description:(NSString *)description reason:(NSString *)reason suggestion:(NSString *)suggestion placeholderImg:(NSString *)imageName; +/// @param image (Framework中的图片名\UIImage对象) ++ (NSError*)errorCode:(NSNYSErrorCode)code description:(NSString *)description reason:(NSString *)reason suggestion:(NSString *)suggestion placeholderImg:(id)image; @end diff --git a/NYSUIKit/Category/NSError+NYS.m b/NYSUIKit/Category/NSError+NYS.m index 2df8b1a..de36a28 100644 --- a/NYSUIKit/Category/NSError+NYS.m +++ b/NYSUIKit/Category/NSError+NYS.m @@ -23,8 +23,8 @@ + (NSError*)errorCode:(NSNYSErrorCode)code userInfo:(nullable NSDictionary*)user @{ NSLocalizedDescriptionKey:@"Unknow Error", NSLocalizedFailureReasonErrorKey:@"no reason", - NSLocalizedRecoverySuggestionErrorKey:@"重试", - @"NSCustomInfoKey": @"Easy case.", + NSLocalizedRecoverySuggestionErrorKey:@"Retry", + @"NSCustomInfoKey": @"", }]; } } @@ -38,13 +38,13 @@ + (NSError*)errorCode:(NSNYSErrorCode)code description:(NSString *)description r }]; } -+ (NSError*)errorCode:(NSNYSErrorCode)code description:(NSString *)description reason:(NSString *)reason suggestion:(NSString *)suggestion placeholderImg:(NSString *)imageName { ++ (NSError*)errorCode:(NSNYSErrorCode)code description:(NSString *)description reason:(NSString *)reason suggestion:(NSString *)suggestion placeholderImg:(id)image { return [NSError errorWithDomain:NSNYSErrorDomain code:code userInfo: @{ NSLocalizedDescriptionKey:description, NSLocalizedFailureReasonErrorKey:reason, NSLocalizedRecoverySuggestionErrorKey:suggestion, - @"NSLocalizedPlaceholderImageName": imageName + @"NSLocalizedPlaceholderImage": image }]; } diff --git a/NYSUIKit/Category/UIButton+NYS.h b/NYSUIKit/Category/UIButton+NYS.h index 384a001..a0fc946 100644 --- a/NYSUIKit/Category/UIButton+NYS.h +++ b/NYSUIKit/Category/UIButton+NYS.h @@ -18,20 +18,15 @@ typedef void (^ButtonBlock)(UIButton *button); /// @param edge 范围 - (void)enlargeTouchEdge:(UIEdgeInsets)edge; -/// 设置点击时间间隔 +/// 按钮点击时间间隔 @property (nonatomic, assign) NSTimeInterval timeInterval; -/// 用于设置单个按钮不需要被hook +/// 按钮不需要被hook时传YES @property (nonatomic, assign) BOOL isIgnore; -@property (nonatomic, copy) ButtonBlock tapBlock; -/// 按钮block回调 -/// - Parameters: -/// - event: 事件 -/// - block: 回调 -- (void)handleControlEvent:(UIControlEvents)event withBlock:(ButtonBlock)block; - -/// 设置是否执行点UI方法 YES 不允许点击 NO 允许点击 -@property (nonatomic, assign) BOOL isIgnoreEvent; +/// 开始加载动画 +- (void)startLoading; +/// 停止加载动画 +- (void)stopLoading; @end diff --git a/NYSUIKit/Category/UIButton+NYS.m b/NYSUIKit/Category/UIButton+NYS.m index 0f04025..7f2596f 100644 --- a/NYSUIKit/Category/UIButton+NYS.m +++ b/NYSUIKit/Category/UIButton+NYS.m @@ -8,7 +8,7 @@ #import "UIButton+NYS.h" #import -static const void *kButtonTapBlockKey = &kButtonTapBlockKey; +static char const * const activityIndicatorKey = "activityIndicator"; @implementation UIButton (NYS) @@ -37,91 +37,114 @@ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { return CGRectContainsPoint(rect, point) ? self : nil; } +- (NSTimeInterval)timeInterval { + return [objc_getAssociatedObject(self, _cmd) doubleValue]; +} +- (void)setTimeInterval:(NSTimeInterval)timeInterval{ + objc_setAssociatedObject(self, @selector(timeInterval), @(timeInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ SEL selA = @selector(sendAction:to:forEvent:); SEL selB = @selector(mySendAction:to:forEvent:); - Method methodA = class_getInstanceMethod(self,selA); + Method methodA = class_getInstanceMethod(self, selA); Method methodB = class_getInstanceMethod(self, selB); - //将 methodB的实现 添加到系统方法中 也就是说 将 methodA方法指针添加成 方法methodB的 返回值表示是否添加成功 + BOOL isAdd = class_addMethod(self, selA, method_getImplementation(methodB), method_getTypeEncoding(methodB)); - //添加成功了 说明 本类中不存在methodB 所以此时必须将方法b的实现指针换成方法A的,否则 b方法将没有实现。 + if (isAdd) { class_replaceMethod(self, selB, method_getImplementation(methodA), method_getTypeEncoding(methodA)); - }else{ - //添加失败了 说明本类中 有methodB的实现,此时只需要将 methodA和methodB的IMP互换一下即可。 + } else { method_exchangeImplementations(methodA, methodB); } }); } -- (NSTimeInterval)timeInterval { - return [objc_getAssociatedObject(self, _cmd) doubleValue]; -} -- (void)setTimeInterval:(NSTimeInterval)timeInterval{ - objc_setAssociatedObject(self, @selector(timeInterval), @(timeInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC); - -} -// 当我们按钮点击事件 sendAction 时 将会执行 mySendAction + - (void)mySendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event { if (self.isIgnore) { - //不需要被hook [self mySendAction:action to:target forEvent:event]; return; } + if ([NSStringFromClass(self.class) isEqualToString:@"UIButton"]) { - self.timeInterval =self.timeInterval == 0 ?defaultInterval:self.timeInterval; - if (self.isIgnoreEvent){ + self.timeInterval = self.timeInterval == 0 ? defaultInterval : self.timeInterval; + + if (self.isIgnoreEvent) { return; - }else if (self.timeInterval > 0){ + } else if (self.timeInterval > 0) { [self performSelector:@selector(resetState) withObject:nil afterDelay:self.timeInterval]; } } - // 此处 methodA和methodB方法IMP互换了,实际上执行 sendAction;所以不会死循环 + self.isIgnoreEvent = YES; [self mySendAction:action to:target forEvent:event]; } -// runtime 动态绑定 属性 -- (void)setIsIgnoreEvent:(BOOL)isIgnoreEvent{ - // 注意BOOL类型 需要用OBJC_ASSOCIATION_RETAIN_NONATOMIC 不要用错,否则set方法会赋值出错 + +- (void)setIsIgnoreEvent:(BOOL)isIgnoreEvent { objc_setAssociatedObject(self, @selector(isIgnoreEvent), @(isIgnoreEvent), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } -- (BOOL)isIgnoreEvent{ - // _cmd == @select(isIgnore); 和set方法里一致 + +- (BOOL)isIgnoreEvent { return [objc_getAssociatedObject(self, _cmd) boolValue]; } -- (void)setIsIgnore:(BOOL)isIgnore{ - // 注意BOOL类型 需要用OBJC_ASSOCIATION_RETAIN_NONATOMIC 不要用错,否则set方法会赋值出错 + +- (void)setIsIgnore:(BOOL)isIgnore { objc_setAssociatedObject(self, @selector(isIgnore), @(isIgnore), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } -- (BOOL)isIgnore{ - // _cmd == @select(isIgnore); 和set方法里一致 + +- (BOOL)isIgnore { return [objc_getAssociatedObject(self, _cmd) boolValue]; } -- (void)resetState{ + +- (void)resetState { [self setIsIgnoreEvent:NO]; } - -- (ButtonBlock)tapBlock { - return objc_getAssociatedObject(self, kButtonTapBlockKey); +#pragma mark - ActivityIndicator functions +- (void)startLoading { + UIActivityIndicatorView *activityIndicator = [self activityIndicator]; + + if (!activityIndicator) { + activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; + + // 指示器与按钮title之间的间距 + CGFloat indicatorMargin = 5.0; + CGFloat indicatorX = CGRectGetMaxX(self.titleLabel.frame) + indicatorMargin; + CGFloat indicatorY = CGRectGetMidY(self.titleLabel.frame) - activityIndicator.frame.size.height / 2; + CGRect indicatorFrame = CGRectMake(indicatorX, indicatorY, activityIndicator.frame.size.width, activityIndicator.frame.size.height); + activityIndicator.frame = indicatorFrame; + + activityIndicator.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin; + + [self addSubview:activityIndicator]; + [self setActivityIndicator:activityIndicator]; + } + + [activityIndicator startAnimating]; + self.enabled = NO; } -- (void)setTapBlock:(ButtonBlock)tapBlock { - objc_setAssociatedObject(self, kButtonTapBlockKey, tapBlock, OBJC_ASSOCIATION_COPY_NONATOMIC); +- (void)stopLoading { + UIActivityIndicatorView *activityIndicator = [self activityIndicator]; + + if (activityIndicator) { + [activityIndicator stopAnimating]; + [activityIndicator removeFromSuperview]; + [self setActivityIndicator:nil]; + } + + self.enabled = YES; } -- (void)handleControlEvent:(UIControlEvents)event withBlock:(ButtonBlock)block { - self.tapBlock = block; - [self addTarget:self action:@selector(buttonTapped) forControlEvents:event]; +- (UIActivityIndicatorView *)activityIndicator { + return objc_getAssociatedObject(self, activityIndicatorKey); } -- (void)buttonTapped { - if (self.tapBlock) { - self.tapBlock(self); - } +- (void)setActivityIndicator:(UIActivityIndicatorView *)activityIndicator { + objc_setAssociatedObject(self, activityIndicatorKey, activityIndicator, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } @end diff --git a/NYSUIKit/Category/UIControl+NYS.h b/NYSUIKit/Category/UIControl+NYS.h new file mode 100644 index 0000000..faf4c9f --- /dev/null +++ b/NYSUIKit/Category/UIControl+NYS.h @@ -0,0 +1,15 @@ +// +// UIControl+NYS.h +// +// NYSUIKit http://github.com/niyongsheng +// Copyright © 2020 NYS. ALL rights reserved. +// + +#import + +@interface UIControl (NYS) + +- (void)addBlockForControlEvents:(UIControlEvents)controlEvents block:(void (^)(id sender))block; +- (void)removeAllBlocksForControlEvents:(UIControlEvents)controlEvents; + +@end diff --git a/NYSUIKit/Category/UIControl+NYS.m b/NYSUIKit/Category/UIControl+NYS.m new file mode 100644 index 0000000..c6efc43 --- /dev/null +++ b/NYSUIKit/Category/UIControl+NYS.m @@ -0,0 +1,49 @@ +// +// UIControl+NYS.m +// +// NYSUIKit http://github.com/niyongsheng +// Copyright © 2020 NYS. ALL rights reserved. +// + +#import "UIControl+NYS.h" +#import + +@implementation UIControl (NYS) + +static const char *UIControlBlocksKey = "UIControlBlocksKey"; + +- (void)addBlockForControlEvents:(UIControlEvents)controlEvents block:(void (^)(id sender))block { + NSMutableDictionary *blocks = objc_getAssociatedObject(self, UIControlBlocksKey); + if (!blocks) { + blocks = [NSMutableDictionary dictionary]; + objc_setAssociatedObject(self, UIControlBlocksKey, blocks, OBJC_ASSOCIATION_RETAIN); + } + + NSMutableArray *eventBlocks = blocks[@(controlEvents)]; + if (!eventBlocks) { + eventBlocks = [NSMutableArray array]; + blocks[@(controlEvents)] = eventBlocks; + } + + [eventBlocks addObject:block]; + [self addTarget:self action:@selector(handleControlEvent:) forControlEvents:controlEvents]; +} + +- (void)removeAllBlocksForControlEvents:(UIControlEvents)controlEvents { + NSMutableDictionary *blocks = objc_getAssociatedObject(self, UIControlBlocksKey); + if (blocks) { + [blocks removeObjectForKey:@(controlEvents)]; + } +} + +- (void)handleControlEvent:(UIControl *)control { + UIControlEvents controlEvents = control.allControlEvents; + NSMutableDictionary *blocks = objc_getAssociatedObject(control, UIControlBlocksKey); + NSMutableArray *eventBlocks = blocks[@(controlEvents)]; + + for (void (^block)(id sender) in eventBlocks) { + block(control); + } +} + +@end diff --git a/NYSUIKit/Category/UITextField+NYS.m b/NYSUIKit/Category/UITextField+NYS.m index fe0af6e..6f768dd 100644 --- a/NYSUIKit/Category/UITextField+NYS.m +++ b/NYSUIKit/Category/UITextField+NYS.m @@ -18,13 +18,12 @@ - (void)setMaxLength:(NSInteger)maxLength { [self addTarget:self action:@selector(NYSTextFieldTextChanged:) forControlEvents:UIControlEventEditingChanged]; } + - (NSInteger)maxLength { return [objc_getAssociatedObject(self, &NYSMaxLengthKey) integerValue]; } - - (void)NYSTextFieldTextChanged:(UITextField *)textField { - self.clearButtonMode = UITextFieldViewModeWhileEditing; if (textField.text.length > self.maxLength) { textField.text = [textField.text substringToIndex:textField.text.length -1]; } diff --git a/NYSUIKit/Category/UIView+NYS.m b/NYSUIKit/Category/UIView+NYS.m index 041096b..3ff9779 100644 --- a/NYSUIKit/Category/UIView+NYS.m +++ b/NYSUIKit/Category/UIView+NYS.m @@ -35,6 +35,7 @@ - (CGFloat)borderWidth { - (void)setCornerRadius:(CGFloat)cornerRadius { self.layer.cornerRadius = cornerRadius; + self.layer.masksToBounds = YES; } - (CGFloat)cornerRadius { diff --git a/NYSUIKit/NYSUIKit.h b/NYSUIKit/NYSUIKit.h index 00eef74..0b4f8ac 100644 --- a/NYSUIKit/NYSUIKit.h +++ b/NYSUIKit/NYSUIKit.h @@ -42,6 +42,7 @@ FOUNDATION_EXPORT const unsigned char NYSUIKitVersionString[]; #import #import #import +#import #import #import #import diff --git a/NYSUIKit/NYSUIKitPublicHeader.h b/NYSUIKit/NYSUIKitPublicHeader.h index d9f2611..faef3ea 100644 --- a/NYSUIKit/NYSUIKitPublicHeader.h +++ b/NYSUIKit/NYSUIKitPublicHeader.h @@ -14,6 +14,7 @@ #define NAppThemeColor [LEETheme getValueWithTag:[LEETheme currentThemeTag] Identifier:@"app_theme_color"] #import +#import #import "NYSUIKitUtilities.h" #endif /* PublicHeader_h */ diff --git a/NYSUIKit/Resources/NYSUIKit.bundle/Info.plist b/NYSUIKit/Resources/NYSUIKit.bundle/Info.plist index e43bcfa..4a891c6 100644 Binary files a/NYSUIKit/Resources/NYSUIKit.bundle/Info.plist and b/NYSUIKit/Resources/NYSUIKit.bundle/Info.plist differ diff --git a/NYSUIKit/Resources/NYSUIKit.bundle/en.lproj/Localizable.strings b/NYSUIKit/Resources/NYSUIKit.bundle/en.lproj/Localizable.strings index b72ffa8..6771530 100644 --- a/NYSUIKit/Resources/NYSUIKit.bundle/en.lproj/Localizable.strings +++ b/NYSUIKit/Resources/NYSUIKit.bundle/en.lproj/Localizable.strings @@ -4,5 +4,6 @@ NetErr="Network Error"; Retry="Retry"; Loading="Loading..."; -TipsAppUpdate="New test version"; +TipsAppUpdate="New Test Version"; AppUpdate="Update"; +Cancel="Cancel"; diff --git a/NYSUIKit/Resources/NYSUIKit.bundle/es.lproj/Localizable.strings b/NYSUIKit/Resources/NYSUIKit.bundle/es.lproj/Localizable.strings index d1b55f7..8f63788 100644 --- a/NYSUIKit/Resources/NYSUIKit.bundle/es.lproj/Localizable.strings +++ b/NYSUIKit/Resources/NYSUIKit.bundle/es.lproj/Localizable.strings @@ -5,4 +5,5 @@ Retry="reintentar"; Loading="Carga..."; TipsAppUpdate="Nueva versión de prueba"; -AppUpdate="actualización"; \ No newline at end of file +AppUpdate="actualización"; +Cancel="cancelar"; diff --git a/NYSUIKit/Resources/NYSUIKit.bundle/ja.lproj/Localizable.strings b/NYSUIKit/Resources/NYSUIKit.bundle/ja.lproj/Localizable.strings index f6b86af..3d36351 100644 --- a/NYSUIKit/Resources/NYSUIKit.bundle/ja.lproj/Localizable.strings +++ b/NYSUIKit/Resources/NYSUIKit.bundle/ja.lproj/Localizable.strings @@ -6,3 +6,4 @@ Loading="装着…"; TipsAppUpdate="新テスト版"; AppUpdate="更新"; +Cancel="キャンセル"; diff --git a/NYSUIKit/Resources/NYSUIKit.bundle/ko.lproj/Localizable.strings b/NYSUIKit/Resources/NYSUIKit.bundle/ko.lproj/Localizable.strings index b06b86a..26c6755 100644 --- a/NYSUIKit/Resources/NYSUIKit.bundle/ko.lproj/Localizable.strings +++ b/NYSUIKit/Resources/NYSUIKit.bundle/ko.lproj/Localizable.strings @@ -6,3 +6,4 @@ Loading="로드 …"; TipsAppUpdate="New 테스트 버전"; AppUpdate="업 데이트"; +Cancel="취소"; diff --git a/NYSUIKit/Resources/NYSUIKit.bundle/lao.lproj/Localizable.strings b/NYSUIKit/Resources/NYSUIKit.bundle/lao.lproj/Localizable.strings index 98883a3..356d157 100644 --- a/NYSUIKit/Resources/NYSUIKit.bundle/lao.lproj/Localizable.strings +++ b/NYSUIKit/Resources/NYSUIKit.bundle/lao.lproj/Localizable.strings @@ -6,3 +6,4 @@ Loading="ກຳລັງອອກ..."; TipsAppUpdate="ລຸ້ນໃຫມ່ບັນຫາ"; AppUpdate="ປັບປຸງຂໍ້ມູນ"; +Cancel="ຍົກເລີກ"; diff --git a/NYSUIKit/Resources/NYSUIKit.bundle/zh-Hans.lproj/Localizable.strings b/NYSUIKit/Resources/NYSUIKit.bundle/zh-Hans.lproj/Localizable.strings index 2203831..dc9f4ad 100644 --- a/NYSUIKit/Resources/NYSUIKit.bundle/zh-Hans.lproj/Localizable.strings +++ b/NYSUIKit/Resources/NYSUIKit.bundle/zh-Hans.lproj/Localizable.strings @@ -6,3 +6,4 @@ Loading="加载中..."; TipsAppUpdate="新测试版本"; AppUpdate="立即更新"; +Cancel="取消"; diff --git a/NYSUIKit/Resources/NYSUIKit.bundle/zh-Hant.lproj/Localizable.strings b/NYSUIKit/Resources/NYSUIKit.bundle/zh-Hant.lproj/Localizable.strings index 2fb1425..ab2d19b 100644 --- a/NYSUIKit/Resources/NYSUIKit.bundle/zh-Hant.lproj/Localizable.strings +++ b/NYSUIKit/Resources/NYSUIKit.bundle/zh-Hant.lproj/Localizable.strings @@ -6,3 +6,4 @@ Loading = "加載中..."; TipsAppUpdate = "新測試版本"; AppUpdate = "立即更新"; +Cancel="取消"; diff --git a/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/error.imageset/Contents.json b/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_error_nys.imageset/Contents.json similarity index 81% rename from NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/error.imageset/Contents.json rename to NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_error_nys.imageset/Contents.json index 896e2f5..32f0d00 100644 --- a/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/error.imageset/Contents.json +++ b/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_error_nys.imageset/Contents.json @@ -15,7 +15,7 @@ "scale" : "1x" }, { - "filename" : "error@2x.png", + "filename" : "icon_error_nys@2x.png", "idiom" : "universal", "scale" : "2x" }, @@ -26,12 +26,12 @@ "value" : "dark" } ], - "filename" : "error_dark@2x.png", + "filename" : "icon_error_nys_dark@2x.png", "idiom" : "universal", "scale" : "2x" }, { - "filename" : "error@3x.png", + "filename" : "icon_error_nys@3x.png", "idiom" : "universal", "scale" : "3x" }, @@ -42,7 +42,7 @@ "value" : "dark" } ], - "filename" : "error_dark@3x.png", + "filename" : "icon_error_nys_dark@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/error.imageset/error@2x.png b/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_error_nys.imageset/icon_error_nys@2x.png similarity index 100% rename from NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/error.imageset/error@2x.png rename to NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_error_nys.imageset/icon_error_nys@2x.png diff --git a/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/error.imageset/error@3x.png b/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_error_nys.imageset/icon_error_nys@3x.png similarity index 100% rename from NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/error.imageset/error@3x.png rename to NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_error_nys.imageset/icon_error_nys@3x.png diff --git a/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/error.imageset/error_dark@2x.png b/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_error_nys.imageset/icon_error_nys_dark@2x.png similarity index 100% rename from NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/error.imageset/error_dark@2x.png rename to NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_error_nys.imageset/icon_error_nys_dark@2x.png diff --git a/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/error.imageset/error_dark@3x.png b/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_error_nys.imageset/icon_error_nys_dark@3x.png similarity index 100% rename from NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/error.imageset/error_dark@3x.png rename to NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_error_nys.imageset/icon_error_nys_dark@3x.png diff --git a/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/linkedin_binding_magnifier.imageset/Contents.json b/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_loading_nys.imageset/Contents.json similarity index 77% rename from NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/linkedin_binding_magnifier.imageset/Contents.json rename to NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_loading_nys.imageset/Contents.json index b64652d..aaded18 100644 --- a/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/linkedin_binding_magnifier.imageset/Contents.json +++ b/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_loading_nys.imageset/Contents.json @@ -15,7 +15,7 @@ "scale" : "1x" }, { - "filename" : "linkedin_binding_magnifier@2x.png", + "filename" : "icon_loading_nys@2x.png", "idiom" : "universal", "scale" : "2x" }, @@ -26,12 +26,12 @@ "value" : "dark" } ], - "filename" : "linkedin_binding_magnifier_dark@2x.png", + "filename" : "icon_loading_nys_dark@2x.png", "idiom" : "universal", "scale" : "2x" }, { - "filename" : "linkedin_binding_magnifier@3x.png", + "filename" : "icon_loading_nys@3x.png", "idiom" : "universal", "scale" : "3x" }, @@ -42,7 +42,7 @@ "value" : "dark" } ], - "filename" : "linkedin_binding_magnifier_dark@3x.png", + "filename" : "icon_loading_nys_dark@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/linkedin_binding_magnifier.imageset/linkedin_binding_magnifier@2x.png b/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_loading_nys.imageset/icon_loading_nys@2x.png similarity index 100% rename from NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/linkedin_binding_magnifier.imageset/linkedin_binding_magnifier@2x.png rename to NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_loading_nys.imageset/icon_loading_nys@2x.png diff --git a/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/linkedin_binding_magnifier.imageset/linkedin_binding_magnifier@3x.png b/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_loading_nys.imageset/icon_loading_nys@3x.png similarity index 100% rename from NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/linkedin_binding_magnifier.imageset/linkedin_binding_magnifier@3x.png rename to NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_loading_nys.imageset/icon_loading_nys@3x.png diff --git a/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/linkedin_binding_magnifier.imageset/linkedin_binding_magnifier_dark@2x.png b/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_loading_nys.imageset/icon_loading_nys_dark@2x.png similarity index 100% rename from NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/linkedin_binding_magnifier.imageset/linkedin_binding_magnifier_dark@2x.png rename to NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_loading_nys.imageset/icon_loading_nys_dark@2x.png diff --git a/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/linkedin_binding_magnifier.imageset/linkedin_binding_magnifier_dark@3x.png b/NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_loading_nys.imageset/icon_loading_nys_dark@3x.png similarity index 100% rename from NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/linkedin_binding_magnifier.imageset/linkedin_binding_magnifier_dark@3x.png rename to NYSUIKit/Resources/NYSUIKit.xcassets/EmptyData/icon_loading_nys.imageset/icon_loading_nys_dark@3x.png diff --git a/NYSUIKit/UI/NYSFirVersionCheck/NYSFirVersionCheck.h b/NYSUIKit/UI/NYSFirVersionCheck/NYSFirVersionCheck.h index e4288f8..1ce484c 100644 --- a/NYSUIKit/UI/NYSFirVersionCheck/NYSFirVersionCheck.h +++ b/NYSUIKit/UI/NYSFirVersionCheck/NYSFirVersionCheck.h @@ -7,7 +7,20 @@ #import -typedef void(^NYSFirVersionCheckCompletion)(NSDictionary *responseDictionary); +@interface NYSFirVersionCheckModel :NSObject +@property (nonatomic , copy) NSString * build; +@property (nonatomic , copy) NSString * installUrl; +@property (nonatomic , copy) NSString * changelog; +@property (nonatomic , copy) NSString * versionShort; +@property (nonatomic , copy) NSString * direct_install_url; +@property (nonatomic , copy) NSString * install_url; +@property (nonatomic , copy) NSString * update_url; +@property (nonatomic , copy) NSString * updated_at; +@property (nonatomic , copy) NSString * versionBuild; +@property (nonatomic , copy) NSString * name; +@end + +typedef void(^NYSFirVersionCheckCompletion)(NSDictionary *responseDictionary, NYSFirVersionCheckModel *checkModel); @interface NYSFirVersionCheck : NSObject diff --git a/NYSUIKit/UI/NYSFirVersionCheck/NYSFirVersionCheck.m b/NYSUIKit/UI/NYSFirVersionCheck/NYSFirVersionCheck.m index 30c6888..6965357 100644 --- a/NYSUIKit/UI/NYSFirVersionCheck/NYSFirVersionCheck.m +++ b/NYSUIKit/UI/NYSFirVersionCheck/NYSFirVersionCheck.m @@ -7,6 +7,33 @@ #import "NYSFirVersionCheck.h" #import "NYSUIKitPublicHeader.h" +#import "NSBundle+NYSFramework.h" + +@implementation NYSFirVersionCheckModel + +- (instancetype)initWithDictionary:(NSDictionary *)dictionary { + self = [super init]; + if (self) { + _build = dictionary[@"build"]; + _installUrl = dictionary[@"installUrl"]; + _versionShort = dictionary[@"versionShort"]; + _direct_install_url = dictionary[@"direct_install_url"]; + _install_url = dictionary[@"install_url"]; + _update_url = dictionary[@"update_url"]; + _updated_at = dictionary[@"updated_at"]; + _versionBuild = dictionary[@"version"]; + _name = dictionary[@"name"]; + id changelogValue = dictionary[@"changelog"]; + if (changelogValue != [NSNull null]) { + _changelog = changelogValue; + } else { + _changelog = @""; + } + } + return self; +} + +@end @interface NYSFirVersionCheck() @@ -74,6 +101,7 @@ + (void)check:(NYSFirVersionCheckCompletion)completion { } else { NSError *parseError = nil; NSDictionary *responseDictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError]; + NYSFirVersionCheckModel *checkModel = [[NYSFirVersionCheckModel alloc] initWithDictionary:responseDictionary]; [NYSTools log:self.class msg:[NSString stringWithFormat:@"FIR - 更新内容: \n%@ ", responseDictionary]]; NSString *code = responseDictionary[@"code"]; @@ -89,16 +117,16 @@ + (void)check:(NYSFirVersionCheckCompletion)completion { NSString *currentBuild = [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey]; int relt = [self convertVersion:versionShort v2:appVersion]; - if (relt == 1) { // 版本号升级 + if (relt == 1) { // 版本号比较 if (completion) { - completion(responseDictionary); + completion(responseDictionary, checkModel); } else { [self showAlert:responseDictionary]; } - } else if (relt == 0) { // 构建号升级 + } else if (build.intValue > currentBuild.intValue) { // 构建号比较 if (completion) { - completion(responseDictionary); + completion(responseDictionary, checkModel); } else { [self showAlert:responseDictionary]; } @@ -117,12 +145,12 @@ + (void)showAlert:(NSDictionary *)responseDictionary { NSString *build = responseDictionary[@"build"]; NSString *version = [self nullToString:responseDictionary[@"versionShort"]]; NSString *changelog = [self nullToString:responseDictionary[@"changelog"]]; - NSString *title = NSLocalizedStringFromTable(@"TipsAppUpdate", @"InfoPlist", nil); + NSString *title = [NSBundle nys_localizedStringForKey:@"TipsAppUpdate"]; dispatch_async(dispatch_get_main_queue(), ^{ UIAlertController *alertController = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"%@:%@(%@)", title, version, build] message:changelog preferredStyle:UIAlertControllerStyleAlert]; - UIAlertAction *laterAction = [UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"Cancel", @"InfoPlist", nil) style:UIAlertActionStyleCancel handler:nil]; - UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"AppUpdate", @"InfoPlist", nil) style:UIAlertActionStyleDestructive handler:^(UIAlertAction*action) { + UIAlertAction *laterAction = [UIAlertAction actionWithTitle:[NSBundle nys_localizedStringForKey:@"Cancel"] style:UIAlertActionStyleCancel handler:nil]; + UIAlertAction *okAction = [UIAlertAction actionWithTitle:[NSBundle nys_localizedStringForKey:@"AppUpdate"] style:UIAlertActionStyleDestructive handler:^(UIAlertAction*action) { [[UIApplication sharedApplication] openURL:[NSURL URLWithString:responseDictionary[@"update_url"]] options:@{} completionHandler:nil]; }]; @@ -145,7 +173,7 @@ + (NSString *)nullToString:(id)string { 比较版本号 @param v1 版本1 @param v2 版本2 - @return 返回0:相等 1:v1>v2 -1:v1v2返回1 v1v2_i?1:-1; + return v1_i>v2_i ? 1 : -1; } } // 循环结束,返回相等 diff --git a/NYSUIKit/UI/NYSLoadingButton/NYSLoadingButton.h b/NYSUIKit/UI/NYSLoadingButton/NYSLoadingButton.h index ac776b1..9c12a2f 100644 --- a/NYSUIKit/UI/NYSLoadingButton/NYSLoadingButton.h +++ b/NYSUIKit/UI/NYSLoadingButton/NYSLoadingButton.h @@ -5,23 +5,22 @@ // Copyright © 2020 NYS. ALL rights reserved. // -@import UIKit; +#import -typedef enum : NSUInteger { +typedef NS_ENUM(NSInteger, LoadingType) { NONE = 0, TOP_LINE = 1, INDICATOR = 2, BACKGROUND_HIGHLIGHTER = 3, CIRCLE_AND_TICK = 4, ALL = 5 -} LoadingType; +}; -IB_DESIGNABLE @interface NYSLoadingButton : UIButton /// BACKGROUND_HIGHLIGHTER | CIRCLE_AND_TICK 下有效 -@property (copy) IBInspectable UIColor *loadingColor; -@property (copy) IBInspectable UIColor *filledBackgroundColor; +@property (copy) UIColor *loadingColor; +@property (copy) UIColor *filledBackgroundColor; @property (assign) LoadingType animationType; /// start loading @@ -32,6 +31,7 @@ IB_DESIGNABLE - (void)fillTheButtonWith:(CGFloat)percent; /// update circle mode stroke - percent like 1,20...100 - (void)fillTheCircleStrokeLoadingWith:(CGFloat)percent; + @end diff --git a/NYSUIKit/UI/NYSLoadingButton/NYSLoadingButton.m b/NYSUIKit/UI/NYSLoadingButton/NYSLoadingButton.m index 5ab87d5..df195e3 100644 --- a/NYSUIKit/UI/NYSLoadingButton/NYSLoadingButton.m +++ b/NYSUIKit/UI/NYSLoadingButton/NYSLoadingButton.m @@ -9,8 +9,8 @@ #import "NYSUIKitPublicHeader.h" @interface NYSLoadingButton() -@property (assign,readonly) CGFloat percentFilled; -@property (assign,readonly) BOOL isloadingShowing; +@property (assign, readonly) CGFloat percentFilled; +@property (assign, readonly) BOOL isloadingShowing; @property (readonly) CAShapeLayer *filledLoadingLayer; @property CAShapeLayer *circleStrokeLoadingLayer; diff --git a/NYSUIKit/UI/NYSLocation/NYSSystemLocation.h b/NYSUIKit/UI/NYSLocation/NYSSystemLocation.h index 43af2fc..1a52adc 100644 --- a/NYSUIKit/UI/NYSLocation/NYSSystemLocation.h +++ b/NYSUIKit/UI/NYSLocation/NYSSystemLocation.h @@ -26,6 +26,7 @@ typedef void (^NYSLocationCompletion)(NSString * _Nonnull address, CLLocationCoo /// 持续定位 - (void)startUpdatingLocationSystem; - (void)startUpdatingLocation:(NYSCoordinateType)coordinateType; +- (void)stopUpdatingLocationSystem; /// 逆地理编码 /// - Parameter currentLocation: 当前位置 diff --git a/NYSUIKit/UI/NYSLocation/NYSSystemLocation.m b/NYSUIKit/UI/NYSLocation/NYSSystemLocation.m index 819f1ff..7c5875a 100644 --- a/NYSUIKit/UI/NYSLocation/NYSSystemLocation.m +++ b/NYSUIKit/UI/NYSLocation/NYSSystemLocation.m @@ -57,10 +57,6 @@ - (void)requestLocation:(NYSCoordinateType)coordinateType { [self.sysLocationManager requestLocation]; [NYSTools showLoading]; - __weak __typeof(self)weakSelf = self; - [NYSTools dismissWithDelay:10 completion:^{ - [weakSelf.sysLocationManager stopUpdatingLocation]; - }]; } /// 持续定位 @@ -92,11 +88,12 @@ - (void)reverseGeocodeWithLocation:(CLLocation * _Nonnull)currentLocation { // 系统逆地理编码 __weak typeof(self) weakSelf = self; [self.geoCoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) { + __strong typeof(weakSelf) strongSelf = weakSelf; [NYSTools dismiss]; - + if (error) { - if (weakSelf.completion) { - weakSelf.completion(@"", kCLLocationCoordinate2DInvalid, error); + if (strongSelf.completion) { + strongSelf.completion(@"", kCLLocationCoordinate2DInvalid, error); } [NYSTools log:self.class error:error]; return; @@ -104,25 +101,25 @@ - (void)reverseGeocodeWithLocation:(CLLocation * _Nonnull)currentLocation { if (placemarks.count > 0) { CLPlacemark *placemark = [placemarks firstObject]; NSString *address = [NSString stringWithFormat:@"%@%@%@%@", placemark.administrativeArea, placemark.locality, placemark.subLocality, placemark.thoroughfare]; - if (weakSelf.completion) { - switch (weakSelf.coordinateType) { + if (strongSelf.completion) { + switch (strongSelf.coordinateType) { case NYSLocationTypeBaiDuMap: { NYSLocationTransform *beforeTransform = [[NYSLocationTransform alloc] initWithLatitude:coordinate.latitude andLongitude:coordinate.longitude]; NYSLocationTransform *afterTransform = [beforeTransform transformFromGPSToGD]; NYSLocationTransform *lastTransform = [afterTransform transformFromGDToBD]; - weakSelf.completion(address, CLLocationCoordinate2DMake(lastTransform.latitude, lastTransform.longitude), error); + strongSelf.completion(address, CLLocationCoordinate2DMake(lastTransform.latitude, lastTransform.longitude), error); } break; case NYSLocationTypeAMap: { NYSLocationTransform *beforeTransform = [[NYSLocationTransform alloc] initWithLatitude:coordinate.latitude andLongitude:coordinate.longitude]; NYSLocationTransform *afterTransform = [beforeTransform transformFromGPSToGD]; - weakSelf.completion(address, CLLocationCoordinate2DMake(afterTransform.latitude, afterTransform.longitude), error); + strongSelf.completion(address, CLLocationCoordinate2DMake(afterTransform.latitude, afterTransform.longitude), error); } break; case NYSLocationTypeSysMap: - weakSelf.completion(address, coordinate, error); + strongSelf.completion(address, coordinate, error); break; default: @@ -145,11 +142,16 @@ - (void)locationManager:(CLLocationManager *)manager didFailWithError:(nonnull N [manager stopUpdatingLocation]; } -- (void)dealloc { +- (void)stopUpdatingLocationSystem { + [NYSTools dismiss]; [self.sysLocationManager stopUpdatingLocation]; self.sysLocationManager.delegate = nil; self.sysLocationManager = nil; [self.geoCoder cancelGeocode]; } +- (void)dealloc { + [self stopUpdatingLocationSystem]; +} + @end diff --git a/NYSUIKit/UI/NYSTableViewAnimation/NYSTableViewAnimation.h b/NYSUIKit/UI/NYSTableViewAnimation/NYSTableViewAnimation.h index f89c486..4f491ee 100644 --- a/NYSUIKit/UI/NYSTableViewAnimation/NYSTableViewAnimation.h +++ b/NYSUIKit/UI/NYSTableViewAnimation/NYSTableViewAnimation.h @@ -8,30 +8,28 @@ #import #import -typedef NS_ENUM(NSInteger,NYSTableViewAnimationType){ - NYSTableViewAnimationTypeMove = 0, // 从左至右依次滑入 - NYSTableViewAnimationTypeMoveSpring = 0, // 类似上一个 - NYSTableViewAnimationTypeAlpha, // 从左至右依次滑入 回弹 - NYSTableViewAnimationTypeFall, // 渐变从上至下依次进入 - NYSTableViewAnimationTypeShake, // 从下自上依次堆叠 - NYSTableViewAnimationTypeOverTurn, // 左右穿插 - NYSTableViewAnimationTypeToTop, // 从上至下依次翻转 - NYSTableViewAnimationTypeSpringList, // 从下自上依次堆叠 - NYSTableViewAnimationTypeShrinkToTop, // 从上至下依次翻转 弹性 - NYSTableViewAnimationTypeLayDown, // 从下自上收缩 - NYSTableViewAnimationTypeRote, // 从上至下滚动展开 +typedef NS_ENUM(NSInteger, NYSTableViewAnimationType){ + NYSTableViewAnimationTypeMoveSpring = 0, // 从左至右依次滑入 + NYSTableViewAnimationTypeAlpha, // 渐变从上至下依次进入 + NYSTableViewAnimationTypeFall, // 从下自上依次掉落 + NYSTableViewAnimationTypeShake, // 左右穿插 + NYSTableViewAnimationTypeOverTurn, // 从上至下依次翻转 + NYSTableViewAnimationTypeToTop, // 从下自上依次堆叠 + NYSTableViewAnimationTypeSpringList, // 从上至下依次翻转 弹性 + NYSTableViewAnimationTypeShrinkToTop, // 从下自上收缩 + NYSTableViewAnimationTypeLayDown, // 从上至下滚动展开 + NYSTableViewAnimationTypeRote, // 从上至下依次翻转 }; @interface NYSTableViewAnimation : NSObject - /// 显示cell动画 /// - Parameters: /// - animationType: 动画类型 /// - tableView: 作用表格 ++ (void)show:(NYSTableViewAnimationType)animationType tableView:(UITableView *)tableView; + (void)showWithAnimationType:(NYSTableViewAnimationType)animationType tableView:(UITableView *)tableView; -+ (void)moveAnimationWithTableView:(UITableView *)tableView; + (void)moveSpringAnimationWithTableView:(UITableView *)tableView; + (void)alphaAnimationWithTableView:(UITableView *)tableView; + (void)fallAnimationWithTableView:(UITableView *)tableView; diff --git a/NYSUIKit/UI/NYSTableViewAnimation/NYSTableViewAnimation.m b/NYSUIKit/UI/NYSTableViewAnimation/NYSTableViewAnimation.m index c6edce0..fabd511 100644 --- a/NYSUIKit/UI/NYSTableViewAnimation/NYSTableViewAnimation.m +++ b/NYSUIKit/UI/NYSTableViewAnimation/NYSTableViewAnimation.m @@ -11,18 +11,16 @@ @interface NYSTableViewAnimation () - @end @implementation NYSTableViewAnimation - -+ (void)showWithAnimationType:(NYSTableViewAnimationType)animationType tableView:(UITableView *)tableView{ ++ (void)show:(NYSTableViewAnimationType)animationType tableView:(UITableView *)tableView { unsigned int count = 0; // Get Class Method Method *methodlist = class_copyMethodList(object_getClass(self.class), &count); - int tag= 0; + int tag = 0; for (int i = 0; i < count; i++) { Method method = methodlist[i]; SEL selector = method_getName(method); @@ -40,21 +38,43 @@ + (void)showWithAnimationType:(NYSTableViewAnimationType)animationType tableView free(methodlist); } -+ (void)moveAnimationWithTableView:(UITableView *)tableView { - - NSArray *cells = tableView.visibleCells; - for (int i = 0; i < cells.count; i++) { - CGFloat totalTime = 0.3; - UITableViewCell *cell = [tableView.visibleCells objectAtIndex:i]; - cell.transform = CGAffineTransformMakeTranslation(-[[UIScreen mainScreen] bounds].size.width, 0); - [UIView animateWithDuration:0.25 delay:i*(totalTime/cells.count) options:0 animations:^{ - cell.transform = CGAffineTransformIdentity; - } completion:^(BOOL finished) { - - }]; - ++ (void)showWithAnimationType:(NYSTableViewAnimationType)animationType tableView:(UITableView *)tableView { + switch (animationType) { + case NYSTableViewAnimationTypeMoveSpring: + [self moveSpringAnimationWithTableView:tableView]; + break; + case NYSTableViewAnimationTypeAlpha: + [self alphaAnimationWithTableView:tableView]; + break; + case NYSTableViewAnimationTypeFall: + [self fallAnimationWithTableView:tableView]; + break; + case NYSTableViewAnimationTypeShake: + [self shakeAnimationWithTableView:tableView]; + break; + case NYSTableViewAnimationTypeOverTurn: + [self overTurnAnimationWithTableView:tableView]; + break; + case NYSTableViewAnimationTypeToTop: + [self toTopAnimationWithTableView:tableView]; + break; + case NYSTableViewAnimationTypeSpringList: + [self springListAnimationWithTableView:tableView]; + break; + case NYSTableViewAnimationTypeShrinkToTop: + [self shrinkToTopAnimationWithTableView:tableView]; + break; + case NYSTableViewAnimationTypeLayDown: + [self layDownAnimationWithTableView:tableView]; + break; + case NYSTableViewAnimationTypeRote: + [self roteAnimationWithTableView:tableView]; + break; + default: + break; } } + + (void)moveSpringAnimationWithTableView:(UITableView *)tableView { NSArray *cells = tableView.visibleCells; @@ -69,6 +89,7 @@ + (void)moveSpringAnimationWithTableView:(UITableView *)tableView { }]; } } + + (void)alphaAnimationWithTableView:(UITableView *)tableView { NSArray *cells = tableView.visibleCells; @@ -83,7 +104,6 @@ + (void)alphaAnimationWithTableView:(UITableView *)tableView { } } - + (void)fallAnimationWithTableView:(UITableView *)tableView { NSArray *cells = tableView.visibleCells; @@ -101,7 +121,6 @@ + (void)fallAnimationWithTableView:(UITableView *)tableView { } } - + (void)shakeAnimationWithTableView:(UITableView *)tableView { NSArray *cells = tableView.visibleCells; @@ -140,7 +159,6 @@ + (void)overTurnAnimationWithTableView:(UITableView *)tableView { + (void)toTopAnimationWithTableView:(UITableView *)tableView { - NSArray *cells = tableView.visibleCells; NSTimeInterval totalTime = 0.8; @@ -214,8 +232,6 @@ + (void)layDownAnimationWithTableView:(UITableView *)tableView { } - - + (void)roteAnimationWithTableView:(UITableView *)tableView { NSArray *cells = tableView.visibleCells; @@ -240,5 +256,4 @@ + (void)roteAnimationWithTableView:(UITableView *)tableView { } } - @end diff --git a/README.md b/README.md index aeb26dd..dcbe578 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,8 @@ NYSKit ## Usage ```ruby - pod 'NYSKit', :git => 'https://github.com/niyongsheng/NYSKit.git' - pod 'NYSUIKit', :git => 'https://github.com/niyongsheng/NYSKit.git' + pod 'NYSKit', '~> 0.0.7' + pod 'NYSUIKit', '~> 0.0.7' pod install ``` @@ -40,6 +40,8 @@ NYSKit `NYSUIKit Document:` https://niyongsheng.github.io/Document/NYSWS/NYSUIKit/index.html +`Json Transition:`[JsonModelFactory](https://github.com/niyongsheng/JsonModelFactory) + `Example Project:`[NYSWS](https://github.com/niyongsheng/NYSWS) ## Architecture @@ -57,6 +59,8 @@ NYSKit ├─ NYSKitPublicHeader.h ├─ NYSNetRequest.h ├─ NYSNetRequest.m +├─ NYSRSAObjC.h +├─ NYSRSAObjC.m ├─ NYSRegularCheck.h ├─ NYSRegularCheck.m ├─ NYSTools.h @@ -99,6 +103,8 @@ NYSUIKit │ ├─ UIButton+NYS.m │ ├─ UIColor+NYS.h │ ├─ UIColor+NYS.m +│ ├─ UIControl+NYS.h +│ ├─ UIControl+NYS.m │ ├─ UIImage+NYS.h │ ├─ UIImage+NYS.m │ ├─ UINavigationController+FDFullscreenPopGesture.h @@ -199,9 +205,6 @@ NYSUIKit ④ `iOS >= 13.0`
⑤ `Xcode >= 14.0`
-## Contribution -Reward[:lollipop:](https://github.com/niyongsheng/niyongsheng.github.io/blob/master/Beg/README.md) Encourage[:heart:](https://github.com/niyongsheng/NYSKit/stargazers) - ## Contact Me * E-mail: niyongsheng@Outlook.com * Weibo: [@Ni永胜](https://weibo.com/u/7317805089)