├── 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 |
--------------------------------------------------------------------------------