├── SwiftDemo ├── SwiftDemo │ ├── Resources │ │ ├── Assets.xcassets │ │ │ ├── Contents.json │ │ │ ├── TabNav │ │ │ │ ├── Contents.json │ │ │ │ ├── tabbar_me.imageset │ │ │ │ │ ├── tabbar_me@2x.png │ │ │ │ │ ├── tabbar_me@3x.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── tabbar_gym.imageset │ │ │ │ │ ├── tabbar_gym@2x.png │ │ │ │ │ ├── tabbar_gym@3x.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── tabbar_meH.imageset │ │ │ │ │ ├── tabbar_meH@2x.png │ │ │ │ │ ├── tabbar_meH@3x.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── tabbar_gymH.imageset │ │ │ │ │ ├── tabbar_gymH@2x.png │ │ │ │ │ ├── tabbar_gymH@3x.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── tabbar_home.imageset │ │ │ │ │ ├── tabbar_home@2x.png │ │ │ │ │ ├── tabbar_home@3x.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── tabbar_homeH.imageset │ │ │ │ │ ├── tabbar_homeH@2x.png │ │ │ │ │ ├── tabbar_homeH@3x.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── tabbar_coterie.imageset │ │ │ │ │ ├── tabbar_coterie@2x.png │ │ │ │ │ ├── tabbar_coterie@3x.png │ │ │ │ │ └── Contents.json │ │ │ │ └── tabbar_coterieH.imageset │ │ │ │ │ ├── tabbar_coterieH@2x.png │ │ │ │ │ ├── tabbar_coterieH@3x.png │ │ │ │ │ └── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── Info.plist │ │ └── Base.lproj │ │ │ ├── Main.storyboard │ │ │ └── LaunchScreen.storyboard │ ├── Code │ │ ├── Home │ │ │ ├── TestViewController.h │ │ │ ├── TestViewController.m │ │ │ └── HomeViewController.swift │ │ ├── Society │ │ │ ├── Model │ │ │ │ ├── CoachListModel.swift │ │ │ │ └── SocietyListModel.swift │ │ │ ├── View │ │ │ │ └── SocietyListCell.swift │ │ │ └── SocietyViewController.swift │ │ ├── Mine │ │ │ └── MeViewController.swift │ │ └── Gym │ │ │ └── GymViewController.swift │ ├── Library │ │ └── Custom │ │ │ └── HWNetworking │ │ │ ├── HWNetworkingError.swift │ │ │ ├── HWNetworkingOC.swift │ │ │ ├── HWMultipartData.swift │ │ │ ├── HWAPI.swift │ │ │ └── HWNetworking.swift │ ├── Main │ │ ├── Controller │ │ │ ├── DNavigationController.swift │ │ │ ├── DBaseVC.swift │ │ │ └── DTabBarController.swift │ │ ├── AppDelegate.swift │ │ ├── API.swift │ │ ├── SwiftDemo-Bridging-Header.h │ │ └── View │ │ │ └── DTabBar.swift │ └── Tools │ │ ├── Extends │ │ ├── UILabel-Extension.swift │ │ ├── UIFont-Extension.swift │ │ ├── UIView-Extension.swift │ │ └── UIColor-Extension.swift │ │ ├── Theme │ │ └── Theme.swift │ │ └── Constants │ │ └── AppConstants.swift ├── SwiftDemo.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── project.pbxproj ├── SwiftDemo.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Podfile.lock ├── Podfile └── SwiftDemoTests │ ├── Info.plist │ └── SwiftDemoTests.swift ├── LICENSE ├── .gitignore └── README.md /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_me.imageset/tabbar_me@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HouWan/HWNetworking/HEAD/SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_me.imageset/tabbar_me@2x.png -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_me.imageset/tabbar_me@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HouWan/HWNetworking/HEAD/SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_me.imageset/tabbar_me@3x.png -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_gym.imageset/tabbar_gym@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HouWan/HWNetworking/HEAD/SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_gym.imageset/tabbar_gym@2x.png -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_gym.imageset/tabbar_gym@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HouWan/HWNetworking/HEAD/SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_gym.imageset/tabbar_gym@3x.png -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_meH.imageset/tabbar_meH@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HouWan/HWNetworking/HEAD/SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_meH.imageset/tabbar_meH@2x.png -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_meH.imageset/tabbar_meH@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HouWan/HWNetworking/HEAD/SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_meH.imageset/tabbar_meH@3x.png -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_gymH.imageset/tabbar_gymH@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HouWan/HWNetworking/HEAD/SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_gymH.imageset/tabbar_gymH@2x.png -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_gymH.imageset/tabbar_gymH@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HouWan/HWNetworking/HEAD/SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_gymH.imageset/tabbar_gymH@3x.png -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_home.imageset/tabbar_home@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HouWan/HWNetworking/HEAD/SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_home.imageset/tabbar_home@2x.png -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_home.imageset/tabbar_home@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HouWan/HWNetworking/HEAD/SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_home.imageset/tabbar_home@3x.png -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_homeH.imageset/tabbar_homeH@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HouWan/HWNetworking/HEAD/SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_homeH.imageset/tabbar_homeH@2x.png -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_homeH.imageset/tabbar_homeH@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HouWan/HWNetworking/HEAD/SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_homeH.imageset/tabbar_homeH@3x.png -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_coterie.imageset/tabbar_coterie@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HouWan/HWNetworking/HEAD/SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_coterie.imageset/tabbar_coterie@2x.png -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_coterie.imageset/tabbar_coterie@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HouWan/HWNetworking/HEAD/SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_coterie.imageset/tabbar_coterie@3x.png -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_coterieH.imageset/tabbar_coterieH@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HouWan/HWNetworking/HEAD/SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_coterieH.imageset/tabbar_coterieH@2x.png -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_coterieH.imageset/tabbar_coterieH@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HouWan/HWNetworking/HEAD/SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_coterieH.imageset/tabbar_coterieH@3x.png -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Code/Home/TestViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TestViewController.h 3 | // SwiftDemo 4 | // 5 | // Created by HouWan on 2020/8/20. 6 | // Copyright © 2020 HouWan. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface TestViewController : UIViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Code/Society/Model/CoachListModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CoachListModel.swift 3 | // SwiftDemo 4 | // 5 | // Created by HouWan on 2020/5/10. 6 | // Copyright © 2020 HouWan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class CoachListModel { 12 | var deptName: String? 13 | var coverPic: String? 14 | var product_price: Double? 15 | var curriSlogans: String? 16 | 17 | required init() {} 18 | } 19 | -------------------------------------------------------------------------------- /SwiftDemo/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Alamofire (5.2.2) 3 | - SwiftyJSON (5.0.0) 4 | 5 | DEPENDENCIES: 6 | - Alamofire (~> 5.2.0) 7 | - SwiftyJSON (~> 5.0.0) 8 | 9 | SPEC REPOS: 10 | https://github.com/CocoaPods/Specs.git: 11 | - Alamofire 12 | - SwiftyJSON 13 | 14 | SPEC CHECKSUMS: 15 | Alamofire: 814429acc853c6c54ff123fc3d2ef66803823ce0 16 | SwiftyJSON: 36413e04c44ee145039d332b4f4e2d3e8d6c4db7 17 | 18 | PODFILE CHECKSUM: 51998e89b3a01a8b9bf69daafae7b6422a30c87e 19 | 20 | COCOAPODS: 1.9.3 21 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_gym.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "tabbar_gym@2x.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "tabbar_gym@3x.png", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_me.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "tabbar_me@2x.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "tabbar_me@3x.png", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_meH.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "tabbar_meH@2x.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "tabbar_meH@3x.png", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_gymH.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "tabbar_gymH@2x.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "tabbar_gymH@3x.png", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_home.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "tabbar_home@2x.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "tabbar_home@3x.png", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_homeH.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "tabbar_homeH@2x.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "tabbar_homeH@3x.png", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_coterie.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "tabbar_coterie@2x.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "tabbar_coterie@3x.png", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/TabNav/tabbar_coterieH.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "tabbar_coterieH@2x.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "tabbar_coterieH@3x.png", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /SwiftDemo/Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | 3 | platform :ios, '10.0' 4 | 5 | inhibit_all_warnings! 6 | 7 | target 'SwiftDemo' do 8 | # Use dynamic frameworks 9 | use_frameworks! 10 | 11 | # 网络请求,类似`AFNetworking` 12 | # https://github.com/Alamofire/Alamofire 13 | pod 'Alamofire', '~> 5.2.0' 14 | 15 | # JOSN转模型 16 | # https://github.com/SwiftyJSON/SwiftyJSON 17 | pod 'SwiftyJSON', '~> 5.0.0' 18 | 19 | target 'SwiftDemoTests' do 20 | inherit! :search_paths 21 | # Pods for testing 22 | end 23 | 24 | end 25 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Library/Custom/HWNetworking/HWNetworkingError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HWNetworkingError.swift 3 | // LianDuoDuo 4 | // 5 | // Created by HouWan on 2020/8/4. 6 | // Copyright © 2020 CSData. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// 请求的错误反馈,继承`NSObject`为了让OC也能调用 12 | public class HWNetworkingError: NSObject { 13 | /// 错误码 14 | @objc var code = -1 15 | /// 错误描述 16 | @objc var localizedDescription: String 17 | 18 | init(code: Int, desc: String) { 19 | self.code = code 20 | self.localizedDescription = desc 21 | super.init() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Code/Mine/MeViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MeViewController.swift 3 | // SwiftDemo 4 | // 5 | // Created by HouWan on 2020/5/7. 6 | // Copyright © 2020 HouWan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class MeViewController: DBaseVC { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | title = "我的" 17 | 18 | let a = UILabel(font: SemiboldFont(25), color: UIColor.purple) 19 | a.text = "天使😇天使" 20 | a.frame = CGRect(x: 10, y: 100, width: 190, height: 55) 21 | view.addSubview(a) 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Main/Controller/DNavigationController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DNavigationController.swift 3 | // SwiftDemo 4 | // 5 | // Created by HouWan on 2020/5/7. 6 | // Copyright © 2020 HouWan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class DNavigationController: UINavigationController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | } 16 | 17 | override func pushViewController(_ viewController: UIViewController, animated: Bool) { 18 | if viewControllers.count > 0 { 19 | // if是为了解决push回来时,没有底部导航的问题 20 | viewController.hidesBottomBarWhenPushed = true 21 | 22 | } 23 | super.pushViewController(viewController, animated: animated) 24 | } 25 | 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Tools/Extends/UILabel-Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UILabel-Extension.swift 3 | // SwiftDemo 4 | // 5 | // Created by HouWan on 2020/5/8. 6 | // Copyright © 2020 HouWan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension UILabel { 12 | 13 | /// 快速创建一个`UILabel`,使用`font & textColor | alignment` 14 | /// - Author: HouWan 15 | /// - Parameters: 16 | /// - font: UIFont对象 17 | /// - color: 字体颜色 18 | /// - alignment: The default was NSTextAlignmentLeft 19 | convenience public init(font: UIFont, color: UIColor, alignment: NSTextAlignment = .left) { 20 | self.init() 21 | self.font = font 22 | self.textColor = color 23 | self.textAlignment = alignment 24 | } 25 | 26 | 27 | 28 | } 29 | 30 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Main/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SwiftDemo 4 | // 5 | // Created by HouWan on 2020/5/7. 6 | // Copyright © 2020 HouWan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | /// App main window 15 | var window: UIWindow? 16 | 17 | 18 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 19 | 20 | window = UIWindow.init(frame: UIScreen.main.bounds) 21 | window?.backgroundColor = UIColor.white 22 | window?.rootViewController = DTabBarController.init() 23 | window?.makeKeyAndVisible() 24 | 25 | return true 26 | } 27 | 28 | 29 | 30 | 31 | } 32 | 33 | 34 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemoTests/SwiftDemoTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftDemoTests.swift 3 | // SwiftDemoTests 4 | // 5 | // Created by HouWan on 2020/5/7. 6 | // Copyright © 2020 HouWan. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import SwiftDemo 11 | 12 | class SwiftDemoTests: XCTestCase { 13 | 14 | override func setUpWithError() throws { 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDownWithError() throws { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | } 21 | 22 | func testExample() throws { 23 | // This is an example of a functional test case. 24 | // Use XCTAssert and related functions to verify your tests produce the correct results. 25 | } 26 | 27 | func testPerformanceExample() throws { 28 | // This is an example of a performance test case. 29 | self.measure { 30 | // Put the code you want to measure the time of here. 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 HouWan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Tools/Theme/Theme.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Theme.swift 3 | // SwiftDemo 4 | // 5 | // Created by HouWan on 2020/5/8. 6 | // Copyright © 2020 HouWan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | // 约定一:颜色全部用十六进制表示,但是注释上RGB的数值和REX数值 13 | // 约定二:所有颜值,全部在此定义和获取,代码中不允许使用UIColor获取颜色 14 | // 约定三:颜色常量名建议不要指明具体色彩,因为比如白色背景,如果命名为`white_bg`,在深色模式,它可能代表黑色 15 | // 约定三:为了将来主题(or.深色模式)开发,严格遵守一、二、三 16 | 17 | 18 | 19 | 20 | ///============================================================================= 21 | /// - Note: 背景色 22 | ///============================================================================= 23 | 24 | /// White Color (RGB:255,255,255) 25 | let theme_tint_A_color = UIColor.white 26 | 27 | 28 | 29 | 30 | 31 | ///============================================================================= 32 | /// - Note: 文本颜色 33 | ///============================================================================= 34 | 35 | /// Color (RGB:45,45,45) | (0x2D2D2D) 36 | let theme_text_A_color = UIColor(0x2D2D2D) 37 | /// Color (RGB:176,176,176) | (0xB0B0B0) 38 | let theme_text_B_color = UIColor(0xB0B0B0) 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Code/Society/View/SocietyListCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocietyListCell.swift 3 | // SwiftDemo 4 | // 5 | // Created by HouWan on 2020/5/10. 6 | // Copyright © 2020 HouWan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SocietyListCell: UITableViewCell { 12 | 13 | func show(model: CoachListModel) { 14 | // TODO... 15 | } 16 | 17 | // ============================================================================ 18 | // MARK: - Initialization 19 | // ============================================================================ 20 | 21 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { 22 | super.init(style: style, reuseIdentifier: reuseIdentifier) 23 | createAndConfigUI() 24 | } 25 | 26 | required init?(coder: NSCoder) { 27 | super.init(coder: coder) 28 | fatalError("init(coder:) has not been implemented") 29 | } 30 | 31 | func createAndConfigUI() { 32 | selectionStyle = .none 33 | contentView.backgroundColor = UIColor.white 34 | contentView.isExclusiveTouch = true 35 | 36 | contentView.layer.borderColor = UIColor.random.cgColor 37 | contentView.layer.borderWidth = 0.5 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Main/Controller/DBaseVC.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DBaseVC.swift 3 | // SwiftDemo 4 | // 5 | // Created by HouWan on 2020/5/7. 6 | // Copyright © 2020 HouWan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Foundation 11 | 12 | 13 | /// `DBaseVC`是项目大部分控制器的基类,提供了以下主要功能 14 | /// - `view`的背景色 15 | /// - `deinit`移除`Notification` 16 | public class DBaseVC: UIViewController { 17 | 18 | public override func viewDidLoad() { 19 | super.viewDidLoad() 20 | 21 | base_config() 22 | } 23 | 24 | public func base_config() { 25 | view.backgroundColor = UIColor.white 26 | } 27 | 28 | 29 | /// 弹框提示,点击[确定]之后`pop`关闭页面, 没有 30 | /// - Parameter info: 提示信息 31 | public func popWithInfo(info: String) { 32 | guard let navVC = navigationController else { return } 33 | 34 | navVC.popViewController(animated: true) 35 | } 36 | 37 | deinit { 38 | NotificationCenter.default.removeObserver(self) 39 | } 40 | } 41 | 42 | /// For status bar style 43 | extension DBaseVC { 44 | public override var prefersStatusBarHidden: Bool { 45 | get { false } 46 | } 47 | 48 | 49 | public override var preferredStatusBarStyle: UIStatusBarStyle { 50 | get { .default } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Main/API.swift: -------------------------------------------------------------------------------- 1 | // 2 | // API.swift 3 | // 项目API文件 4 | // 5 | // ### ######## #### 6 | // ## ## ## ## ## 7 | // ## ## ## ## ## 8 | // ## ## ######## ## 9 | // ######### ## ## 10 | // ## ## ## ## 11 | // ## ## ## #### 12 | // 13 | 14 | import Foundation 15 | 16 | /// 实现协议,每个接口,都是一个`APIItem` 17 | struct APIItem: HWAPIProtocol { 18 | var url: String { API.DOMAIN + URLPath } // 域名 + path 19 | let description: String 20 | let extra: String? 21 | var method: HWHTTPMethod 22 | 23 | private let URLPath: String // URL的path 24 | 25 | init(_ path: String, d: String, e: String? = nil, m: HWHTTPMethod = .get) { 26 | URLPath = path 27 | description = d 28 | extra = e 29 | method = m 30 | } 31 | 32 | init(_ path: String, m: HWHTTPMethod) { 33 | self.init(path, d: "", e: nil, m: m) 34 | } 35 | } 36 | 37 | /// App的接口 38 | struct API { 39 | /// 项目的域名 40 | static var DOMAIN = "https://api.xxxoo.cn/" 41 | 42 | // MARK: Home模块 43 | struct Home { 44 | static let storeList = APIItem("store/depAll", d: "首页门店列表", m: .post) 45 | } 46 | 47 | // MARK: 我的模块 48 | struct Me { 49 | static let meIndex = APIItem("member/myDetailsNew", d: "我的页面") 50 | } 51 | } 52 | 53 | /** 54 | 可能有人疑问,为什么接口要加一个`description` 55 | 这里解释一下: 56 | 57 | ** 1.在API文件里,能直接明白这接口是做什么的 ** 58 | ** 2.在我项目里,有一个debug隐藏模块,可以看到所有的API请求 ** 59 | ** 3.在debug模块里,不仅后台Java同事能通过`描述`定位接口,测试同事也方便找接口 ** 60 | 61 | */ 62 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Tools/Extends/UIFont-Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIFont-Extension.swift 3 | // SwiftDemo 4 | // 5 | // Created by HouWan on 2020/5/8. 6 | // Copyright © 2020 HouWan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension UIFont { 12 | 13 | /// 快捷创建一个**Medium System Font**,因为UI使用此字体频率非常高 14 | /// - Parameter fontSize: 字体大小 15 | /// - Returns: UIFont对象 16 | public class func mediumFont(ofSize fontSize: CGFloat) -> UIFont { 17 | return UIFont.systemFont(ofSize: fontSize, weight:UIFont.Weight.medium) 18 | } 19 | 20 | /// 快捷创建一个**Semibold System Font**,因为UI使用此字体频率非常高 21 | /// - Parameter fontSize: 字体大小 22 | /// - Returns: UIFont对象 23 | public class func semiboldFont(ofSize fontSize: CGFloat) -> UIFont { 24 | return UIFont.systemFont(ofSize: fontSize, weight:UIFont.Weight.semibold) 25 | } 26 | } 27 | 28 | 29 | /// 快捷创建一个**Medium System Font**,因为UI使用此字体频率非常高 30 | /// - Parameter fontSize: fontSize: 字体大小 31 | /// - Returns: UIFont对象 32 | public func MediumFont(_ fontSize: CGFloat) -> UIFont { 33 | return UIFont.mediumFont(ofSize: fontSize) 34 | } 35 | 36 | /// 快捷创建一个**Semibold System Font**,因为UI使用此字体频率非常高 37 | /// - Parameter fontSize: 字体大小 38 | /// - Returns: UIFont对象 39 | public func SemiboldFont(_ fontSize: CGFloat) -> UIFont { 40 | return UIFont.semiboldFont(ofSize: fontSize) 41 | } 42 | 43 | /// 快捷创建一个**System Font**,因为UI使用此字体频率非常高 44 | /// - Parameter fontSize: 字体大小 45 | /// - Returns: UIFont对象 46 | public func SystemFont(_ fontSize: CGFloat) -> UIFont { 47 | return UIFont.systemFont(ofSize: fontSize) 48 | } 49 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Tools/Constants/AppConstants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppConstants.swift 3 | // SwiftDemo 4 | // 5 | // Created by HouWan on 2020/5/9. 6 | // Copyright © 2020 HouWan. All rights reserved. 7 | // 8 | // 9 | // App 的一些常量,比如全局的枚举值、常用数值、高频工具函数等 10 | // 11 | 12 | import Foundation 13 | 14 | 15 | // ============================================================================ 16 | // MARK: - Function 17 | // ============================================================================ 18 | 19 | 20 | /// 判断是否是`iPhoneX`系列,此系列有`safeArea`的概念 21 | /// - Returns: true代表是`iPhoneX`系列 22 | public func iPhoneX() -> Bool { 23 | // 利用safeAreaInsets.bottom > 0 来判断是否是iPhoneX系列 24 | guard let w = UIApplication.shared.delegate?.window else { 25 | return false 26 | } 27 | 28 | guard #available(iOS 11.0, *) else { 29 | return false 30 | } 31 | 32 | return w!.safeAreaInsets.bottom > 0.0 33 | } 34 | 35 | 36 | // ============================================================================ 37 | // MARK: - Constants 38 | // ============================================================================ 39 | 40 | /// -> 手机屏幕的宽度 41 | public let kScreenWidth = UIScreen.main.bounds.width 42 | /// -> 手机屏幕的高度 43 | public let kScreenHeight = UIScreen.main.bounds.height 44 | 45 | /// `iPhoneX`系列顶部的安全边距 46 | public let kiPhoneXSafeTop = 44.0 47 | /// `iPhoneX`系列底部的安全边距 48 | public let kiPhoneXSafeBottom = 34.0 49 | 50 | /// App状态栏的高度 51 | var kStatusBarHeight: CGFloat { 52 | return iPhoneX() ? 40.0 : 20 53 | } 54 | 55 | /// App导航栏高度,包含状态栏(20/44) 56 | var kNavigatioHeight: CGFloat { 57 | return iPhoneX() ? 88.0 : 64.0 58 | } 59 | 60 | /// App`TabBar`的高度 61 | var kTabBarHeight: CGFloat { 62 | return iPhoneX() ? 83.0 : 49.0 63 | } 64 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Main/SwiftDemo-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | /// 2 | /// ### Use this file to import your target's public headers that you would like to expose to Swift. 3 | /// 4 | /// _______.____ __ ____ __ _______ .___________. 5 | /// / |\ \ / \ / / | | | ____|| | 6 | /// | (----` \ \/ \/ / | | | |__ `---| |----` 7 | /// \ \ \ / | | | __| | | 8 | /// .----) | \ /\ / | | | | | | 9 | /// |_______/ \__/ \__/ |__| |__| |__| 10 | /// 11 | /// 12 | /// ### 1. 用于把OC的类 暴露给 Swift 调用 13 | /// > 此类直接导入类头文件,或者库头文件,会对整个App Swift模块可见 14 | /// > 注意在项目的`Build Setting`里面搜索`Defines Module`项,设置为`YES` 15 | /// 16 | /// ### 2. Swift 类暴露给OC调用,会在项目自动生成一个隐藏文件`HWSwiftDemo-Swift.h`,在OC类中,直接`#import`此类即可 17 | /// 18 | /// **注意**只有继承`NSObject`等OC的root类,才能对OC的类公开和调用 19 | /// ```swift 20 | /// class Person: NSObject { 21 | /// @objc var name: String 22 | /// @objc var age: Int 23 | /// 24 | /// // 只有属性和方法加`@objc`才能在OC类里面调用和访问 25 | /// @objc init(name: String, age: Int) { 26 | /// self.name = name 27 | /// self.age = age 28 | /// } 29 | /// } 30 | /// ``` 31 | /// 32 | /// OC类中,对Swift类的一些常用宏: 33 | /// ```c 34 | /// @interface MyClass : NSObject 35 | /// - (void)test1 NS_SWIFT_NAME(myTest()); // 改变在swift中方法名 36 | /// - (void)test2 NS_SWIFT_UNAVAILABLE("请使用myTest"); 37 | /// @end 38 | /// ``` 39 | /// 40 | /// ### 3. 一些参考链接 41 | /// [混编讲解一](https://www.jianshu.com/p/3e32bacb8da2) 42 | /// [混编讲解二](https://www.jianshu.com/p/89fb0f2a2694) 43 | /// 44 | 45 | 46 | /// ***********************系统库*********************** 47 | #import 48 | #import 49 | 50 | 51 | 52 | /// ***********************第三方*********************** 53 | #import 54 | #import 55 | 56 | 57 | /// ***********************自定义*********************** 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Code/Society/Model/SocietyListModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocietyListModel.swift 3 | // SwiftDemo 4 | // 5 | // Created by HouWan on 2020/5/18. 6 | // Copyright © 2020 HouWan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | class SocietyListModel: NSObject { 13 | /// 用户头像 14 | var image: String? 15 | /// 发帖内容 16 | var content: String? 17 | /// 昵称 18 | var nickName: String? 19 | /// 门店 20 | var storeName: String? 21 | /// 帖子ID 22 | var msginfoId: String! 23 | /// 帖子图片 24 | var pic: [SocietyPicModel]? 25 | 26 | 27 | required override init() {} 28 | } 29 | 30 | 31 | enum SocietyPicType { 32 | case normal /// 普通图 33 | case gif /// GIF 34 | case rectangle /// 长图 35 | } 36 | 37 | /// 图片模型 38 | class SocietyPicModel: NSString { 39 | var picUrl: String! 40 | var picWidth: String? 41 | var picHeight: String? 42 | 43 | var PIC_URL: URL? { 44 | get { URL(string: picUrl) } 45 | } 46 | 47 | /// private for pic type 48 | private var _picType: SocietyPicType? = nil 49 | 50 | /// 获取图片的类型 51 | /// - Returns: 图片的类型`SocietyPicType` 52 | func picType() -> SocietyPicType { 53 | guard _picType != nil else { 54 | return _picType! 55 | } 56 | 57 | var picW = (picWidth as NSString?)?.doubleValue ?? 0 58 | var picH = (picHeight as NSString?)?.doubleValue ?? 0 59 | 60 | if picW.isNaN { picW = 0} 61 | if picH.isNaN { picH = 0} 62 | 63 | guard picH > 0 && picW > 0 else { 64 | _picType = .normal 65 | return _picType! 66 | } 67 | 68 | // 1.先判断是否图 69 | if picH >= picW * 2.5 { 70 | _picType = .rectangle 71 | } else { 72 | _picType = picUrl.lowercased().hasSuffix("gif") ? .gif : .normal 73 | } 74 | 75 | return _picType! 76 | } 77 | 78 | 79 | } 80 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Tools/Extends/UIView-Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView-Extension.swift 3 | // SwiftDemo 4 | // 5 | // Created by HouWan on 2020/5/9. 6 | // Copyright © 2020 HouWan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // MARK: - Properties 12 | extension UIView { 13 | 14 | /// x origin of view. 15 | var x: CGFloat { 16 | get { 17 | return frame.origin.x 18 | } 19 | set { 20 | frame.origin.x = newValue 21 | } 22 | } 23 | 24 | /// y origin of view. 25 | var y: CGFloat { 26 | get { 27 | return frame.origin.y 28 | } 29 | set { 30 | frame.origin.y = newValue 31 | } 32 | } 33 | 34 | /// Width of view. 35 | var width: CGFloat { 36 | get { 37 | return frame.size.width 38 | } 39 | set { 40 | frame.size.width = newValue 41 | } 42 | } 43 | 44 | /// Height of view. 45 | var height: CGFloat { 46 | get { 47 | return frame.size.height 48 | } 49 | set { 50 | frame.size.height = newValue 51 | } 52 | } 53 | 54 | /// Size of view. 55 | var size: CGSize { 56 | get { 57 | return frame.size 58 | } 59 | set { 60 | frame.size = newValue 61 | } 62 | } 63 | 64 | /// Origin of view. 65 | var origin: CGPoint { 66 | get { 67 | return frame.origin 68 | } 69 | set { 70 | frame.origin = newValue 71 | } 72 | } 73 | 74 | /// CenterX of view. 75 | var centerX: CGFloat { 76 | get { 77 | return center.x 78 | } 79 | set { 80 | center.x = newValue 81 | } 82 | } 83 | 84 | /// CenterY of view. 85 | var centerY: CGFloat { 86 | get { 87 | return center.y 88 | } 89 | set { 90 | center.y = newValue 91 | } 92 | } 93 | 94 | /// Bottom of view. 95 | var bottom: CGFloat { 96 | return frame.maxY 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | 28 | ## App packaging 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | # Package.resolved 43 | # *.xcodeproj 44 | # 45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 46 | # hence it is not needed unless you have added a package configuration file to your project 47 | # .swiftpm 48 | 49 | .build/ 50 | 51 | # CocoaPods 52 | Pods/ 53 | !Podfile 54 | !Podfile.lock 55 | 56 | # Carthage 57 | # 58 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 59 | # Carthage/Checkouts 60 | 61 | Carthage/Build/ 62 | 63 | # Accio dependency management 64 | Dependencies/ 65 | .accio/ 66 | 67 | # fastlane 68 | # 69 | # It is recommended to not store the screenshots in the git repo. 70 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 71 | # For more information about the recommended setup visit: 72 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 73 | 74 | fastlane/report.xml 75 | fastlane/Preview.html 76 | fastlane/screenshots/**/*.png 77 | fastlane/test_output 78 | 79 | # Code Injection 80 | # 81 | # After new code Injection tools there's a generated folder /iOSInjectionProject 82 | # https://github.com/johnno1962/injectionforxcode 83 | 84 | iOSInjectionProject/ 85 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Code/Home/TestViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TestViewController.m 3 | // SwiftDemo 4 | // 5 | // Created by HouWan on 2020/8/20. 6 | // Copyright © 2020 HouWan. All rights reserved. 7 | // 8 | 9 | #import "TestViewController.h" 10 | #import "SwiftDemo-Swift.h" 11 | 12 | @implementation TestViewController 13 | 14 | - (void)viewDidLoad { 15 | [super viewDidLoad]; 16 | 17 | } 18 | 19 | /// 测试用例 1 20 | - (void)test_get_a { 21 | NSString *url = @"http://game.gtimg.cn/images/lol/act/img/js/heroList/hero_list.js"; 22 | NSDictionary *dict = @{@"v": @(33)}; 23 | 24 | [HWNetworkingOC GET:url info:@"LOL英雄列表" parameters:dict success:^(id response) { 25 | NSLog(@"get --> %@", response); 26 | } failed:^(HWNetworkingError *error) { 27 | NSLog(@"xxx -> %@", error.localizedDescription); 28 | }]; 29 | } 30 | 31 | /// 测试用例 2 32 | - (void)test_post_a { 33 | NSString *url = @"https://api.sunpig.cn/member/myDetailsNew"; 34 | NSDictionary *dict = @{@"userId": @"02363BC2523811E68BD95CB9018916241119"}; 35 | 36 | [HWNetworkingOC POST:url info:@"我的页面" parameters:dict success:^(id response) { 37 | NSLog(@"post --> %@", response); 38 | } failed:^(HWNetworkingError *error) { 39 | NSLog(@"xxx -> %@", error.localizedDescription); 40 | }]; 41 | } 42 | 43 | /// 测试用例 3 44 | - (void)test_error_a { 45 | NSString *url = @"https://api.sunpig.cn/member/myDetailsNew"; 46 | NSDictionary *dict = @{@"userId": @"123"}; 47 | 48 | [HWNetworkingOC POST:url info:@"我的页面" parameters:dict success:^(id response) { 49 | NSLog(@"post --> %@", response); 50 | } failed:^(HWNetworkingError *error) { 51 | NSLog(@"xxx -> %@", error.localizedDescription); 52 | }]; 53 | } 54 | 55 | /// 测试用例 3 56 | - (void)test_error_b { 57 | NSString *url = @"https://api.sunpig.cn/member/myDetailsw"; 58 | NSDictionary *dict = @{@"userId": @"123"}; 59 | 60 | [HWNetworkingOC POST:url info:@"我的页面" parameters:dict success:^(id response) { 61 | NSLog(@"post --> %@", response); 62 | } failed:^(HWNetworkingError *error) { 63 | NSLog(@"xxx -> %@", error.localizedDescription); 64 | }]; 65 | } 66 | 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Tools/Extends/UIColor-Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor-Extension.swift 3 | // SwiftDemo 4 | // 5 | // Created by HouWan on 2020/5/7. 6 | // Copyright © 2020 HouWan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // MARK: - Initializers 12 | extension UIColor { 13 | 14 | /// 快捷构造器-RGBA色值,RGB取值范围是[0...255], alpha取值范围是[0...1] 15 | /// - Author: HouWan 16 | /// - Parameters: 17 | /// - r: red 18 | /// - g: green 19 | /// - b: blue 20 | /// - a: alpha, default: 1.0 21 | convenience public init(r: CGFloat, g: CGFloat, b: CGFloat, a: CGFloat = 1.0) { 22 | self.init(red: r/255.0, green: g/255.0, blue:b/255.0, alpha:a) 23 | } 24 | 25 | /// Same as above! 26 | convenience public init(_ r: CGFloat, _ g: CGFloat, _ b: CGFloat, _ a: CGFloat = 1.0) { 27 | self.init(red: r/255.0, green: g/255.0, blue:b/255.0, alpha:a) 28 | } 29 | 30 | /// 使用十六进制颜色码生成`UIColor`对象, eg:`UIColor(0xFF2D3A)` 31 | /// - Author: HouWan 32 | /// - Parameters: 33 | /// - hexValue: 十六进制数值 34 | /// - alpha: alpha, default: 1.0, alpha取值范围是[0...1] 35 | convenience public init(_ hexValue: Int, alpha: Float = 1.0) { 36 | self.init(red: CGFloat((hexValue & 0xFF0000) >> 16) / 255.0, 37 | green: CGFloat((hexValue & 0x00FF00) >> 8) / 255.0, 38 | blue: CGFloat(hexValue & 0x0000FF) / 255.0, 39 | alpha: CGFloat(alpha)) 40 | } 41 | 42 | /// 使用十六进制颜色码生成`UIColor`对象, eg:`UIColor.hexColor(0xFF2D3A)` 43 | /// - Author: HouWan 44 | /// - Parameters: 45 | /// - hexValue: 十六进制数值 46 | /// - alpha: alpha, default: 1.0, alpha取值范围是[0...1] 47 | /// - Returns: 十六进制颜色 48 | class func hexColor(_ hexValue: Int, alpha: Float = 1.0) -> UIColor { 49 | return UIColor(hexValue, alpha: alpha) 50 | } 51 | 52 | } 53 | 54 | 55 | // MARK: - Properties 56 | extension UIColor { 57 | 58 | /// 返回一个随机得出来的RGB颜色, 透明度为1.0 59 | class var random: UIColor { 60 | let red = CGFloat(Int.random(in: 0...255)) 61 | let green = CGFloat(Int.random(in: 0...255)) 62 | let blue = CGFloat(Int.random(in: 0...255)) 63 | return UIColor.init(red, green, blue) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Main/Controller/DTabBarController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DTabBarController.swift 3 | // SwiftDemo 4 | // 5 | // Created by HouWan on 2020/5/7. 6 | // Copyright © 2020 HouWan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /// [Notification key] 双击`TabBar`通知key 12 | let NDoubleTapTabBarNotification = NSNotification.Name("DoubleTapTabBar") 13 | 14 | 15 | @objcMembers 16 | class DTabBarController: UITabBarController, DTabBarDelegate { 17 | 18 | override func viewDidLoad() { 19 | super.viewDidLoad() 20 | 21 | // KVC替换自己的`tabBar` 22 | let tabBar = DTabBar() 23 | tabBar.tabBarDelegate = self 24 | setValue(tabBar, forKeyPath: "tabBar") 25 | 26 | // 自定义了`TabBar`,所以下面的title和image参数是没啥用的,这里仅为了记录正常创建ChildVC的方法 27 | addChild("首页", "tabbar_home", "tabbar_homeH", HomeViewController.self) 28 | addChild("健身房", "tabbar_gym", "tabbar_gymH", GymViewController.self) 29 | addChild("光猪圈", "tabbar_coterie", "tabbar_coterieH", SocietyViewController.self) 30 | addChild("我的", "tabbar_me", "tabbar_meH", MeViewController.self) 31 | } 32 | 33 | 34 | /// 初始化并添加一个子控制器 35 | /// - Parameters: 36 | /// - title: 标题 37 | /// - image: 图标 38 | /// - selectedImage: 选中时的图标 39 | /// - type: 控制器 40 | func addChild(_ title: String, 41 | _ image: String, 42 | _ selectedImage: String, 43 | _ type: UIViewController.Type) { 44 | let vc = DNavigationController(rootViewController: type.init()) 45 | vc.title = title 46 | vc.tabBarItem.image = UIImage(named: image) 47 | vc.tabBarItem.selectedImage = UIImage(named: selectedImage) 48 | vc.tabBarItem.setTitleTextAttributes([.foregroundColor: UIColor.black], for: .selected) 49 | addChild(vc) 50 | } 51 | 52 | } 53 | 54 | 55 | // MARK: - DTabBarDelegate 56 | extension DTabBarController{ 57 | 58 | /// 单击某个item的代理回调 59 | /// - Parameters: 60 | /// - tabBar: DTabBar对象 61 | /// - index: 点击Item的索引 62 | @objc func singleTap(tabBar:DTabBar, index: Int) { 63 | selectedIndex = index 64 | } 65 | 66 | /// 双击某个item的代理回调 67 | /// - Parameters: 68 | /// - tabBar: DTabBar对象 69 | /// - index: 点击Item的索引 70 | @objc func doubleTap(tabBar:DTabBar, index: Int) { 71 | // 通知刷新数据,eg: 圈子,我的 72 | NotificationCenter.default.post(name: NDoubleTapTabBarNotification, object: nil) 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Library/Custom/HWNetworking/HWNetworkingOC.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HWNetworkingOC.swift 3 | // LianDuoDuo 4 | // 5 | // Created by HouWan on 2020/8/14. 6 | // Copyright © 2020 CSData. All rights reserved. 7 | // 8 | // swiftlint:disable all 9 | // 10 | 11 | import UIKit 12 | 13 | /// 封装OC调用网络请求 14 | @objc class HWNetworkingOC: NSObject { 15 | 16 | /// POST请求 17 | /// 18 | /// - Parameters: 19 | /// - url: 请求的URL,是全地址 20 | /// - info: 请求的描述说明,可以为nil,比如: 首页的请求 21 | /// - parameters: 请求参数,可能为nil 22 | /// - headers: `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default. 23 | /// - success: 请求成功的响应回调 24 | /// - failed: 请求失败的响应回调 25 | @objc static func POST(_ url: String, info: String?, parameters: [String: Any]?, headers: [String: String]?, success: @escaping HNSuccessClosure, failed: @escaping HNFailedClosure) { 26 | HN.POST(url: url, parameters: parameters, headers: headers).success(success).failed { error in 27 | failed(error) 28 | }.description = info 29 | } 30 | 31 | @objc static func POST(_ url: String, info: String?, parameters: [String: Any]?, success: @escaping HNSuccessClosure, failed: @escaping HNFailedClosure) { 32 | HN.POST(url: url, parameters: parameters, headers: nil).success(success).failed { error in 33 | failed(error) 34 | }.description = info 35 | } 36 | 37 | /// GET请求 38 | /// 39 | /// - Parameters: 40 | /// - url: 请求的URL,是全地址 41 | /// - info: 请求的描述说明,可以为nil,比如: 首页的请求 42 | /// - parameters: 请求参数,可能为nil 43 | /// - headers: `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default. 44 | /// - success: 请求成功的响应回调 45 | /// - failed: 请求失败的响应回调 46 | @objc static func GET(_ url: String, info: String?, parameters: [String: Any]?, headers: [String: String]?, success: @escaping HNSuccessClosure, failed: @escaping HNFailedClosure) { 47 | HN.GET(url: url, parameters: parameters, headers: headers).success(success).failed { error in 48 | failed(error) 49 | }.description = info 50 | } 51 | 52 | @objc static func GET(_ url: String, info: String?, parameters: [String: Any]?, success: @escaping HNSuccessClosure, failed: @escaping HNFailedClosure) { 53 | HN.GET(url: url, parameters: parameters, headers: nil).success(success).failed { error in 54 | failed(error) 55 | }.description = info 56 | } 57 | 58 | @objc static func GET(_ url: String, info: String?, success: @escaping HNSuccessClosure, failed: @escaping HNFailedClosure) { 59 | HN.GET(url: url, parameters: nil, headers: nil).success(success).failed { error in 60 | failed(error) 61 | }.description = info 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Library/Custom/HWNetworking/HWMultipartData.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HWMultipartData.swift 3 | // LianDuoDuo 4 | // 5 | // Created by HouWan on 2020/8/15. 6 | // Copyright © 2020 CSData. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// 常见数据类型的`MIME Type` 12 | public enum HWDataMimeType: String { 13 | case JPEG = "image/jpeg" 14 | case PNG = "image/png" 15 | case GIF = "image/gif" 16 | case HEIC = "image/heic" 17 | case HEIF = "image/heif" 18 | case WEBP = "image/webp" 19 | case TIF = "image/tif" 20 | case JSON = "application/json" 21 | } 22 | 23 | /// HWMultipartData for upload datas, eg: images/photos 24 | public class HWMultipartData { 25 | /// The data to be encoded and appended to the form data. 26 | let data: Data 27 | /// Name to associate with the `Data` in the `Content-Disposition` HTTP header. 28 | let name: String 29 | /// Filename to associate with the `Data` in the `Content-Disposition` HTTP header. 30 | let fileName: String 31 | /// The MIME type of the specified data. (For example, the MIME type for a JPEG image is image/jpeg.) For a list of valid MIME types 32 | /// see http://www.iana.org/assignments/media-types/. This parameter must not be `nil`. 33 | let mimeType: String 34 | 35 | /// Create HWMultipartDataModel 36 | /// - Parameters: 37 | /// - data: The data to be encoded and appended to the form data. 38 | /// - name: The name to be associated with the specified data. 39 | /// - fileName: The filename to be associated with the specified data. 40 | /// - mimeType: The MIME type of the specified data. eg: image/jpeg 41 | init(data: Data, name: String, fileName: String, mimeType: String) { 42 | self.data = data 43 | self.name = name 44 | self.fileName = fileName 45 | self.mimeType = mimeType 46 | } 47 | 48 | /// Create HWMultipartDataModel 49 | /// - Parameters: 50 | /// - data: The data to be encoded and appended to the form data. 51 | /// - name: The name to be associated with the specified data. 52 | /// - fileName: The filename to be associated with the specified data. 53 | /// - type: The MIME type of the specified data. eg: image/jpeg 54 | convenience init(data: Data, name: String, fileName: String, type: HWDataMimeType) { 55 | self.init(data: data, name: name, fileName: fileName, mimeType: type.rawValue) 56 | } 57 | 58 | // mimeType --> image/jpeg, image/png, image/gif, 59 | // see: https://www.cnblogs.com/fuqiang88/p/4618652.html 60 | 61 | // 中文说明一下,增加理解: 62 | // 当提交一张图片或一个文件的时候 name 可以随便设置,服务端直接能拿到,如果服务端需要根据name去取不同文件的时候 63 | // 则appendPartWithFileData 方法中的 name 需要根据form的中的name一一对应 64 | // 所以name的值,是需要跟后台服务端商量好的. 65 | } 66 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Code/Gym/GymViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GymViewController.swift 3 | // SwiftDemo 4 | // 5 | // Created by HouWan on 2020/5/7. 6 | // Copyright © 2020 HouWan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class GymViewController: DBaseVC, UITableViewDelegate, UITableViewDataSource { 12 | 13 | var tableView: UITableView! 14 | 15 | private let CELL_CRI = "CellReuseIdentifier" 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | createAndConfigUI() 20 | } 21 | 22 | func createAndConfigUI() { 23 | title = "健身房" 24 | 25 | let h = kScreenHeight - kNavigatioHeight - kTabBarHeight 26 | let r = CGRect(x: 0, y: kNavigatioHeight, width: kScreenWidth, height: h) 27 | 28 | tableView = UITableView(frame: r, style: .plain); 29 | tableView.backgroundColor = theme_tint_A_color 30 | // tableView.separatorStyle = .none 31 | tableView.register(UITableViewCell.self, forCellReuseIdentifier: CELL_CRI) 32 | tableView.delegate = self 33 | tableView.dataSource = self 34 | 35 | if #available(iOS 11.0, *) { 36 | tableView.contentInsetAdjustmentBehavior = .never 37 | } else { 38 | automaticallyAdjustsScrollViewInsets = false 39 | } 40 | view.addSubview(tableView) 41 | } 42 | } 43 | 44 | 45 | /// UITableViewDelegate 46 | extension GymViewController { 47 | func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { 48 | 49 | } 50 | 51 | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 52 | return 60 53 | } 54 | 55 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 56 | debugPrint(indexPath) 57 | } 58 | } 59 | 60 | /// UITableViewDataSource 61 | extension GymViewController { 62 | 63 | @available(iOS 2.0, *) 64 | // Default is 1 if not implemented 65 | func numberOfSections(in tableView: UITableView) -> Int { 66 | return 1 67 | } 68 | 69 | @available(iOS 2.0, *) 70 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 71 | return 10 72 | } 73 | 74 | @available(iOS 2.0, *) 75 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 76 | let c = tableView.dequeueReusableCell(withIdentifier: CELL_CRI, for: indexPath) 77 | 78 | c.selectionStyle = .none 79 | c.textLabel?.textColor = theme_text_A_color 80 | c.textLabel?.font = MediumFont(15) 81 | c.textLabel?.text = "精品私教课" 82 | 83 | return c 84 | } 85 | 86 | 87 | } 88 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Library/Custom/HWNetworking/HWAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HWAPI.swift 3 | // LianDuoDuo 4 | // 5 | // Created by HouWan on 2020/8/17. 6 | // Copyright © 2020 CSData. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Alamofire 11 | 12 | /// Type representing HTTP methods. 13 | public enum HWHTTPMethod { 14 | /// Common HTTP methods. 15 | case delete, get, patch, post, put 16 | } 17 | 18 | /// API interface protocol 19 | public protocol HWAPIProtocol { 20 | /// API URL address 21 | var url: String { get } 22 | /// API description information 23 | var description: String { get } 24 | /// API additional information, eg: Author | Note... 25 | var extra: String? { get } 26 | /// Type representing HTTP methods. 27 | var method: HWHTTPMethod { get } 28 | } 29 | 30 | /// Extension method 31 | public extension HWAPIProtocol { 32 | 33 | /// 根据`HWAPIProtocol`进行一个网络请求 34 | /// 35 | /// - Parameters: 36 | /// - parameters: `nil` by default. 37 | /// - headers: `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default. 38 | /// - success: Successful response 39 | /// - failed: Failed response 40 | /// 41 | func fetch(_ parameters: [String: Any]? = nil, headers: [String: String]? = nil, success: HNSuccessClosure?, failed: HNFailedClosure?) { 42 | let task = HN.fetch(self, parameters: parameters, headers: headers) 43 | if let s = success { 44 | task.success(s) 45 | } 46 | if let f = failed { 47 | task.failed(f) 48 | } 49 | } 50 | 51 | /// 根据`HWAPIProtocol`进行一个网络请求 52 | /// 53 | /// - Parameters: 54 | /// - parameters: `nil` by default. 55 | /// - headers: `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default. 56 | /// 57 | func fetch(_ parameters: [String: Any]? = nil, headers: [String: String]? = nil) -> HWNetworkRequest { 58 | HN.fetch(self, parameters: parameters, headers: headers) 59 | } 60 | } 61 | 62 | /// 为了`HWAPIProtocol`给`HWNetworking`扩展的网络请求方法 63 | public extension HWNetworking { 64 | /// Creates a request, for `HWAPIProtocol` 65 | /// 66 | /// - note: more see: `self.request(...)` 67 | @discardableResult 68 | func fetch(_ api: HWAPIProtocol, parameters: [String: Any]? = nil, headers: [String: String]? = nil) -> HWNetworkRequest { 69 | let method = methodWith(api.method) 70 | let task = request(url: api.url, method: method, parameters: parameters, headers: headers) 71 | task.description = api.description 72 | task.extra = api.extra 73 | return task 74 | } 75 | } 76 | 77 | /// Function to convert request method 78 | private func methodWith(_ m: HWHTTPMethod) -> Alamofire.HTTPMethod { 79 | // case delete, get, patch, post, put 80 | switch m { 81 | case .delete: return .delete 82 | case .get: return .get 83 | case .patch: return .patch 84 | case .post: return .post 85 | case .put: return .put 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Resources/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Code/Society/SocietyViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocietyViewController.swift 3 | // SwiftDemo 4 | // 5 | // Created by HouWan on 2020/5/7. 6 | // Copyright © 2020 HouWan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SocietyViewController: DBaseVC, UITableViewDelegate, UITableViewDataSource { 12 | 13 | var tableView: UITableView! 14 | var page: Int = 1 15 | 16 | 17 | lazy var dataArray: [CoachListModel] = { 18 | return [] 19 | }() 20 | 21 | 22 | let CELL_CRI = "CellReuseIdentifier" 23 | 24 | override func viewDidLoad() { 25 | super.viewDidLoad() 26 | title = "朋友圈" 27 | 28 | let h = kScreenHeight - kNavigatioHeight - kTabBarHeight 29 | let r = CGRect(x: 0, y: kNavigatioHeight, width: kScreenWidth, height: h) 30 | 31 | tableView = UITableView(frame: r, style: .plain); 32 | tableView.backgroundColor = theme_tint_A_color 33 | tableView.separatorStyle = .none 34 | tableView.register(SocietyListCell.self, forCellReuseIdentifier: CELL_CRI) 35 | tableView.delegate = self 36 | tableView.dataSource = self 37 | 38 | if #available(iOS 11.0, *) { 39 | tableView.contentInsetAdjustmentBehavior = .never 40 | } else { 41 | automaticallyAdjustsScrollViewInsets = false 42 | } 43 | view.addSubview(tableView) 44 | } 45 | } 46 | 47 | /// UITableViewDelegate 48 | extension SocietyViewController { 49 | @available(iOS 2.0, *) 50 | func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { 51 | 52 | } 53 | 54 | @available(iOS 6.0, *) 55 | func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) { 56 | 57 | } 58 | 59 | @available(iOS 6.0, *) 60 | func tableView(_ tableView: UITableView, willDisplayFooterView view: UIView, forSection section: Int) { 61 | 62 | } 63 | 64 | @available(iOS 2.0, *) 65 | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 66 | return 60 67 | } 68 | 69 | @available(iOS 2.0, *) 70 | func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { 71 | return 0 72 | } 73 | 74 | @available(iOS 2.0, *) 75 | func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { 76 | return 0 77 | } 78 | 79 | @available(iOS 2.0, *) 80 | func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { 81 | return nil 82 | } 83 | 84 | @available(iOS 2.0, *) 85 | func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { 86 | return nil 87 | } 88 | 89 | @available(iOS 2.0, *) 90 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 91 | print("xxx") 92 | } 93 | } 94 | 95 | /// UITableViewDataSource 96 | extension SocietyViewController { 97 | 98 | @available(iOS 2.0, *) 99 | // Default is 1 if not implemented 100 | func numberOfSections(in tableView: UITableView) -> Int { 101 | return 1 102 | } 103 | 104 | @available(iOS 2.0, *) 105 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 106 | return dataArray.count 107 | } 108 | 109 | @available(iOS 2.0, *) 110 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 111 | let c = tableView.dequeueReusableCell(withIdentifier: CELL_CRI, for: indexPath) as! SocietyListCell 112 | c.show(model: dataArray[indexPath.row]) 113 | return c 114 | } 115 | } 116 | 117 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Code/Home/HomeViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HomeViewController.swift 3 | // SwiftDemo 4 | // 5 | // Created by HouWan on 2020/5/7. 6 | // Copyright © 2020 HouWan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class HomeViewController: DBaseVC { 12 | 13 | var tableView: UITableView! 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | title = "首页" 19 | 20 | let a = UILabel(font: SemiboldFont(16), color: UIColor.blue) 21 | a.numberOfLines = 0; 22 | a.text = "用法直接看`HomeViewController`类即可\n\nOC的调用方式,和`HomeViewController`在同一个目录下" 23 | a.frame = CGRect(x: 10, y: 100, width: view.width - 20, height: 165) 24 | view.addSubview(a) 25 | 26 | 27 | // 开始网络状态监测 28 | // 由于可能多个地方需要知道网络状态,所以添加通知`kNetworkStatusNotification`即可 29 | // 在通知回调方法里面,判断`HN.networkStatus`即可 30 | HN.startMonitoring() 31 | } 32 | 33 | /// **测试用例** post 34 | func test_post_a() { 35 | let p: [String: Any] = ["city": "北京市", "locatex": 0, "locatey": 0, "num": 2] 36 | HN.POST(url: API.Home.storeList.url, parameters: p).success { response in 37 | print("response -->", response) 38 | }.failed { error in 39 | print("error -->", error) 40 | } 41 | } 42 | 43 | /// **测试用例** post 44 | func test_post_b() { 45 | let p: [String: Any] = ["city": "北京市", "locatex": 0, "locatey": 0, "num": 2] 46 | HN.fetch(API.Home.storeList, parameters: p).success { response in 47 | print("response -->", response) 48 | }.failed { error in 49 | print("error -->", error) 50 | } 51 | } 52 | 53 | /// **测试用例** post 54 | func test_post_c() { 55 | let p: [String: Any] = ["city": "北京市", "locatex": 0, "locatey": 0, "num": 2] 56 | API.Home.storeList.fetch(p, success: {response in 57 | print("response -->", response) 58 | }, failed: {error in 59 | print("error -->", error) 60 | }) 61 | } 62 | 63 | /// **测试用例** get 64 | func test_get_a() { 65 | let p = ["userId": "02363BC2523811E68BD95CB9018916241119"] 66 | 67 | API.Me.meIndex.fetch(p, success: {response in 68 | print("response -->", response) 69 | }, failed: {error in 70 | print("error -->", error) 71 | }) 72 | } 73 | 74 | /// **测试用例** get 75 | func test_get_b() { 76 | let p = ["userId": "02363BC2523811E68BD95CB9018916241119"] 77 | 78 | HN.fetch(API.Me.meIndex, parameters: p).success { response in 79 | print("response -->", response) 80 | }.failed { error in 81 | print("error -->", error) 82 | } 83 | } 84 | 85 | /// **测试用例** get 86 | func test_get_c() { 87 | let p = ["userId": "02363BC2523811E68BD95CB9018916241119"] 88 | 89 | API.Me.meIndex.fetch(p).success { response in 90 | print("response -->", response) 91 | }.failed { error in 92 | print("error -->", error) 93 | } 94 | } 95 | 96 | /// **测试用例** get请求 97 | func get() { 98 | let url = "https://demo.xx.com/get/" 99 | let p: [String : Any] = ["name": "demo", "age": 18] 100 | 101 | HN.GET(url: url, parameters: p).success { (response) in 102 | // TODO... 103 | }.failed { (error) in 104 | // TODO... 105 | } 106 | } 107 | 108 | /// **测试用例** post请求 109 | func post() { 110 | let url = "https://demo.xx.com/get/" 111 | let p: [String : Any] = ["name": "demo", "age": 18] 112 | 113 | HN.POST(url: url, parameters: p).success { (response) in 114 | // TODO... 115 | }.failed { (error) in 116 | // TODO... 117 | } 118 | } 119 | 120 | /// **测试用例** 上传图片 121 | func photo() { 122 | let url = "https://demo.xx.com/get/" 123 | let p: [String : String] = ["name": "demo", "age": "18"] 124 | 125 | // 假设这里有2个照片,转为data,一般是选取相册里面的,可能还要压缩 126 | let d1_png = (UIImage(named: "xxxx.png")?.pngData())! 127 | let d2_jpg = (UIImage(named: "xxxx.jpg")?.jpegData(compressionQuality: 1))! 128 | 129 | // 图片的`MIME Type`可以使用`SDWebImage`获得 130 | let datas = [HWMultipartData(data: d1_png, name: "headurl", fileName: "1.png", 131 | mimeType: HWDataMimeType.PNG.rawValue), 132 | HWMultipartData(data: d2_jpg, name: "headurl", fileName: "2.jpg", 133 | mimeType: HWDataMimeType.JPEG.rawValue)] 134 | 135 | HN.POST(url: url, parameters: p, datas: datas).progress { (progress) in 136 | debugPrint("progress: \(progress.fractionCompleted)") 137 | }.success { (response) in 138 | debugPrint("success: \(response)") 139 | }.failed { (error) in 140 | debugPrint("failed: \(error)") 141 | } 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Main/View/DTabBar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DTabBar.swift 3 | // SwiftDemo 4 | // 5 | // Created by HouWan on 2020/5/7. 6 | // Copyright © 2020 HouWan. All rights reserved. 7 | // 8 | // https://draveness.me/swift-zhong-init-de-shi-yong/ 9 | // https://www.jianshu.com/p/fb1a91600468 10 | // 11 | // 12 | 13 | 14 | import UIKit 15 | 16 | 17 | // MARK: - 点击`DTabBar`事件代理回调 18 | @objc protocol DTabBarDelegate: NSObjectProtocol { 19 | 20 | /// 单击某个item的代理回调 21 | /// - Parameters: 22 | /// - tabBar: DTabBar对象 23 | /// - index: 点击Item的索引 24 | @objc func singleTap(tabBar:DTabBar, index: Int) -> Void 25 | 26 | /// 双击某个item的代理回调 27 | /// - Parameters: 28 | /// - tabBar: DTabBar对象 29 | /// - index: 点击Item的索引 30 | @objc optional func doubleTap(tabBar:DTabBar, index: Int) -> Void 31 | } 32 | 33 | 34 | 35 | // MARK: - 自定义`UITabBar` 36 | class DTabBar: UITabBar { 37 | 38 | /// 当前选中的Item 39 | fileprivate var currentItem: DTabBar_Item? 40 | /// 代理 41 | weak var tabBarDelegate: DTabBarDelegate? 42 | 43 | 44 | ///============================================================================= 45 | /// - Note: Initialization 46 | ///============================================================================= 47 | 48 | override init(frame: CGRect) { 49 | super.init(frame: frame) 50 | createAndConfigUI() 51 | } 52 | 53 | required init?(coder: NSCoder) { 54 | super.init(coder: coder) 55 | createAndConfigUI() 56 | } 57 | 58 | func createAndConfigUI() { 59 | isTranslucent = false 60 | backgroundColor = theme_tint_A_color 61 | 62 | let list = [DTabBarItemModel(t: "首页", i: "tabbar_home", s: "tabbar_homeH"), 63 | DTabBarItemModel(t: "健身房", i: "tabbar_gym", s: "tabbar_gymH"), 64 | DTabBarItemModel(t: "光猪圈", i: "tabbar_coterie", s: "tabbar_coterieH"), 65 | DTabBarItemModel(t: "我的", i: "tabbar_me", s: "tabbar_meH")] 66 | 67 | let w: CGFloat = CGFloat(ceilf(Float(CGFloat(kScreenWidth / 4.0)))) 68 | 69 | for (index, data) in list.enumerated() { 70 | let item = DTabBar_Item(model: data) 71 | item.frame = CGRect(x: CGFloat(index) * w, y: 0.0, width: w, height: kTabBarHeight) 72 | addSubview(item) 73 | 74 | item.index = index; 75 | item.selected = index == 0; 76 | 77 | if index == 0 { currentItem = item } 78 | 79 | let singleTap = UITapGestureRecognizer(target: self, action: #selector(singleTap(tap:))) 80 | singleTap.numberOfTouchesRequired = 1 81 | singleTap.numberOfTapsRequired = 1 82 | item.addGestureRecognizer(singleTap) 83 | 84 | let doubleTap = UITapGestureRecognizer(target: self, action: #selector(doubleTap(tap:))) 85 | doubleTap.numberOfTouchesRequired = 1 86 | doubleTap.numberOfTapsRequired = 2 87 | item.addGestureRecognizer(doubleTap) 88 | } 89 | } 90 | } 91 | 92 | // MARK: - TouchAction 93 | extension DTabBar { 94 | 95 | /// 点击 96 | @objc func singleTap(tap: UITapGestureRecognizer) { 97 | let item = tap.view as! DTabBar_Item 98 | guard item != currentItem else { return } 99 | 100 | currentItem?.selected = false 101 | item.selected = true 102 | currentItem = item 103 | 104 | animation(item: item) 105 | 106 | guard let d = tabBarDelegate else { return } 107 | 108 | if d.responds(to: #selector(d.singleTap(tabBar:index:))) { 109 | d.singleTap(tabBar: self, index: item.index!) 110 | } 111 | } 112 | 113 | /// 双击 114 | @objc func doubleTap(tap: UITapGestureRecognizer) { 115 | 116 | let item = tap.view as! DTabBar_Item 117 | 118 | // 如果没有正在显示,按单击处理 119 | guard currentItem == item else { 120 | singleTap(tap: tap) 121 | return 122 | } 123 | 124 | guard let d = tabBarDelegate else { return } 125 | 126 | if d.responds(to: #selector(d.doubleTap(tabBar:index:))) { 127 | d.doubleTap?(tabBar: self, index: item.index!) 128 | } 129 | } 130 | 131 | /// 动画一下 132 | fileprivate func animation(item: DTabBar_Item) { 133 | let pulse = CABasicAnimation(keyPath: "transform.scale") 134 | pulse.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut) 135 | pulse.duration = 0.2 136 | pulse.autoreverses = true 137 | pulse.fromValue = 0.9 138 | pulse.toValue = 1.1 139 | item.iconView.layer.add(pulse, forKey: nil) 140 | } 141 | } 142 | 143 | 144 | // MARK: - Override 145 | extension DTabBar { 146 | // -------------------彻底移除系统items------------------- 147 | override var items: [UITabBarItem]? { 148 | get { return [] } 149 | set {} 150 | } 151 | 152 | override func setItems(_ items: [UITabBarItem]?, animated: Bool) { 153 | } 154 | // ---------------------------------------------------- 155 | } 156 | 157 | 158 | // MARK: - 自定义`UITabBar`的按钮 159 | fileprivate class DTabBar_Item: UIView { 160 | 161 | var model: DTabBarItemModel? 162 | var index: Int? 163 | 164 | /// change UI style 165 | var selected: Bool = false { 166 | didSet { 167 | if selected { 168 | iconView.image = UIImage(named: model!.selectedImage) 169 | titleView.textColor = theme_text_A_color 170 | } else { 171 | iconView.image = UIImage(named: model!.image) 172 | titleView.textColor = theme_text_B_color 173 | } 174 | } 175 | } 176 | 177 | lazy var iconView: UIImageView = { 178 | let iconView = UIImageView() 179 | iconView.contentMode = .bottom 180 | return iconView 181 | }() 182 | 183 | lazy var titleView: UILabel = { 184 | let titleView = UILabel(font: UIFont.systemFont(ofSize: 10), color: theme_text_A_color, alignment: .center) 185 | return titleView 186 | }() 187 | 188 | /// 设置Item显示所需数据 189 | /// - Parameters: 190 | /// - model: 数据 191 | func configData(model: DTabBarItemModel) { 192 | titleView.text = model.title 193 | iconView.image = UIImage(named: model.image) 194 | 195 | self.model = model 196 | } 197 | 198 | ///============================================================================= 199 | /// - Note: Initialization 200 | ///============================================================================= 201 | override init(frame: CGRect) { 202 | super.init(frame: frame) 203 | createUI() 204 | } 205 | 206 | required init?(coder: NSCoder) { 207 | super.init(coder: coder) 208 | createUI() 209 | } 210 | 211 | convenience init(model: DTabBarItemModel) { 212 | self.init(frame: .zero) 213 | configData(model: model) 214 | } 215 | 216 | func createUI() { 217 | backgroundColor = theme_tint_A_color 218 | addSubview(iconView) 219 | addSubview(titleView) 220 | } 221 | 222 | override func layoutSubviews() { 223 | super.layoutSubviews() 224 | iconView.frame = CGRect(x: 0, y: 0, width: width, height: 28) 225 | let y = iconView.bottom + 8 226 | titleView.frame = CGRect(x: 0, y: y, width: width, height: 12) 227 | } 228 | } 229 | 230 | 231 | /// 一个·TabBarItem·展示所需的全部数据 232 | fileprivate struct DTabBarItemModel { 233 | var title: String 234 | var image: String 235 | var selectedImage: String 236 | 237 | /// Initialization 238 | /// - Parameters: 239 | /// - t: title 240 | /// - i: image name 241 | /// - s: selectedImage name 242 | init(t: String, i: String, s: String) { 243 | title = t 244 | image = i 245 | selectedImage = s 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 一.前言 2 | 对于iOS开发者,应该没有不知道`AFNetworking`的!它是一个用OC语言写的网络库,对于`AFNetworking`有很多著名的二次封装,比如猿题库团队的开源库`YTKNetwork`,它将`AFNetworking`封装成抽象父类,然后根据每个不同的网络请求,都编写不同的子类,子类继承父类,来实现请求业务(OOP思想设计)。 3 | 4 | 对于Swift开发,优雅的网络开发框架`Alamofire`当是不二选择,`Alamofire`是建立在`NSURLSession`上的封装,可以直接使用`Alamofire`进行网络请求,但是我们项目中往往需要一些“项目化”设置,所以习惯二次封装。在Swift开源社区,对`Alamofire`二次封装最有名的当属`Moya`,它在底层将`Alamofire`进行封装,对外提供更简洁的接口供开发者调用(POP思想设计). 5 | 6 | > `Alamofire`地址: 7 | > `Moya`地址: 8 | 9 | 不过似乎在大型项目,比如使用`Moya+RxSwift+MVVM`才能发挥`Moya`的威力,所以对中小项目,大都会自己简单对`Alamofire`封装下使用,网上搜索一下,封装之后的使用方法几乎都是下面这种方式: 10 | 11 | ```swift 12 | NetworkTools.request(url: "api", parameters:p, success: { (response) in 13 | // TODO... 14 | }) { (error) in 15 | // TODO... 16 | } 17 | ``` 18 | 19 | 这种应该是受OC的影响,方法里面跟着2个`Block`回调的思路。但在Swift里面就是两个逃逸尾随闭包`@escaping closure`,虽然语法没问题,但是我感觉怪怪的,特别是闭包里面代码一多起来,`{()}{()}`大括号看的晕晕的。 20 | 21 | 我受`PromiseKit`和`JQuery`启发,进行了`点`语法封装,使用方法如下: 22 | 23 | > `PromiseKit`是`iOS/MacOS`中一个用来处理异步编程的框架。可以直接配合`Alamofire`或者`AFNetworking`进行处理,功能很强大! 24 | > GitHub: 25 | 26 | ## 二.使用方法A 27 | 28 | ```swift 29 | // 进行一个请求,不管失败情况 30 | HN.POST(url: url, parameters: p, datas: datas).success { (response) in 31 | debugPrint("success: \(response)") 32 | } 33 | 34 | // 进行一个请求,处理成功和失败 35 | HN.GET(url: url, parameters: p).success { (response) in 36 | debugPrint("success: \(response)") 37 | }.failed { (error) in 38 | debugPrint("failed: \(error)") 39 | } 40 | 41 | // 上传图片 42 | HN.POST(url: url, parameters: p, datas: datas).progress { (progress) in 43 | debugPrint("progress: \(progress.fractionCompleted)") 44 | }.success { (response) in 45 | debugPrint("success: \(response)") 46 | }.failed { (error) in 47 | debugPrint("failed: \(error)") 48 | } 49 | ``` 50 | 51 | 正如上面代码所示,成功和失败都是使用`点`语法进行回调,清晰明了,甚至你可以不管成功和失败,只发送一个请求: 52 | ```swift 53 | HN.GET(url: "api") 54 | ``` 55 | 56 | ---- 57 | 58 | ## 三.使用方法B 59 | 60 | 3.1 结合`HWAPIProtocol`使用,这里新建一个`struct`去实现`HWAPIProtocol`: 61 | ```swift 62 | /// 实现协议,每个接口,都是一个`APIItem` 63 | struct APIItem: HWAPIProtocol { 64 | /// 全路径URL = 域名 + path 65 | private(set) var url: String 66 | /// 接口概述 67 | let description: String 68 | /// 额外信息 69 | let extra: String? 70 | /// HTTPMethod, eg: POST 71 | var method: HWHTTPMethod 72 | 73 | /// 创建一个接口对象,使用PATH方式 74 | /// 75 | /// - Parameters: 76 | /// - path: URL的路径部分 77 | /// - d: 接口概述 78 | /// - e: 额外信息 79 | /// - m: eg: POST 80 | init(_ path: String, d: String, e: String? = nil, m: HWHTTPMethod = .post) { 81 | url = API.DOMAIN + path 82 | description = d 83 | extra = e 84 | method = m 85 | } 86 | 87 | /// 创建一个接口对象,使用PATH方式 88 | /// 89 | /// - Parameters: 90 | /// - path: URL的路径部分 91 | /// - m: eg: POST 92 | init(_ path: String, m: HWHTTPMethod = .post) { 93 | url = API.DOMAIN + path 94 | description = path 95 | extra = nil 96 | method = m 97 | } 98 | 99 | /// 创建一个接口对象,使用URL全路径 100 | /// 101 | /// - Parameters: 102 | /// - path: URL的路径部分 103 | /// - d: 接口概述 104 | /// - e: 额外信息 105 | /// - m: eg: POST 106 | init(url: String, d: String, e: String? = nil, m: HWHTTPMethod = .post) { 107 | self.url = url 108 | description = d 109 | extra = e 110 | method = m 111 | } 112 | } 113 | ``` 114 | 115 | 3.2. 项目里面,写API的文件就可以设计为(模块化): 116 | ```swift 117 | /// App的接口 118 | struct API { 119 | static var DOMAIN = "https://www.baidu.com/" 120 | 121 | // MARK: Home模块 122 | struct Home { 123 | static let homeIndex = APIItem("homeIndex", d: "首页数据") 124 | static let storeList = APIItem("homeIndex", d: "首页门店列表", m: .get) 125 | } 126 | 127 | // MARK: 圈子模块 128 | struct Social { 129 | static let socialIndex = APIItem("socialList", d: "圈子首页列表") 130 | } 131 | } 132 | ``` 133 | 134 | 3.3 网络请求方式: 135 | ```swift 136 | // 1.不带参数 137 | HN.fetch(API.Home.homeIndex).success { response in 138 | print(response) 139 | } 140 | 141 | // 2.加上参数 142 | let p: [String: Any] = ["name": "ZhangSan", "age": 22] 143 | HN.fetch(API.Home.homeIndex, parameters: p).success { response in 144 | print(response) 145 | } 146 | 147 | // 3.加上Header 和失败情况 148 | let h = ["Referrer Policy": "no-referrer-when-downgrade"] 149 | HN.fetch(API.Home.homeIndex, headers: h).success { response in 150 | print(response) 151 | }.failed { error in 152 | print(error) 153 | } 154 | ``` 155 | 156 | > 可能有人疑问,为什么接口要加一个`description`,这里解释一下: 157 | > 1.在API文件里,能直接明白这接口是做什么的 158 | > 2.在我项目里,有一个debug隐藏模块,可以看到所有的API请求情况,可以看到这个`description` 159 | > 3.在debug模块里,不仅后台Java同事能通过`description`定位接口,测试同事也方便找接口 160 | 161 | ---- 162 | ## 四.使用方法C 163 | 由于已经为`HWAPIProtocol`扩展了已实现`fetch()`方法,所以上面的请求可以简化为更高阶的方式: 164 | ```swift 165 | // 1.不带参数 166 | API.Me.meIndex.fetch().success { response in 167 | print("response -->", response) 168 | }.failed { error in 169 | print("error -->", error) 170 | } 171 | 172 | API.Home.homeIndex.fetch(success: {response in 173 | print(response) 174 | }, failed: {error in 175 | print(error) 176 | }) 177 | 178 | // 2.加上参数 179 | let p: [String: Any] = ["name": "ZhangSan", "age": 22] 180 | API.Home.homeIndex.fetch(p, success: { response in 181 | print(response) 182 | }) { error in 183 | print(error) 184 | } 185 | 186 | // 3.加上Header 和失败情况 187 | let h = ["Referrer Policy": "no-referrer-when-downgrade"] 188 | API.Home.homeIndex.fetch(p, headers: h, success: { response in 189 | print(response) 190 | }) { error in 191 | print(error) 192 | } 193 | ``` 194 | ---- 195 | 196 | ## 五.OC使用方法 197 | OC的请求如下,具体可以看Demo,这里简单列举一个实例: 198 | ```c 199 | NSString *url = @"http://game.gtimg.cn/images/lol/act/img/js/heroList/hero_list.js"; 200 | NSDictionary *dict = @{@"v": @(33)}; 201 | 202 | [HWNetworkingOC GET:url info:@"LOL英雄列表" parameters:dict success:^(id response) { 203 | NSLog(@"%@", response); 204 | } failed:^(NSString *error) { 205 | NSLog(@"%@", error); 206 | }]; 207 | ``` 208 | ---- 209 | 210 | ## 六.思路? 211 | 设计思路其实很简单,首先是一个单例,用于持有`Alamofire.Session`和每个请求对象,顺便定义几个回调 212 | ```swift 213 | /// Closure type executed when the request is successful 214 | public typealias HNSuccessClosure = (_ JSON: Any) -> Void 215 | /// Closure type executed when the request is failed 216 | public typealias HNFailedClosure = (_ error: Any) -> Void 217 | /// Closure type executed when monitoring the upload or download progress of a request. 218 | public typealias HNProgressHandler = (Progress) -> Void 219 | 220 | public class HWNetworking { 221 | /// For singleton pattern 222 | public static let shared = HWNetworking() 223 | /// TaskQueue Array for (`Alamofire.Request` & callback) 224 | private var taskQueue = [HWNetworkRequest]() 225 | /// `Session` creates and manages Alamofire's `Request` types during their lifetimes. 226 | var sessionManager: Alamofire.Session! 227 | } 228 | ``` 229 | 230 | 把每个请求封装成对象,调用对象的`success(...)`方法和`failed(...)`等,获得这个请求的成功和失败回调,回调之后,销毁对象即可. 231 | ```swift 232 | public class HWNetworkRequest: Equatable { 233 | /// Alamofire.DataRequest 234 | var request: DataRequest? 235 | 236 | /// request response callback 237 | private var successHandler: HNSuccessClosure? 238 | /// request failed callback 239 | private var failedHandler: HNFailedClosure? 240 | /// `ProgressHandler` provided for upload/download progress callbacks. 241 | private var progressHandler: HNProgressHandler? 242 | 243 | // MARK: - Handler 244 | 245 | /// Handle request response 246 | func handleResponse(response: AFDataResponse) { 247 | switch response.result { 248 | case .failure(let error): 249 | if let closure = failedHandler { 250 | closure(error.localizedDescription) 251 | } 252 | 253 | case .success(let JSON): 254 | if let closure = successHandler { 255 | closure(JSON) 256 | } 257 | } 258 | clearReference() 259 | } 260 | 261 | /// Processing request progress (Only when uploading files) 262 | func handleProgress(progress: Foundation.Progress) { 263 | if let closure = progressHandler { 264 | closure(progress) 265 | } 266 | } 267 | 268 | // MARK: - Callback 269 | 270 | /// Adds a handler to be called once the request has finished. 271 | public func success(_ closure: @escaping HNSuccessClosure) -> Self { 272 | successHandler = closure 273 | return self 274 | } 275 | 276 | /// Adds a handler to be called once the request has finished. 277 | @discardableResult 278 | public func failed(_ closure: @escaping HNFailedClosure) -> Self { 279 | failedHandler = closure 280 | return self 281 | } 282 | } 283 | ``` 284 | 285 | 核心的请求方法如下: 286 | ```swift 287 | extension HWNetworking { 288 | public func request(url: String, 289 | method: HTTPMethod = .get, 290 | parameters: [String: Any]?, 291 | headers: [String: String]? = nil, 292 | encoding: ParameterEncoding = URLEncoding.default) -> HWNetworkRequest { 293 | let task = HWNetworkRequest() 294 | 295 | var h: HTTPHeaders? = nil 296 | if let tempHeaders = headers { 297 | h = HTTPHeaders(tempHeaders) 298 | } 299 | 300 | task.request = sessionManager.request(url, 301 | method: method, 302 | parameters: parameters, 303 | encoding: encoding, 304 | headers: h).validate().responseJSON { [weak self] response in 305 | task.handleResponse(response: response) 306 | 307 | if let index = self?.taskQueue.firstIndex(of: task) { 308 | self?.taskQueue.remove(at: index) 309 | } 310 | } 311 | taskQueue.append(task) 312 | return task 313 | } 314 | } 315 | ``` 316 | 317 | 再封装几个常用的POST和Get快捷方法: 318 | ```swift 319 | /// Shortcut method for `HWNetworking` 320 | extension HWNetworking { 321 | @discardableResult 322 | public func POST(url: String, parameters: [String: Any]? = nil, headers: [String: String]? = nil) -> HWNetworkRequest { 323 | request(url: url, method: .post, parameters: parameters, headers: nil) 324 | } 325 | 326 | /// Creates a GET request 327 | @discardableResult 328 | public func GET(url: String, parameters: [String: Any]? = nil, headers: [String: String]? = nil) -> HWNetworkRequest { 329 | request(url: url, method: .get, parameters: parameters, headers: nil) 330 | } 331 | } 332 | ``` 333 | 334 | 大致的思路就如上面贴出的关键代码,限于篇幅,这里不贴完整的代码了,可以直接去Github上`clone`下来看看,实现的大致功能如下: 335 | - [x] 常规的POST/GET 336 | - [x] 网络状态监听和通知 337 | - [x] 上传图片的封装(单张或者多张) 338 | - [ ] 下载文件(没有做,我这项目里没有这样的需求,不过方法留着了,自行扩展即可) 339 | 340 | 将来要做的功能: 341 | - [ ] 支持`closure`和`delegate`两种模式的回调方式 342 | - [ ] 支持网络请求`URL`的`filter`,可以统一为网络请求加上一些参数,或者拦截请求结果 343 | - [ ] 统一的`Header`设置 344 | 345 | 346 | 也欢迎大家把好的想法留言或者`git Issues`,因为我会在项目里使用这个类,所以后面如果有新的想法和功能,我都会更新维护的。 347 | 348 | **Github地址**,[GitHub点我](https://github.com/HouWan/HWNetworking)或者复制下面链接: 349 | 350 | 351 | > 从github上clone下以后,cd到目录`SwiftDemo`,执行`pod install`命令即可运行Demo 352 | ---- 353 | 354 | 关于`尾随闭包`,可能有同学说,那系统很多API这么使用的,比如: 355 | ```swift 356 | UIView.animate(withDuration: 1, animations: { 357 | // TODO... 358 | }) { (finished) in 359 | // TODO... 360 | } 361 | ``` 362 | 363 | 这个看大家习惯了,不过在最新的`Swift 5.3`中,针对这块多个尾随闭包有了新的语法糖: 364 | ```swift 365 | // old Swift3 366 | UIView.animate(withDuration: 0.3, animations: { 367 | self.view.alpha = 0 368 | }, completion: { _ in 369 | self.view.removeFromSuperview() 370 | }) 371 | // still old Swift4/5 372 | UIView.animate(withDuration: 0.3, animations: { 373 | self.view.alpha = 0 374 | }) { _ in 375 | self.view.removeFromSuperview() 376 | } 377 | // new swift 5.3 378 | UIView.animate(withDuration: 0.3) { 379 | self.view.alpha = 0 380 | } completion: { _ in 381 | self.view.removeFromSuperview() 382 | } 383 | ``` 384 | 385 | **PS**:最近我有跳槽的想法,有工作机会的老板,欢迎骚扰哦!北京呦! 386 | 387 | **END。** 388 | *我是小侯爷。* 389 | *在魔都艰苦奋斗,白天是上班族,晚上是知识服务工作者。* 390 | *如果读完觉得有收获的话,记得关注和点赞哦。* 391 | *非要打赏的话,我也是不会拒绝的。* 392 | 393 | ### License 394 | 395 | `HWNetworking` is released under the MIT license. See [LICENSE](https://github.com/HouWan/HWNetworking/blob/master/LICENSE) for details. 396 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Library/Custom/HWNetworking/HWNetworking.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HouWan on 2020/05/23. 3 | // Copyright © 2020年 HouWan. All rights reserved. 4 | // 5 | // This source code is licensed under the MIT license found in the 6 | // LICENSE file in the root directory of this source tree. 7 | // 8 | // 9 | // ~~ 天地保佑 永无BUG ~~ 10 | // _ooOoo_ 11 | // o8888888o 12 | // 88" . "88 13 | // (| -_- |) 14 | // O\ = /O 15 | // ____/`---'\____ 16 | // .' \\| |// `. 17 | // / \\||| : |||// \ 18 | // / _||||| -:- |||||- \ 19 | // | | \\\ - /// | | 20 | // | \_| ''\---/'' | | 21 | // \ .-\__ `-` ___/-. / 22 | // ___`. .' /--.--\ `. . __ 23 | // ."" '< `.___\_<|>_/___.' >'"". 24 | // | | : `- \`.;`\ _ /`;.`/ - ` : | | 25 | // \ \ `-. \_ __\ /__ _/ .-` / / 26 | // ======`-.____`-.___\_____/___.-`____.-'====== 27 | // 28 | 29 | import Foundation 30 | import Alamofire 31 | 32 | /// Closure type executed when the request is successful 33 | public typealias HNSuccessClosure = (_ JSON: Any) -> Void 34 | /// Closure type executed when the request is failed 35 | public typealias HNFailedClosure = (_ error: HWNetworkingError) -> Void 36 | /// Closure type executed when monitoring the upload or download progress of a request. 37 | public typealias HNProgressHandler = (Progress) -> Void 38 | 39 | /// Defines the various states of network reachability. 40 | public enum HWReachabilityStatus { 41 | /// It is unknown whether the network is reachable. 42 | case unknown 43 | /// The network is not reachable. 44 | case notReachable 45 | /// The connection type is either over Ethernet or WiFi. 46 | case ethernetOrWiFi 47 | /// The connection type is a cellular connection. 48 | case cellular 49 | } 50 | 51 | // ============================================================================ 52 | 53 | /// Reference to `HWNetworking.shared` for quick bootstrapping and examples. 54 | public let HN = HWNetworking.shared 55 | 56 | /// This notification will be sent when you call method `startMonitoring()` to monitor the network 57 | /// and the network status changes. 58 | public let kNetworkStatusNotification = NSNotification.Name("kNetworkStatusNotification") 59 | 60 | // ============================================================================ 61 | 62 | /// `HWNetworking`网络请求主类 63 | public class HWNetworking { 64 | /// For singleton pattern 65 | public static let shared = HWNetworking() 66 | /// TaskQueue Array for (`Alamofire.Request` & callback) 67 | private(set) var taskQueue = [HWNetworkRequest]() 68 | /// `Session` creates and manages Alamofire's `Request` types during their lifetimes. 69 | var sessionManager: Alamofire.Session! 70 | 71 | /// Network reachability manager, The first call to method `startMonitoring()` will be initialized. 72 | var reachability: NetworkReachabilityManager? 73 | /// The newwork status, `.unknown` by default, You need to call the `startMonitoring()` method 74 | var networkStatus: HWReachabilityStatus = .unknown 75 | 76 | // MARK: - Core method 77 | 78 | /// Initialization 79 | /// `private` for singleton pattern 80 | private init() { 81 | let config = URLSessionConfiguration.af.default 82 | config.timeoutIntervalForRequest = 20 // Timeout interval 83 | config.timeoutIntervalForResource = 20 // Timeout interval 84 | sessionManager = Alamofire.Session(configuration: config) 85 | } 86 | 87 | /// Creates a `DataRequest` from a `URLRequest` created using the passed components 88 | /// 89 | /// - Parameters: 90 | /// - method: `HTTPMethod` for the `URLRequest`. `.get` by default. 91 | /// - parameters: `nil` by default. 92 | /// - headers: `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default. 93 | /// 94 | /// - Returns: The created `DataRequest`. 95 | public func request(url: String, 96 | method: HTTPMethod = .get, 97 | parameters: [String: Any]?, 98 | headers: [String: String]? = nil, 99 | encoding: ParameterEncoding = URLEncoding.default) -> HWNetworkRequest { 100 | let task = HWNetworkRequest() 101 | 102 | var h: HTTPHeaders? 103 | if let tempHeaders = headers { 104 | h = HTTPHeaders(tempHeaders) 105 | } 106 | 107 | task.request = sessionManager.request(url, 108 | method: method, 109 | parameters: parameters, 110 | encoding: encoding, 111 | headers: h).validate().responseJSON { [weak self] response in 112 | task.handleResponse(response: response) 113 | 114 | if let index = self?.taskQueue.firstIndex(of: task) { 115 | self?.taskQueue.remove(at: index) 116 | } 117 | } 118 | taskQueue.append(task) 119 | return task 120 | } 121 | 122 | /// Creates a `UploadRequest` from a `URLRequest` created using the passed components 123 | /// 124 | /// - Parameters: 125 | /// - method: `HTTPMethod` for the `URLRequest`. `.post` by default. 126 | /// - parameters: 为了方便格式化参数,采用了[String: String]格式. `nil` by default. 127 | /// - datas: Data to upload. The data is encapsulated here! more see `HWMultipartData` 128 | /// - headers: `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default. 129 | /// 130 | /// - Returns: The created `UploadRequest`. 131 | public func upload(url: String, 132 | method: HTTPMethod = .post, 133 | parameters: [String: String]?, 134 | datas: [HWMultipartData], 135 | headers: [String: String]? = nil) -> HWNetworkRequest { 136 | let task = HWNetworkRequest() 137 | 138 | var h: HTTPHeaders? 139 | if let tempHeaders = headers { 140 | h = HTTPHeaders(tempHeaders) 141 | } 142 | 143 | task.request = sessionManager.upload(multipartFormData: { (multipartData) in 144 | // 1.参数 parameters 145 | if let parameters = parameters { 146 | for p in parameters { 147 | multipartData.append(p.value.data(using: .utf8)!, withName: p.key) 148 | } 149 | } 150 | // 2.数据 datas 151 | for d in datas { 152 | multipartData.append(d.data, withName: d.name, fileName: d.fileName, mimeType: d.mimeType) 153 | } 154 | }, to: url, method: method, headers: h).uploadProgress(queue: .main, closure: { (progress) in 155 | task.handleProgress(progress: progress) 156 | }).validate().responseJSON(completionHandler: { [weak self] response in 157 | task.handleResponse(response: response) 158 | 159 | if let index = self?.taskQueue.firstIndex(of: task) { 160 | self?.taskQueue.remove(at: index) 161 | } 162 | }) 163 | taskQueue.append(task) 164 | return task 165 | } 166 | 167 | /// Creates a `DownloadRequest`... 168 | /// 169 | /// - warning: Has not been implemented 170 | /// - Returns: The created `DownloadRequest`. 171 | public func download(url: String, method: HTTPMethod = .post) -> HWNetworkRequest { 172 | // has not been implemented 173 | fatalError("download(...) has not been implemented") 174 | } 175 | 176 | // MARK: - Cancellation 177 | 178 | /// Cancel all active `Request`s, optionally calling a completion handler when complete. 179 | /// 180 | /// - Note: This is an asynchronous operation and does not block the creation of future `Request`s. Cancelled 181 | /// `Request`s may not cancel immediately due internal work, and may not cancel at all if they are close to 182 | /// completion when cancelled. 183 | /// 184 | /// - Parameters: 185 | /// - queue: `DispatchQueue` on which the completion handler is run. `.main` by default. 186 | /// - completion: Closure to be called when all `Request`s have been cancelled. 187 | public func cancelAllRequests(completingOnQueue queue: DispatchQueue = .main, completion: (() -> Void)? = nil) { 188 | sessionManager.cancelAllRequests(completingOnQueue: queue, completion: completion) 189 | } 190 | } 191 | 192 | /// Shortcut method for `HWNetworking` 193 | extension HWNetworking { 194 | 195 | /// Creates a POST request 196 | /// 197 | /// - note: more see: `self.request(...)` 198 | @discardableResult 199 | public func POST(url: String, parameters: [String: Any]? = nil, headers: [String: String]? = nil) -> HWNetworkRequest { 200 | request(url: url, method: .post, parameters: parameters, headers: nil) 201 | } 202 | 203 | /// Creates a POST request for upload data 204 | /// 205 | /// - note: more see: `self.request(...)` 206 | @discardableResult 207 | public func POST(url: String, parameters: [String: String]? = nil, headers: [String: String]? = nil, datas: [HWMultipartData]? = nil) -> HWNetworkRequest { 208 | guard datas != nil else { 209 | return request(url: url, method: .post, parameters: parameters, headers: nil) 210 | } 211 | return upload(url: url, parameters: parameters, datas: datas!, headers: headers) 212 | } 213 | 214 | /// Creates a GET request 215 | /// 216 | /// - note: more see: `self.request(...)` 217 | @discardableResult 218 | public func GET(url: String, parameters: [String: Any]? = nil, headers: [String: String]? = nil) -> HWNetworkRequest { 219 | request(url: url, method: .get, parameters: parameters, headers: nil) 220 | } 221 | } 222 | 223 | /// Detect network status 监听网络状态 224 | extension HWNetworking { 225 | /// Starts monitoring for changes in network reachability status. 226 | public func startMonitoring() { 227 | if reachability == nil { 228 | reachability = NetworkReachabilityManager.default 229 | } 230 | 231 | reachability?.startListening(onQueue: .main, onUpdatePerforming: { [unowned self] (status) in 232 | switch status { 233 | case .notReachable: 234 | self.networkStatus = .notReachable 235 | case .unknown: 236 | self.networkStatus = .unknown 237 | case .reachable(.ethernetOrWiFi): 238 | self.networkStatus = .ethernetOrWiFi 239 | case .reachable(.cellular): 240 | self.networkStatus = .cellular 241 | } 242 | // Sent notification 243 | NotificationCenter.default.post(name: kNetworkStatusNotification, object: nil) 244 | debugPrint("HWNetworking Network Status: \(self.networkStatus)") 245 | }) 246 | } 247 | 248 | /// Stops monitoring for changes in network reachability status. 249 | public func stopMonitoring() { 250 | guard reachability != nil else { return } 251 | reachability?.stopListening() 252 | } 253 | } 254 | 255 | /// RequestTask 256 | public class HWNetworkRequest: Equatable { 257 | 258 | /// Alamofire.DataRequest 259 | var request: Alamofire.Request? 260 | /// API description information. default: nil 261 | var description: String? 262 | /// API additional information, eg: Author | Note..., default: nil 263 | var extra: String? 264 | 265 | /// request response callback 266 | private var successHandler: HNSuccessClosure? 267 | /// request failed callback 268 | private var failedHandler: HNFailedClosure? 269 | /// `ProgressHandler` provided for upload/download progress callbacks. 270 | private var progressHandler: HNProgressHandler? 271 | 272 | // MARK: - Handler 273 | 274 | /// Handle request response 275 | func handleResponse(response: AFDataResponse) { 276 | switch response.result { 277 | case .failure(let error): 278 | if let closure = failedHandler { 279 | let hwe = HWNetworkingError(code: error.responseCode ?? -1, desc: error.localizedDescription) 280 | closure(hwe) 281 | } 282 | case .success(let JSON): 283 | if let closure = successHandler { 284 | closure(JSON) 285 | } 286 | } 287 | clearReference() 288 | } 289 | 290 | /// Processing request progress (Only when uploading files) 291 | func handleProgress(progress: Foundation.Progress) { 292 | if let closure = progressHandler { 293 | closure(progress) 294 | } 295 | } 296 | 297 | // MARK: - Callback 298 | 299 | /// Adds a handler to be called once the request has finished. 300 | /// 301 | /// - Parameters: 302 | /// - closure: A closure to be executed once the request has finished. 303 | /// 304 | /// - Returns: The request. 305 | @discardableResult 306 | public func success(_ closure: @escaping HNSuccessClosure) -> Self { 307 | successHandler = closure 308 | return self 309 | } 310 | 311 | /// Adds a handler to be called once the request has finished. 312 | /// 313 | /// - Parameters: 314 | /// - closure: A closure to be executed once the request has finished. 315 | /// 316 | /// - Returns: The request. 317 | @discardableResult 318 | public func failed(_ closure: @escaping HNFailedClosure) -> Self { 319 | failedHandler = closure 320 | return self 321 | } 322 | 323 | /// Sets a closure to be called periodically during the lifecycle of the instance as data is sent to the server. 324 | /// 325 | /// - Note: Only the last closure provided is used. 326 | /// 327 | /// - Parameters: 328 | /// - closure: The closure to be executed periodically as data is sent to the server. 329 | /// 330 | /// - Returns: The instance. 331 | @discardableResult 332 | public func progress(closure: @escaping HNProgressHandler) -> Self { 333 | progressHandler = closure 334 | return self 335 | } 336 | 337 | /// Cancels the instance. Once cancelled, a `Request` can no longer be resumed or suspended. 338 | /// 339 | /// - Returns: The instance. 340 | func cancel() { 341 | request?.cancel() 342 | } 343 | 344 | /// Free memory 345 | func clearReference() { 346 | successHandler = nil 347 | failedHandler = nil 348 | progressHandler = nil 349 | } 350 | } 351 | 352 | /// Equatable for `HWNetworkRequest` 353 | extension HWNetworkRequest { 354 | /// Returns a Boolean value indicating whether two values are equal. 355 | public static func == (lhs: HWNetworkRequest, rhs: HWNetworkRequest) -> Bool { 356 | return lhs.request?.id == rhs.request?.id 357 | } 358 | } 359 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 51; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 2A5AE2A3FA3A4FF73553A5FB /* Pods_SwiftDemo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4B5AFF62E6B4D4DEF54E3BD /* Pods_SwiftDemo.framework */; }; 11 | 536723263ED185F49A3E3C30 /* Pods_SwiftDemoTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A819D687B3383DBEE74FFC39 /* Pods_SwiftDemoTests.framework */; }; 12 | 87504BFF2463AC85007FF576 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87504BFE2463AC85007FF576 /* AppDelegate.swift */; }; 13 | 87504C062463AC85007FF576 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 87504C042463AC85007FF576 /* Main.storyboard */; }; 14 | 87504C082463AC86007FF576 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 87504C072463AC86007FF576 /* Assets.xcassets */; }; 15 | 87504C0B2463AC86007FF576 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 87504C092463AC86007FF576 /* LaunchScreen.storyboard */; }; 16 | 87504C162463AC87007FF576 /* SwiftDemoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87504C152463AC87007FF576 /* SwiftDemoTests.swift */; }; 17 | 87504C2E2463B34A007FF576 /* DNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87504C2D2463B34A007FF576 /* DNavigationController.swift */; }; 18 | 87504C302463BD38007FF576 /* DTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87504C2F2463BD38007FF576 /* DTabBarController.swift */; }; 19 | 87504C322463BD6C007FF576 /* HomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87504C312463BD6C007FF576 /* HomeViewController.swift */; }; 20 | 87504C342463BD7D007FF576 /* SocietyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87504C332463BD7D007FF576 /* SocietyViewController.swift */; }; 21 | 87504C362463BD87007FF576 /* MeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87504C352463BD87007FF576 /* MeViewController.swift */; }; 22 | 87504C382463BD91007FF576 /* GymViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87504C372463BD91007FF576 /* GymViewController.swift */; }; 23 | 87504C3F2463BFB1007FF576 /* DBaseVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87504C3E2463BFB1007FF576 /* DBaseVC.swift */; }; 24 | 875F3F07246680410009E607 /* UIView-Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875F3F06246680410009E607 /* UIView-Extension.swift */; }; 25 | 875F3F0A246685820009E607 /* AppConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 875F3F09246685820009E607 /* AppConstants.swift */; }; 26 | 877AB67924659E09009D975B /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 877AB67824659E09009D975B /* Theme.swift */; }; 27 | 8784A2BA24641933002A46FA /* UIColor-Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8784A2B924641933002A46FA /* UIColor-Extension.swift */; }; 28 | 8784A2BD24642CBD002A46FA /* DTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8784A2BC24642CBD002A46FA /* DTabBar.swift */; }; 29 | 87A34FD2247221F1005B3988 /* SocietyListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87A34FD1247221F1005B3988 /* SocietyListModel.swift */; }; 30 | 87B1E57B2467E27D00E4A2F6 /* HWNetworking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87B1E57A2467E27D00E4A2F6 /* HWNetworking.swift */; }; 31 | 87B1E57D2467F77E00E4A2F6 /* CoachListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87B1E57C2467F77E00E4A2F6 /* CoachListModel.swift */; }; 32 | 87C9535F2464FBC7005B06B7 /* UILabel-Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87C9535E2464FBC7005B06B7 /* UILabel-Extension.swift */; }; 33 | 87C953612464FEB3005B06B7 /* UIFont-Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87C953602464FEB3005B06B7 /* UIFont-Extension.swift */; }; 34 | 87E13F4E246716BE008F2C7D /* SocietyListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87E13F4D246716BE008F2C7D /* SocietyListCell.swift */; }; 35 | 87F468A024EE7E3600904F53 /* HWMultipartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87F4689E24EE7E3600904F53 /* HWMultipartData.swift */; }; 36 | 87F468A124EE7E3600904F53 /* HWAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87F4689F24EE7E3600904F53 /* HWAPI.swift */; }; 37 | 87F468A424EE7E3D00904F53 /* HWNetworkingError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87F468A224EE7E3D00904F53 /* HWNetworkingError.swift */; }; 38 | 87F468A524EE7E3D00904F53 /* HWNetworkingOC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87F468A324EE7E3D00904F53 /* HWNetworkingOC.swift */; }; 39 | 87F468A724EE9B6000904F53 /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87F468A624EE9B6000904F53 /* API.swift */; }; 40 | 87F468AA24EEA06900904F53 /* TestViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 87F468A924EEA06900904F53 /* TestViewController.m */; }; 41 | /* End PBXBuildFile section */ 42 | 43 | /* Begin PBXContainerItemProxy section */ 44 | 87504C122463AC87007FF576 /* PBXContainerItemProxy */ = { 45 | isa = PBXContainerItemProxy; 46 | containerPortal = 87504BF32463AC85007FF576 /* Project object */; 47 | proxyType = 1; 48 | remoteGlobalIDString = 87504BFA2463AC85007FF576; 49 | remoteInfo = SwiftDemo; 50 | }; 51 | /* End PBXContainerItemProxy section */ 52 | 53 | /* Begin PBXFileReference section */ 54 | 30F8D7C1E86D5ADB218A7C4E /* Pods-SwiftDemoTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftDemoTests.release.xcconfig"; path = "Target Support Files/Pods-SwiftDemoTests/Pods-SwiftDemoTests.release.xcconfig"; sourceTree = ""; }; 55 | 42CA35B79DFD7BFADF030E8B /* Pods-SwiftDemoTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftDemoTests.debug.xcconfig"; path = "Target Support Files/Pods-SwiftDemoTests/Pods-SwiftDemoTests.debug.xcconfig"; sourceTree = ""; }; 56 | 4DF235B712C5C69C8D2CA647 /* Pods-SwiftDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftDemo.debug.xcconfig"; path = "Target Support Files/Pods-SwiftDemo/Pods-SwiftDemo.debug.xcconfig"; sourceTree = ""; }; 57 | 59E89834BCEB9338FC3394AF /* Pods-SwiftDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftDemo.release.xcconfig"; path = "Target Support Files/Pods-SwiftDemo/Pods-SwiftDemo.release.xcconfig"; sourceTree = ""; }; 58 | 87504BFB2463AC85007FF576 /* SwiftDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | 87504BFE2463AC85007FF576 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 60 | 87504C052463AC85007FF576 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 61 | 87504C072463AC86007FF576 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 62 | 87504C0A2463AC86007FF576 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 63 | 87504C0C2463AC86007FF576 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 64 | 87504C112463AC87007FF576 /* SwiftDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 65 | 87504C152463AC87007FF576 /* SwiftDemoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftDemoTests.swift; sourceTree = ""; }; 66 | 87504C172463AC87007FF576 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 67 | 87504C2D2463B34A007FF576 /* DNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DNavigationController.swift; sourceTree = ""; }; 68 | 87504C2F2463BD38007FF576 /* DTabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DTabBarController.swift; sourceTree = ""; }; 69 | 87504C312463BD6C007FF576 /* HomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewController.swift; sourceTree = ""; }; 70 | 87504C332463BD7D007FF576 /* SocietyViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocietyViewController.swift; sourceTree = ""; }; 71 | 87504C352463BD87007FF576 /* MeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeViewController.swift; sourceTree = ""; }; 72 | 87504C372463BD91007FF576 /* GymViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GymViewController.swift; sourceTree = ""; }; 73 | 87504C3E2463BFB1007FF576 /* DBaseVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBaseVC.swift; sourceTree = ""; }; 74 | 87504C402463D754007FF576 /* SwiftDemo-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SwiftDemo-Bridging-Header.h"; sourceTree = ""; }; 75 | 875F3F06246680410009E607 /* UIView-Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView-Extension.swift"; sourceTree = ""; }; 76 | 875F3F09246685820009E607 /* AppConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConstants.swift; sourceTree = ""; }; 77 | 877AB67824659E09009D975B /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = ""; }; 78 | 8784A2B924641933002A46FA /* UIColor-Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor-Extension.swift"; sourceTree = ""; }; 79 | 8784A2BC24642CBD002A46FA /* DTabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DTabBar.swift; sourceTree = ""; }; 80 | 87A34FD1247221F1005B3988 /* SocietyListModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocietyListModel.swift; sourceTree = ""; }; 81 | 87B1E57A2467E27D00E4A2F6 /* HWNetworking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HWNetworking.swift; sourceTree = ""; }; 82 | 87B1E57C2467F77E00E4A2F6 /* CoachListModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoachListModel.swift; sourceTree = ""; }; 83 | 87C9535E2464FBC7005B06B7 /* UILabel-Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel-Extension.swift"; sourceTree = ""; }; 84 | 87C953602464FEB3005B06B7 /* UIFont-Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont-Extension.swift"; sourceTree = ""; }; 85 | 87E13F4D246716BE008F2C7D /* SocietyListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocietyListCell.swift; sourceTree = ""; }; 86 | 87F4689E24EE7E3600904F53 /* HWMultipartData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HWMultipartData.swift; sourceTree = ""; }; 87 | 87F4689F24EE7E3600904F53 /* HWAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HWAPI.swift; sourceTree = ""; }; 88 | 87F468A224EE7E3D00904F53 /* HWNetworkingError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HWNetworkingError.swift; sourceTree = ""; }; 89 | 87F468A324EE7E3D00904F53 /* HWNetworkingOC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HWNetworkingOC.swift; sourceTree = ""; }; 90 | 87F468A624EE9B6000904F53 /* API.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = ""; }; 91 | 87F468A824EEA06900904F53 /* TestViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestViewController.h; sourceTree = ""; }; 92 | 87F468A924EEA06900904F53 /* TestViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestViewController.m; sourceTree = ""; }; 93 | A819D687B3383DBEE74FFC39 /* Pods_SwiftDemoTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwiftDemoTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 94 | D4B5AFF62E6B4D4DEF54E3BD /* Pods_SwiftDemo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwiftDemo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 95 | /* End PBXFileReference section */ 96 | 97 | /* Begin PBXFrameworksBuildPhase section */ 98 | 87504BF82463AC85007FF576 /* Frameworks */ = { 99 | isa = PBXFrameworksBuildPhase; 100 | buildActionMask = 2147483647; 101 | files = ( 102 | 2A5AE2A3FA3A4FF73553A5FB /* Pods_SwiftDemo.framework in Frameworks */, 103 | ); 104 | runOnlyForDeploymentPostprocessing = 0; 105 | }; 106 | 87504C0E2463AC87007FF576 /* Frameworks */ = { 107 | isa = PBXFrameworksBuildPhase; 108 | buildActionMask = 2147483647; 109 | files = ( 110 | 536723263ED185F49A3E3C30 /* Pods_SwiftDemoTests.framework in Frameworks */, 111 | ); 112 | runOnlyForDeploymentPostprocessing = 0; 113 | }; 114 | /* End PBXFrameworksBuildPhase section */ 115 | 116 | /* Begin PBXGroup section */ 117 | 010395978612B5E9E98EADE6 /* Pods */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | 4DF235B712C5C69C8D2CA647 /* Pods-SwiftDemo.debug.xcconfig */, 121 | 59E89834BCEB9338FC3394AF /* Pods-SwiftDemo.release.xcconfig */, 122 | 42CA35B79DFD7BFADF030E8B /* Pods-SwiftDemoTests.debug.xcconfig */, 123 | 30F8D7C1E86D5ADB218A7C4E /* Pods-SwiftDemoTests.release.xcconfig */, 124 | ); 125 | path = Pods; 126 | sourceTree = ""; 127 | }; 128 | 661F29E0495F24F8AA5B87B8 /* Frameworks */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | D4B5AFF62E6B4D4DEF54E3BD /* Pods_SwiftDemo.framework */, 132 | A819D687B3383DBEE74FFC39 /* Pods_SwiftDemoTests.framework */, 133 | ); 134 | name = Frameworks; 135 | sourceTree = ""; 136 | }; 137 | 87504BF22463AC85007FF576 = { 138 | isa = PBXGroup; 139 | children = ( 140 | 87504BFD2463AC85007FF576 /* SwiftDemo */, 141 | 87504C142463AC87007FF576 /* SwiftDemoTests */, 142 | 87504BFC2463AC85007FF576 /* Products */, 143 | 010395978612B5E9E98EADE6 /* Pods */, 144 | 661F29E0495F24F8AA5B87B8 /* Frameworks */, 145 | ); 146 | sourceTree = ""; 147 | }; 148 | 87504BFC2463AC85007FF576 /* Products */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | 87504BFB2463AC85007FF576 /* SwiftDemo.app */, 152 | 87504C112463AC87007FF576 /* SwiftDemoTests.xctest */, 153 | ); 154 | name = Products; 155 | sourceTree = ""; 156 | }; 157 | 87504BFD2463AC85007FF576 /* SwiftDemo */ = { 158 | isa = PBXGroup; 159 | children = ( 160 | 87504C2B2463B22A007FF576 /* Tools */, 161 | 87504C282463B20F007FF576 /* Library */, 162 | 87504C232463B209007FF576 /* Code */, 163 | 87504C222463AD22007FF576 /* Resources */, 164 | 87504C212463AD1D007FF576 /* Main */, 165 | ); 166 | path = SwiftDemo; 167 | sourceTree = ""; 168 | }; 169 | 87504C142463AC87007FF576 /* SwiftDemoTests */ = { 170 | isa = PBXGroup; 171 | children = ( 172 | 87504C152463AC87007FF576 /* SwiftDemoTests.swift */, 173 | 87504C172463AC87007FF576 /* Info.plist */, 174 | ); 175 | path = SwiftDemoTests; 176 | sourceTree = ""; 177 | }; 178 | 87504C212463AD1D007FF576 /* Main */ = { 179 | isa = PBXGroup; 180 | children = ( 181 | 8784A2BB24642C84002A46FA /* View */, 182 | 87504C3B2463BDD0007FF576 /* Controller */, 183 | 87504BFE2463AC85007FF576 /* AppDelegate.swift */, 184 | 87504C402463D754007FF576 /* SwiftDemo-Bridging-Header.h */, 185 | 87F468A624EE9B6000904F53 /* API.swift */, 186 | ); 187 | path = Main; 188 | sourceTree = ""; 189 | }; 190 | 87504C222463AD22007FF576 /* Resources */ = { 191 | isa = PBXGroup; 192 | children = ( 193 | 87504C042463AC85007FF576 /* Main.storyboard */, 194 | 87504C072463AC86007FF576 /* Assets.xcassets */, 195 | 87504C092463AC86007FF576 /* LaunchScreen.storyboard */, 196 | 87504C0C2463AC86007FF576 /* Info.plist */, 197 | ); 198 | path = Resources; 199 | sourceTree = ""; 200 | }; 201 | 87504C232463B209007FF576 /* Code */ = { 202 | isa = PBXGroup; 203 | children = ( 204 | 87504C242463B209007FF576 /* Home */, 205 | 87504C252463B209007FF576 /* Society */, 206 | 87504C262463B209007FF576 /* Mine */, 207 | 87504C272463B209007FF576 /* Gym */, 208 | ); 209 | path = Code; 210 | sourceTree = ""; 211 | }; 212 | 87504C242463B209007FF576 /* Home */ = { 213 | isa = PBXGroup; 214 | children = ( 215 | 87504C312463BD6C007FF576 /* HomeViewController.swift */, 216 | 87F468A824EEA06900904F53 /* TestViewController.h */, 217 | 87F468A924EEA06900904F53 /* TestViewController.m */, 218 | ); 219 | path = Home; 220 | sourceTree = ""; 221 | }; 222 | 87504C252463B209007FF576 /* Society */ = { 223 | isa = PBXGroup; 224 | children = ( 225 | 87E13F4C2467169C008F2C7D /* View */, 226 | 87E13F4B24671698008F2C7D /* Model */, 227 | 87504C332463BD7D007FF576 /* SocietyViewController.swift */, 228 | ); 229 | path = Society; 230 | sourceTree = ""; 231 | }; 232 | 87504C262463B209007FF576 /* Mine */ = { 233 | isa = PBXGroup; 234 | children = ( 235 | 87504C352463BD87007FF576 /* MeViewController.swift */, 236 | ); 237 | path = Mine; 238 | sourceTree = ""; 239 | }; 240 | 87504C272463B209007FF576 /* Gym */ = { 241 | isa = PBXGroup; 242 | children = ( 243 | 87504C372463BD91007FF576 /* GymViewController.swift */, 244 | ); 245 | path = Gym; 246 | sourceTree = ""; 247 | }; 248 | 87504C282463B20F007FF576 /* Library */ = { 249 | isa = PBXGroup; 250 | children = ( 251 | 87504C292463B20F007FF576 /* Custom */, 252 | 87504C2A2463B20F007FF576 /* ThirdParty */, 253 | ); 254 | path = Library; 255 | sourceTree = ""; 256 | }; 257 | 87504C292463B20F007FF576 /* Custom */ = { 258 | isa = PBXGroup; 259 | children = ( 260 | 87B1E5792467E25A00E4A2F6 /* HWNetworking */, 261 | ); 262 | path = Custom; 263 | sourceTree = ""; 264 | }; 265 | 87504C2A2463B20F007FF576 /* ThirdParty */ = { 266 | isa = PBXGroup; 267 | children = ( 268 | ); 269 | path = ThirdParty; 270 | sourceTree = ""; 271 | }; 272 | 87504C2B2463B22A007FF576 /* Tools */ = { 273 | isa = PBXGroup; 274 | children = ( 275 | 875F3F08246685750009E607 /* Constants */, 276 | 877AB67724659DD6009D975B /* Theme */, 277 | 87504C2C2463B22A007FF576 /* Extends */, 278 | ); 279 | path = Tools; 280 | sourceTree = ""; 281 | }; 282 | 87504C2C2463B22A007FF576 /* Extends */ = { 283 | isa = PBXGroup; 284 | children = ( 285 | 87C953602464FEB3005B06B7 /* UIFont-Extension.swift */, 286 | 8784A2B924641933002A46FA /* UIColor-Extension.swift */, 287 | 87C9535E2464FBC7005B06B7 /* UILabel-Extension.swift */, 288 | 875F3F06246680410009E607 /* UIView-Extension.swift */, 289 | ); 290 | path = Extends; 291 | sourceTree = ""; 292 | }; 293 | 87504C3B2463BDD0007FF576 /* Controller */ = { 294 | isa = PBXGroup; 295 | children = ( 296 | 87504C2D2463B34A007FF576 /* DNavigationController.swift */, 297 | 87504C2F2463BD38007FF576 /* DTabBarController.swift */, 298 | 87504C3E2463BFB1007FF576 /* DBaseVC.swift */, 299 | ); 300 | path = Controller; 301 | sourceTree = ""; 302 | }; 303 | 875F3F08246685750009E607 /* Constants */ = { 304 | isa = PBXGroup; 305 | children = ( 306 | 875F3F09246685820009E607 /* AppConstants.swift */, 307 | ); 308 | path = Constants; 309 | sourceTree = ""; 310 | }; 311 | 877AB67724659DD6009D975B /* Theme */ = { 312 | isa = PBXGroup; 313 | children = ( 314 | 877AB67824659E09009D975B /* Theme.swift */, 315 | ); 316 | path = Theme; 317 | sourceTree = ""; 318 | }; 319 | 8784A2BB24642C84002A46FA /* View */ = { 320 | isa = PBXGroup; 321 | children = ( 322 | 8784A2BC24642CBD002A46FA /* DTabBar.swift */, 323 | ); 324 | path = View; 325 | sourceTree = ""; 326 | }; 327 | 87B1E5792467E25A00E4A2F6 /* HWNetworking */ = { 328 | isa = PBXGroup; 329 | children = ( 330 | 87F4689F24EE7E3600904F53 /* HWAPI.swift */, 331 | 87F4689E24EE7E3600904F53 /* HWMultipartData.swift */, 332 | 87B1E57A2467E27D00E4A2F6 /* HWNetworking.swift */, 333 | 87F468A224EE7E3D00904F53 /* HWNetworkingError.swift */, 334 | 87F468A324EE7E3D00904F53 /* HWNetworkingOC.swift */, 335 | ); 336 | path = HWNetworking; 337 | sourceTree = ""; 338 | }; 339 | 87E13F4B24671698008F2C7D /* Model */ = { 340 | isa = PBXGroup; 341 | children = ( 342 | 87B1E57C2467F77E00E4A2F6 /* CoachListModel.swift */, 343 | 87A34FD1247221F1005B3988 /* SocietyListModel.swift */, 344 | ); 345 | path = Model; 346 | sourceTree = ""; 347 | }; 348 | 87E13F4C2467169C008F2C7D /* View */ = { 349 | isa = PBXGroup; 350 | children = ( 351 | 87E13F4D246716BE008F2C7D /* SocietyListCell.swift */, 352 | ); 353 | path = View; 354 | sourceTree = ""; 355 | }; 356 | /* End PBXGroup section */ 357 | 358 | /* Begin PBXNativeTarget section */ 359 | 87504BFA2463AC85007FF576 /* SwiftDemo */ = { 360 | isa = PBXNativeTarget; 361 | buildConfigurationList = 87504C1A2463AC87007FF576 /* Build configuration list for PBXNativeTarget "SwiftDemo" */; 362 | buildPhases = ( 363 | 9EDCB9DE26A55A4CC768A87F /* [CP] Check Pods Manifest.lock */, 364 | 87504BF72463AC85007FF576 /* Sources */, 365 | 87504BF82463AC85007FF576 /* Frameworks */, 366 | 87504BF92463AC85007FF576 /* Resources */, 367 | 2FBF54468E9A315FCA6E38E1 /* [CP] Embed Pods Frameworks */, 368 | ); 369 | buildRules = ( 370 | ); 371 | dependencies = ( 372 | ); 373 | name = SwiftDemo; 374 | productName = SwiftDemo; 375 | productReference = 87504BFB2463AC85007FF576 /* SwiftDemo.app */; 376 | productType = "com.apple.product-type.application"; 377 | }; 378 | 87504C102463AC87007FF576 /* SwiftDemoTests */ = { 379 | isa = PBXNativeTarget; 380 | buildConfigurationList = 87504C1D2463AC87007FF576 /* Build configuration list for PBXNativeTarget "SwiftDemoTests" */; 381 | buildPhases = ( 382 | 53A54A82B2CDEDFEEC955B45 /* [CP] Check Pods Manifest.lock */, 383 | 87504C0D2463AC87007FF576 /* Sources */, 384 | 87504C0E2463AC87007FF576 /* Frameworks */, 385 | 87504C0F2463AC87007FF576 /* Resources */, 386 | ); 387 | buildRules = ( 388 | ); 389 | dependencies = ( 390 | 87504C132463AC87007FF576 /* PBXTargetDependency */, 391 | ); 392 | name = SwiftDemoTests; 393 | productName = SwiftDemoTests; 394 | productReference = 87504C112463AC87007FF576 /* SwiftDemoTests.xctest */; 395 | productType = "com.apple.product-type.bundle.unit-test"; 396 | }; 397 | /* End PBXNativeTarget section */ 398 | 399 | /* Begin PBXProject section */ 400 | 87504BF32463AC85007FF576 /* Project object */ = { 401 | isa = PBXProject; 402 | attributes = { 403 | LastSwiftUpdateCheck = 1140; 404 | LastUpgradeCheck = 1140; 405 | ORGANIZATIONNAME = HouWan; 406 | TargetAttributes = { 407 | 87504BFA2463AC85007FF576 = { 408 | CreatedOnToolsVersion = 11.4.1; 409 | LastSwiftMigration = 1140; 410 | }; 411 | 87504C102463AC87007FF576 = { 412 | CreatedOnToolsVersion = 11.4.1; 413 | TestTargetID = 87504BFA2463AC85007FF576; 414 | }; 415 | }; 416 | }; 417 | buildConfigurationList = 87504BF62463AC85007FF576 /* Build configuration list for PBXProject "SwiftDemo" */; 418 | compatibilityVersion = "Xcode 9.3"; 419 | developmentRegion = en; 420 | hasScannedForEncodings = 0; 421 | knownRegions = ( 422 | en, 423 | Base, 424 | ); 425 | mainGroup = 87504BF22463AC85007FF576; 426 | productRefGroup = 87504BFC2463AC85007FF576 /* Products */; 427 | projectDirPath = ""; 428 | projectRoot = ""; 429 | targets = ( 430 | 87504BFA2463AC85007FF576 /* SwiftDemo */, 431 | 87504C102463AC87007FF576 /* SwiftDemoTests */, 432 | ); 433 | }; 434 | /* End PBXProject section */ 435 | 436 | /* Begin PBXResourcesBuildPhase section */ 437 | 87504BF92463AC85007FF576 /* Resources */ = { 438 | isa = PBXResourcesBuildPhase; 439 | buildActionMask = 2147483647; 440 | files = ( 441 | 87504C0B2463AC86007FF576 /* LaunchScreen.storyboard in Resources */, 442 | 87504C082463AC86007FF576 /* Assets.xcassets in Resources */, 443 | 87504C062463AC85007FF576 /* Main.storyboard in Resources */, 444 | ); 445 | runOnlyForDeploymentPostprocessing = 0; 446 | }; 447 | 87504C0F2463AC87007FF576 /* Resources */ = { 448 | isa = PBXResourcesBuildPhase; 449 | buildActionMask = 2147483647; 450 | files = ( 451 | ); 452 | runOnlyForDeploymentPostprocessing = 0; 453 | }; 454 | /* End PBXResourcesBuildPhase section */ 455 | 456 | /* Begin PBXShellScriptBuildPhase section */ 457 | 2FBF54468E9A315FCA6E38E1 /* [CP] Embed Pods Frameworks */ = { 458 | isa = PBXShellScriptBuildPhase; 459 | buildActionMask = 2147483647; 460 | files = ( 461 | ); 462 | inputFileListPaths = ( 463 | "${PODS_ROOT}/Target Support Files/Pods-SwiftDemo/Pods-SwiftDemo-frameworks-${CONFIGURATION}-input-files.xcfilelist", 464 | ); 465 | name = "[CP] Embed Pods Frameworks"; 466 | outputFileListPaths = ( 467 | "${PODS_ROOT}/Target Support Files/Pods-SwiftDemo/Pods-SwiftDemo-frameworks-${CONFIGURATION}-output-files.xcfilelist", 468 | ); 469 | runOnlyForDeploymentPostprocessing = 0; 470 | shellPath = /bin/sh; 471 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SwiftDemo/Pods-SwiftDemo-frameworks.sh\"\n"; 472 | showEnvVarsInLog = 0; 473 | }; 474 | 53A54A82B2CDEDFEEC955B45 /* [CP] Check Pods Manifest.lock */ = { 475 | isa = PBXShellScriptBuildPhase; 476 | buildActionMask = 2147483647; 477 | files = ( 478 | ); 479 | inputFileListPaths = ( 480 | ); 481 | inputPaths = ( 482 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 483 | "${PODS_ROOT}/Manifest.lock", 484 | ); 485 | name = "[CP] Check Pods Manifest.lock"; 486 | outputFileListPaths = ( 487 | ); 488 | outputPaths = ( 489 | "$(DERIVED_FILE_DIR)/Pods-SwiftDemoTests-checkManifestLockResult.txt", 490 | ); 491 | runOnlyForDeploymentPostprocessing = 0; 492 | shellPath = /bin/sh; 493 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 494 | showEnvVarsInLog = 0; 495 | }; 496 | 9EDCB9DE26A55A4CC768A87F /* [CP] Check Pods Manifest.lock */ = { 497 | isa = PBXShellScriptBuildPhase; 498 | buildActionMask = 2147483647; 499 | files = ( 500 | ); 501 | inputFileListPaths = ( 502 | ); 503 | inputPaths = ( 504 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 505 | "${PODS_ROOT}/Manifest.lock", 506 | ); 507 | name = "[CP] Check Pods Manifest.lock"; 508 | outputFileListPaths = ( 509 | ); 510 | outputPaths = ( 511 | "$(DERIVED_FILE_DIR)/Pods-SwiftDemo-checkManifestLockResult.txt", 512 | ); 513 | runOnlyForDeploymentPostprocessing = 0; 514 | shellPath = /bin/sh; 515 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 516 | showEnvVarsInLog = 0; 517 | }; 518 | /* End PBXShellScriptBuildPhase section */ 519 | 520 | /* Begin PBXSourcesBuildPhase section */ 521 | 87504BF72463AC85007FF576 /* Sources */ = { 522 | isa = PBXSourcesBuildPhase; 523 | buildActionMask = 2147483647; 524 | files = ( 525 | 87B1E57B2467E27D00E4A2F6 /* HWNetworking.swift in Sources */, 526 | 87504C322463BD6C007FF576 /* HomeViewController.swift in Sources */, 527 | 87A34FD2247221F1005B3988 /* SocietyListModel.swift in Sources */, 528 | 87B1E57D2467F77E00E4A2F6 /* CoachListModel.swift in Sources */, 529 | 87504C362463BD87007FF576 /* MeViewController.swift in Sources */, 530 | 87504C3F2463BFB1007FF576 /* DBaseVC.swift in Sources */, 531 | 87504C2E2463B34A007FF576 /* DNavigationController.swift in Sources */, 532 | 875F3F0A246685820009E607 /* AppConstants.swift in Sources */, 533 | 87F468A124EE7E3600904F53 /* HWAPI.swift in Sources */, 534 | 877AB67924659E09009D975B /* Theme.swift in Sources */, 535 | 87C953612464FEB3005B06B7 /* UIFont-Extension.swift in Sources */, 536 | 87F468A424EE7E3D00904F53 /* HWNetworkingError.swift in Sources */, 537 | 8784A2BA24641933002A46FA /* UIColor-Extension.swift in Sources */, 538 | 87504C302463BD38007FF576 /* DTabBarController.swift in Sources */, 539 | 87F468AA24EEA06900904F53 /* TestViewController.m in Sources */, 540 | 8784A2BD24642CBD002A46FA /* DTabBar.swift in Sources */, 541 | 87C9535F2464FBC7005B06B7 /* UILabel-Extension.swift in Sources */, 542 | 875F3F07246680410009E607 /* UIView-Extension.swift in Sources */, 543 | 87F468A024EE7E3600904F53 /* HWMultipartData.swift in Sources */, 544 | 87E13F4E246716BE008F2C7D /* SocietyListCell.swift in Sources */, 545 | 87504BFF2463AC85007FF576 /* AppDelegate.swift in Sources */, 546 | 87F468A524EE7E3D00904F53 /* HWNetworkingOC.swift in Sources */, 547 | 87504C382463BD91007FF576 /* GymViewController.swift in Sources */, 548 | 87F468A724EE9B6000904F53 /* API.swift in Sources */, 549 | 87504C342463BD7D007FF576 /* SocietyViewController.swift in Sources */, 550 | ); 551 | runOnlyForDeploymentPostprocessing = 0; 552 | }; 553 | 87504C0D2463AC87007FF576 /* Sources */ = { 554 | isa = PBXSourcesBuildPhase; 555 | buildActionMask = 2147483647; 556 | files = ( 557 | 87504C162463AC87007FF576 /* SwiftDemoTests.swift in Sources */, 558 | ); 559 | runOnlyForDeploymentPostprocessing = 0; 560 | }; 561 | /* End PBXSourcesBuildPhase section */ 562 | 563 | /* Begin PBXTargetDependency section */ 564 | 87504C132463AC87007FF576 /* PBXTargetDependency */ = { 565 | isa = PBXTargetDependency; 566 | target = 87504BFA2463AC85007FF576 /* SwiftDemo */; 567 | targetProxy = 87504C122463AC87007FF576 /* PBXContainerItemProxy */; 568 | }; 569 | /* End PBXTargetDependency section */ 570 | 571 | /* Begin PBXVariantGroup section */ 572 | 87504C042463AC85007FF576 /* Main.storyboard */ = { 573 | isa = PBXVariantGroup; 574 | children = ( 575 | 87504C052463AC85007FF576 /* Base */, 576 | ); 577 | name = Main.storyboard; 578 | sourceTree = ""; 579 | }; 580 | 87504C092463AC86007FF576 /* LaunchScreen.storyboard */ = { 581 | isa = PBXVariantGroup; 582 | children = ( 583 | 87504C0A2463AC86007FF576 /* Base */, 584 | ); 585 | name = LaunchScreen.storyboard; 586 | sourceTree = ""; 587 | }; 588 | /* End PBXVariantGroup section */ 589 | 590 | /* Begin XCBuildConfiguration section */ 591 | 87504C182463AC87007FF576 /* Debug */ = { 592 | isa = XCBuildConfiguration; 593 | buildSettings = { 594 | ALWAYS_SEARCH_USER_PATHS = NO; 595 | CLANG_ANALYZER_NONNULL = YES; 596 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 597 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 598 | CLANG_CXX_LIBRARY = "libc++"; 599 | CLANG_ENABLE_MODULES = YES; 600 | CLANG_ENABLE_OBJC_ARC = YES; 601 | CLANG_ENABLE_OBJC_WEAK = YES; 602 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 603 | CLANG_WARN_BOOL_CONVERSION = YES; 604 | CLANG_WARN_COMMA = YES; 605 | CLANG_WARN_CONSTANT_CONVERSION = YES; 606 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 607 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 608 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 609 | CLANG_WARN_EMPTY_BODY = YES; 610 | CLANG_WARN_ENUM_CONVERSION = YES; 611 | CLANG_WARN_INFINITE_RECURSION = YES; 612 | CLANG_WARN_INT_CONVERSION = YES; 613 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 614 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 615 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 616 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 617 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 618 | CLANG_WARN_STRICT_PROTOTYPES = YES; 619 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 620 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 621 | CLANG_WARN_UNREACHABLE_CODE = YES; 622 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 623 | COPY_PHASE_STRIP = NO; 624 | DEBUG_INFORMATION_FORMAT = dwarf; 625 | ENABLE_STRICT_OBJC_MSGSEND = YES; 626 | ENABLE_TESTABILITY = YES; 627 | GCC_C_LANGUAGE_STANDARD = gnu11; 628 | GCC_DYNAMIC_NO_PIC = NO; 629 | GCC_NO_COMMON_BLOCKS = YES; 630 | GCC_OPTIMIZATION_LEVEL = 0; 631 | GCC_PREPROCESSOR_DEFINITIONS = ( 632 | "DEBUG=1", 633 | "$(inherited)", 634 | ); 635 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 636 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 637 | GCC_WARN_UNDECLARED_SELECTOR = YES; 638 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 639 | GCC_WARN_UNUSED_FUNCTION = YES; 640 | GCC_WARN_UNUSED_VARIABLE = YES; 641 | IPHONEOS_DEPLOYMENT_TARGET = 13.4; 642 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 643 | MTL_FAST_MATH = YES; 644 | ONLY_ACTIVE_ARCH = YES; 645 | SDKROOT = iphoneos; 646 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 647 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 648 | }; 649 | name = Debug; 650 | }; 651 | 87504C192463AC87007FF576 /* Release */ = { 652 | isa = XCBuildConfiguration; 653 | buildSettings = { 654 | ALWAYS_SEARCH_USER_PATHS = NO; 655 | CLANG_ANALYZER_NONNULL = YES; 656 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 657 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 658 | CLANG_CXX_LIBRARY = "libc++"; 659 | CLANG_ENABLE_MODULES = YES; 660 | CLANG_ENABLE_OBJC_ARC = YES; 661 | CLANG_ENABLE_OBJC_WEAK = YES; 662 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 663 | CLANG_WARN_BOOL_CONVERSION = YES; 664 | CLANG_WARN_COMMA = YES; 665 | CLANG_WARN_CONSTANT_CONVERSION = YES; 666 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 667 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 668 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 669 | CLANG_WARN_EMPTY_BODY = YES; 670 | CLANG_WARN_ENUM_CONVERSION = YES; 671 | CLANG_WARN_INFINITE_RECURSION = YES; 672 | CLANG_WARN_INT_CONVERSION = YES; 673 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 674 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 675 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 676 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 677 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 678 | CLANG_WARN_STRICT_PROTOTYPES = YES; 679 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 680 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 681 | CLANG_WARN_UNREACHABLE_CODE = YES; 682 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 683 | COPY_PHASE_STRIP = NO; 684 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 685 | ENABLE_NS_ASSERTIONS = NO; 686 | ENABLE_STRICT_OBJC_MSGSEND = YES; 687 | GCC_C_LANGUAGE_STANDARD = gnu11; 688 | GCC_NO_COMMON_BLOCKS = YES; 689 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 690 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 691 | GCC_WARN_UNDECLARED_SELECTOR = YES; 692 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 693 | GCC_WARN_UNUSED_FUNCTION = YES; 694 | GCC_WARN_UNUSED_VARIABLE = YES; 695 | IPHONEOS_DEPLOYMENT_TARGET = 13.4; 696 | MTL_ENABLE_DEBUG_INFO = NO; 697 | MTL_FAST_MATH = YES; 698 | SDKROOT = iphoneos; 699 | SWIFT_COMPILATION_MODE = wholemodule; 700 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 701 | VALIDATE_PRODUCT = YES; 702 | }; 703 | name = Release; 704 | }; 705 | 87504C1B2463AC87007FF576 /* Debug */ = { 706 | isa = XCBuildConfiguration; 707 | baseConfigurationReference = 4DF235B712C5C69C8D2CA647 /* Pods-SwiftDemo.debug.xcconfig */; 708 | buildSettings = { 709 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 710 | CLANG_ENABLE_MODULES = YES; 711 | CODE_SIGN_STYLE = Automatic; 712 | DEFINES_MODULE = YES; 713 | INFOPLIST_FILE = SwiftDemo/Resources/Info.plist; 714 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 715 | LD_RUNPATH_SEARCH_PATHS = ( 716 | "$(inherited)", 717 | "@executable_path/Frameworks", 718 | ); 719 | PRODUCT_BUNDLE_IDENTIFIER = com.a.a.SwiftDemo; 720 | PRODUCT_NAME = "$(TARGET_NAME)"; 721 | SWIFT_OBJC_BRIDGING_HEADER = "SwiftDemo/Main/SwiftDemo-Bridging-Header.h"; 722 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 723 | SWIFT_VERSION = 5.0; 724 | TARGETED_DEVICE_FAMILY = 1; 725 | }; 726 | name = Debug; 727 | }; 728 | 87504C1C2463AC87007FF576 /* Release */ = { 729 | isa = XCBuildConfiguration; 730 | baseConfigurationReference = 59E89834BCEB9338FC3394AF /* Pods-SwiftDemo.release.xcconfig */; 731 | buildSettings = { 732 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 733 | CLANG_ENABLE_MODULES = YES; 734 | CODE_SIGN_STYLE = Automatic; 735 | DEFINES_MODULE = YES; 736 | INFOPLIST_FILE = SwiftDemo/Resources/Info.plist; 737 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 738 | LD_RUNPATH_SEARCH_PATHS = ( 739 | "$(inherited)", 740 | "@executable_path/Frameworks", 741 | ); 742 | PRODUCT_BUNDLE_IDENTIFIER = com.a.a.SwiftDemo; 743 | PRODUCT_NAME = "$(TARGET_NAME)"; 744 | SWIFT_OBJC_BRIDGING_HEADER = "SwiftDemo/Main/SwiftDemo-Bridging-Header.h"; 745 | SWIFT_VERSION = 5.0; 746 | TARGETED_DEVICE_FAMILY = 1; 747 | }; 748 | name = Release; 749 | }; 750 | 87504C1E2463AC87007FF576 /* Debug */ = { 751 | isa = XCBuildConfiguration; 752 | baseConfigurationReference = 42CA35B79DFD7BFADF030E8B /* Pods-SwiftDemoTests.debug.xcconfig */; 753 | buildSettings = { 754 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 755 | BUNDLE_LOADER = "$(TEST_HOST)"; 756 | CODE_SIGN_STYLE = Automatic; 757 | INFOPLIST_FILE = SwiftDemoTests/Info.plist; 758 | IPHONEOS_DEPLOYMENT_TARGET = 13.4; 759 | LD_RUNPATH_SEARCH_PATHS = ( 760 | "$(inherited)", 761 | "@executable_path/Frameworks", 762 | "@loader_path/Frameworks", 763 | ); 764 | PRODUCT_BUNDLE_IDENTIFIER = com.a.a.SwiftDemoTests; 765 | PRODUCT_NAME = "$(TARGET_NAME)"; 766 | SWIFT_VERSION = 5.0; 767 | TARGETED_DEVICE_FAMILY = "1,2"; 768 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftDemo.app/SwiftDemo"; 769 | }; 770 | name = Debug; 771 | }; 772 | 87504C1F2463AC87007FF576 /* Release */ = { 773 | isa = XCBuildConfiguration; 774 | baseConfigurationReference = 30F8D7C1E86D5ADB218A7C4E /* Pods-SwiftDemoTests.release.xcconfig */; 775 | buildSettings = { 776 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 777 | BUNDLE_LOADER = "$(TEST_HOST)"; 778 | CODE_SIGN_STYLE = Automatic; 779 | INFOPLIST_FILE = SwiftDemoTests/Info.plist; 780 | IPHONEOS_DEPLOYMENT_TARGET = 13.4; 781 | LD_RUNPATH_SEARCH_PATHS = ( 782 | "$(inherited)", 783 | "@executable_path/Frameworks", 784 | "@loader_path/Frameworks", 785 | ); 786 | PRODUCT_BUNDLE_IDENTIFIER = com.a.a.SwiftDemoTests; 787 | PRODUCT_NAME = "$(TARGET_NAME)"; 788 | SWIFT_VERSION = 5.0; 789 | TARGETED_DEVICE_FAMILY = "1,2"; 790 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftDemo.app/SwiftDemo"; 791 | }; 792 | name = Release; 793 | }; 794 | /* End XCBuildConfiguration section */ 795 | 796 | /* Begin XCConfigurationList section */ 797 | 87504BF62463AC85007FF576 /* Build configuration list for PBXProject "SwiftDemo" */ = { 798 | isa = XCConfigurationList; 799 | buildConfigurations = ( 800 | 87504C182463AC87007FF576 /* Debug */, 801 | 87504C192463AC87007FF576 /* Release */, 802 | ); 803 | defaultConfigurationIsVisible = 0; 804 | defaultConfigurationName = Release; 805 | }; 806 | 87504C1A2463AC87007FF576 /* Build configuration list for PBXNativeTarget "SwiftDemo" */ = { 807 | isa = XCConfigurationList; 808 | buildConfigurations = ( 809 | 87504C1B2463AC87007FF576 /* Debug */, 810 | 87504C1C2463AC87007FF576 /* Release */, 811 | ); 812 | defaultConfigurationIsVisible = 0; 813 | defaultConfigurationName = Release; 814 | }; 815 | 87504C1D2463AC87007FF576 /* Build configuration list for PBXNativeTarget "SwiftDemoTests" */ = { 816 | isa = XCConfigurationList; 817 | buildConfigurations = ( 818 | 87504C1E2463AC87007FF576 /* Debug */, 819 | 87504C1F2463AC87007FF576 /* Release */, 820 | ); 821 | defaultConfigurationIsVisible = 0; 822 | defaultConfigurationName = Release; 823 | }; 824 | /* End XCConfigurationList section */ 825 | }; 826 | rootObject = 87504BF32463AC85007FF576 /* Project object */; 827 | } 828 | --------------------------------------------------------------------------------