├── .gitignore
├── .ruby-gemset
├── .ruby-version
├── .swift-version
├── .swiftlint.yml
├── .travis.yml
├── Brewfile
├── Gemfile
├── Gemfile.lock
├── LICENSE
├── PodTest
├── AppDelegate.swift
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── Info.plist
└── ViewController.swift
├── Podfile
├── Podfile.lock
├── README.md
├── Sources
├── Classes
│ ├── AlertController.swift
│ ├── Label.swift
│ ├── RefreshControl.swift
│ ├── SwiftUtils.swift
│ ├── TableView.swift
│ └── ViewController.swift
├── Extensions
│ ├── Array.swift
│ ├── Bool.swift
│ ├── CGGeometry.swift
│ ├── Dictionary.swift
│ ├── Double.swift
│ ├── Float.swift
│ ├── Int.swift
│ ├── NSBundle.swift
│ ├── NSData.swift
│ ├── NSDate.swift
│ ├── NSFileManager.swift
│ ├── NSLock.swift
│ ├── NSURL.swift
│ ├── Range.swift
│ ├── Regex.swift
│ ├── String.swift
│ ├── UICollectionView.swift
│ ├── UIColor.swift
│ ├── UIGeometry.swift
│ ├── UIImage.swift
│ ├── UILayoutPriority.swift
│ ├── UITableView.swift
│ ├── UIView.swift
│ └── UIViewController.swift
└── Info.plist
├── SwiftUtils.podspec
├── SwiftUtils.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── WorkspaceSettings.xcsettings
└── xcshareddata
│ └── xcschemes
│ ├── PodTest.xcscheme
│ └── SwiftUtils.xcscheme
├── SwiftUtils.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ ├── IDEWorkspaceChecks.plist
│ └── WorkspaceSettings.xcsettings
├── Tests
├── Array.swift
├── Bool.swift
├── Data
│ ├── TestView.swift
│ └── TestView.xib
├── Info.plist
├── String.swift
└── UIView.swift
├── fastlane
├── Fastfile
└── Scanfile
└── scripts
├── branch
├── codecov
├── install
├── lint
├── pod_test
├── pr_number
├── setup
├── setup_rbenv
├── src_branch
├── test
└── validate_branch
/.gitignore:
--------------------------------------------------------------------------------
1 | ### Swift ###
2 | # Xcode
3 | #
4 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
5 |
6 | ## Build generated
7 | build/
8 | DerivedData/
9 |
10 | ## Various settings
11 | *.pbxuser
12 | !default.pbxuser
13 | *.mode1v3
14 | !default.mode1v3
15 | *.mode2v3
16 | !default.mode2v3
17 | *.perspectivev3
18 | !default.perspectivev3
19 | xcuserdata/
20 |
21 | ## Other
22 | *.moved-aside
23 | *.xccheckout
24 | *.xcscmblueprint
25 | *.DS_Store
26 |
27 | ## Obj-C/Swift specific
28 | *.hmap
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 | .build/
43 |
44 | # CocoaPods
45 | #
46 | # We recommend against adding the Pods directory to your .gitignore. However
47 | # you should judge for yourself, the pros and cons are mentioned at:
48 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
49 | Pods/
50 |
51 | # Carthage
52 | #
53 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
54 | Carthage/Checkouts
55 | Carthage/Build
56 |
57 | # fastlane
58 | #
59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
60 | # screenshots whenever they are needed.
61 | # For more information about the recommended setup visit:
62 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md
63 |
64 | fastlane/report.xml
65 | fastlane/Preview.html
66 | fastlane/screenshots
67 | fastlane/README.md
68 | fastlane/test_output
69 |
70 | # Bundler
71 | vendor
72 | .bundle.bundle
73 | .bundle
74 | vendor/bundle
75 | *.coverage.txt
76 | swiftlint-report.json
77 |
--------------------------------------------------------------------------------
/.ruby-gemset:
--------------------------------------------------------------------------------
1 | ci
2 |
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | 2.5.1
2 |
--------------------------------------------------------------------------------
/.swift-version:
--------------------------------------------------------------------------------
1 | 4.2
--------------------------------------------------------------------------------
/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | # reporter: xcode
2 | disabled_rules:
3 | - todo
4 | - trailing_whitespace
5 | - variable_name
6 | excluded:
7 | - Carthage
8 | - Pods
9 | line_length: 300
10 | file_length: 1000
11 | function_body_length:
12 | - 50
13 | - 100
14 | type_body_length:
15 | - 300
16 | - 500
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: objective-c
2 | osx_image: xcode10
3 | cache:
4 | - bundler
5 | - cocoapods
6 | install:
7 | - set -o pipefail
8 | - sudo systemsetup -settimezone Asia/Ho_Chi_Minh
9 | - bundle install --path=vendor/bundle --jobs 4 --retry 3
10 | script:
11 | - ./scripts/branch
12 | - bundle exec pod install --repo-update
13 | - ./scripts/lint
14 | - bundle exec fastlane test
--------------------------------------------------------------------------------
/Brewfile:
--------------------------------------------------------------------------------
1 | brew 'swiftlint'
2 | brew 'jq'
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem 'xcpretty', '0.2.8'
4 | gem 'cocoapods', '1.5.3'
5 | gem 'linterbot', '0.2.7'
6 | gem 'fastlane'
7 | gem 'json', '~> 2.0.3'
8 |
9 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | CFPropertyList (2.3.6)
5 | activesupport (4.2.10)
6 | i18n (~> 0.7)
7 | minitest (~> 5.1)
8 | thread_safe (~> 0.3, >= 0.3.4)
9 | tzinfo (~> 1.1)
10 | addressable (2.5.2)
11 | public_suffix (>= 2.0.2, < 4.0)
12 | atomos (0.1.2)
13 | babosa (1.0.2)
14 | claide (1.0.2)
15 | cocoapods (1.5.3)
16 | activesupport (>= 4.0.2, < 5)
17 | claide (>= 1.0.2, < 2.0)
18 | cocoapods-core (= 1.5.3)
19 | cocoapods-deintegrate (>= 1.0.2, < 2.0)
20 | cocoapods-downloader (>= 1.2.0, < 2.0)
21 | cocoapods-plugins (>= 1.0.0, < 2.0)
22 | cocoapods-search (>= 1.0.0, < 2.0)
23 | cocoapods-stats (>= 1.0.0, < 2.0)
24 | cocoapods-trunk (>= 1.3.0, < 2.0)
25 | cocoapods-try (>= 1.1.0, < 2.0)
26 | colored2 (~> 3.1)
27 | escape (~> 0.0.4)
28 | fourflusher (~> 2.0.1)
29 | gh_inspector (~> 1.0)
30 | molinillo (~> 0.6.5)
31 | nap (~> 1.0)
32 | ruby-macho (~> 1.1)
33 | xcodeproj (>= 1.5.7, < 2.0)
34 | cocoapods-core (1.5.3)
35 | activesupport (>= 4.0.2, < 6)
36 | fuzzy_match (~> 2.0.4)
37 | nap (~> 1.0)
38 | cocoapods-deintegrate (1.0.2)
39 | cocoapods-downloader (1.2.2)
40 | cocoapods-plugins (1.0.0)
41 | nap
42 | cocoapods-search (1.0.0)
43 | cocoapods-stats (1.0.0)
44 | cocoapods-trunk (1.3.1)
45 | nap (>= 0.8, < 2.0)
46 | netrc (~> 0.11)
47 | cocoapods-try (1.1.0)
48 | colored (1.2)
49 | colored2 (3.1.2)
50 | commander (4.4.3)
51 | highline (~> 1.7.2)
52 | commander-fastlane (4.4.6)
53 | highline (~> 1.7.2)
54 | concurrent-ruby (1.0.5)
55 | declarative (0.0.10)
56 | declarative-option (0.1.0)
57 | domain_name (0.5.20170404)
58 | unf (>= 0.0.5, < 1.0.0)
59 | dotenv (2.2.1)
60 | escape (0.0.4)
61 | excon (0.61.0)
62 | faraday (0.13.1)
63 | multipart-post (>= 1.2, < 3)
64 | faraday-cookie_jar (0.0.6)
65 | faraday (>= 0.7.4)
66 | http-cookie (~> 1.0.0)
67 | faraday_middleware (0.12.2)
68 | faraday (>= 0.7.4, < 1.0)
69 | fastimage (2.1.1)
70 | fastlane (2.54.2)
71 | CFPropertyList (>= 2.3, < 3.0.0)
72 | addressable (>= 2.3, < 3.0.0)
73 | babosa (>= 1.0.2, < 2.0.0)
74 | bundler (>= 1.12.0, < 2.0.0)
75 | colored
76 | commander-fastlane (>= 4.4.5, < 5.0.0)
77 | dotenv (>= 2.1.1, < 3.0.0)
78 | excon (>= 0.45.0, < 1.0.0)
79 | faraday (~> 0.9)
80 | faraday-cookie_jar (~> 0.0.6)
81 | faraday_middleware (~> 0.9)
82 | fastimage (>= 2.1.0, < 3.0.0)
83 | gh_inspector (>= 1.0.1, < 2.0.0)
84 | google-api-client (>= 0.13.1, < 0.14.0)
85 | highline (>= 1.7.2, < 2.0.0)
86 | json (< 3.0.0)
87 | mini_magick (~> 4.5.1)
88 | multi_json
89 | multi_xml (~> 0.5)
90 | multipart-post (~> 2.0.0)
91 | plist (>= 3.1.0, < 4.0.0)
92 | rubyzip (>= 1.1.0, < 2.0.0)
93 | security (= 0.1.3)
94 | slack-notifier (>= 1.3, < 2.0.0)
95 | terminal-notifier (>= 1.6.2, < 2.0.0)
96 | terminal-table (>= 1.4.5, < 2.0.0)
97 | tty-screen (~> 0.5.0)
98 | word_wrap (~> 1.0.0)
99 | xcodeproj (>= 1.5.0, < 2.0.0)
100 | xcpretty (>= 0.2.4, < 1.0.0)
101 | xcpretty-travis-formatter (>= 0.0.3)
102 | fourflusher (2.0.1)
103 | fuzzy_match (2.0.4)
104 | gh_inspector (1.1.3)
105 | google-api-client (0.13.6)
106 | addressable (~> 2.5, >= 2.5.1)
107 | googleauth (~> 0.5)
108 | httpclient (>= 2.8.1, < 3.0)
109 | mime-types (~> 3.0)
110 | representable (~> 3.0)
111 | retriable (>= 2.0, < 4.0)
112 | googleauth (0.6.2)
113 | faraday (~> 0.12)
114 | jwt (>= 1.4, < 3.0)
115 | logging (~> 2.0)
116 | memoist (~> 0.12)
117 | multi_json (~> 1.11)
118 | os (~> 0.9)
119 | signet (~> 0.7)
120 | highline (1.7.8)
121 | http-cookie (1.0.3)
122 | domain_name (~> 0.5)
123 | httpclient (2.8.3)
124 | i18n (0.9.5)
125 | concurrent-ruby (~> 1.0)
126 | json (2.0.4)
127 | jwt (2.1.0)
128 | linterbot (0.2.7)
129 | commander (~> 4.3)
130 | octokit (~> 4.2)
131 | little-plugger (1.1.4)
132 | logging (2.2.2)
133 | little-plugger (~> 1.1)
134 | multi_json (~> 1.10)
135 | memoist (0.16.0)
136 | mime-types (3.1)
137 | mime-types-data (~> 3.2015)
138 | mime-types-data (3.2016.0521)
139 | mini_magick (4.5.1)
140 | minitest (5.11.3)
141 | molinillo (0.6.6)
142 | multi_json (1.13.1)
143 | multi_xml (0.6.0)
144 | multipart-post (2.0.0)
145 | nanaimo (0.2.4)
146 | nap (1.1.0)
147 | netrc (0.11.0)
148 | octokit (4.7.0)
149 | sawyer (~> 0.8.0, >= 0.5.3)
150 | os (0.9.6)
151 | plist (3.4.0)
152 | public_suffix (3.0.1)
153 | representable (3.0.4)
154 | declarative (< 0.1.0)
155 | declarative-option (< 0.2.0)
156 | uber (< 0.2.0)
157 | retriable (3.1.1)
158 | rouge (2.0.7)
159 | ruby-macho (1.3.1)
160 | rubyzip (1.2.1)
161 | sawyer (0.8.1)
162 | addressable (>= 2.3.5, < 2.6)
163 | faraday (~> 0.8, < 1.0)
164 | security (0.1.3)
165 | signet (0.8.1)
166 | addressable (~> 2.3)
167 | faraday (~> 0.9)
168 | jwt (>= 1.5, < 3.0)
169 | multi_json (~> 1.10)
170 | slack-notifier (1.5.1)
171 | terminal-notifier (1.8.0)
172 | terminal-table (1.8.0)
173 | unicode-display_width (~> 1.1, >= 1.1.1)
174 | thread_safe (0.3.6)
175 | tty-screen (0.5.1)
176 | tzinfo (1.2.5)
177 | thread_safe (~> 0.1)
178 | uber (0.1.0)
179 | unf (0.1.4)
180 | unf_ext
181 | unf_ext (0.0.7.5)
182 | unicode-display_width (1.3.0)
183 | word_wrap (1.0.0)
184 | xcodeproj (1.5.7)
185 | CFPropertyList (>= 2.3.3, < 4.0)
186 | atomos (~> 0.1.2)
187 | claide (>= 1.0.2, < 2.0)
188 | colored2 (~> 3.1)
189 | nanaimo (~> 0.2.4)
190 | xcpretty (0.2.8)
191 | rouge (~> 2.0.7)
192 | xcpretty-travis-formatter (1.0.0)
193 | xcpretty (~> 0.2, >= 0.0.7)
194 |
195 | PLATFORMS
196 | ruby
197 |
198 | DEPENDENCIES
199 | cocoapods (= 1.5.3)
200 | fastlane
201 | json (~> 2.0.3)
202 | linterbot (= 0.2.7)
203 | xcpretty (= 0.2.8)
204 |
205 | BUNDLED WITH
206 | 1.16.2
207 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/PodTest/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // PodTest
4 | //
5 | // Created by DaoNV on 9/21/16.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SwiftUtils
11 |
12 | @UIApplicationMain
13 | class AppDelegate: UIResponder, UIApplicationDelegate {
14 |
15 | var window: UIWindow?
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
18 | return true
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/PodTest/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ios-marketing",
45 | "size" : "1024x1024",
46 | "scale" : "1x"
47 | }
48 | ],
49 | "info" : {
50 | "version" : 1,
51 | "author" : "xcode"
52 | }
53 | }
--------------------------------------------------------------------------------
/PodTest/Base.lproj/LaunchScreen.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 |
28 |
29 |
--------------------------------------------------------------------------------
/PodTest/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 |
28 |
--------------------------------------------------------------------------------
/PodTest/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 4.2
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/PodTest/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // PodTest
4 | //
5 | // Created by DaoNV on 9/21/16.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SwiftUtils
11 |
12 | class ViewController: UIViewController {
13 | var didShowPopup = false
14 |
15 | override func viewDidAppear(_ animated: Bool) {
16 | super.viewDidAppear(animated)
17 | guard didShowPopup == false else { return }
18 | didShowPopup = true
19 | let popup = PopupController()
20 | present(popup, animated: true) {
21 | NSLog("1")
22 | let vc = AlertController(title: "OK", message: "Huh?", preferredStyle: .alert)
23 | vc.level = .high
24 | vc.addAction("OK", style: .cancel, handler: nil)
25 | vc.present(from: self, animated: true, completion: {
26 | NSLog("2")
27 | })
28 | }
29 | }
30 | }
31 |
32 | class PopupController: UIViewController, AlertLevelProtocol {
33 | var level: AlertLevel = .normal
34 |
35 | override func viewDidLoad() {
36 | super.viewDidLoad()
37 | view.backgroundColor = UIColor.red
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | source 'https://github.com/CocoaPods/Specs.git'
2 | inhibit_all_warnings!
3 | platform :ios, '8.0'
4 | use_frameworks!
5 |
6 | target 'PodTest' do
7 | pod 'SwiftUtils', :path => './'
8 | end
9 |
10 | target 'SwiftUtils' do
11 | pod 'SwiftLint', '0.27.0'
12 | target 'Tests' do
13 | inherit! :search_paths
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - SwiftLint (0.27.0)
3 | - SwiftUtils (4.2)
4 |
5 | DEPENDENCIES:
6 | - SwiftLint (= 0.27.0)
7 | - SwiftUtils (from `./`)
8 |
9 | SPEC REPOS:
10 | https://github.com/cocoapods/specs.git:
11 | - SwiftLint
12 |
13 | EXTERNAL SOURCES:
14 | SwiftUtils:
15 | :path: "./"
16 |
17 | SPEC CHECKSUMS:
18 | SwiftLint: 3207c1faa2240bf8973b191820a116113cd11073
19 | SwiftUtils: 53c2d3af84be01705cef1adcd26d1b2185877ff2
20 |
21 | PODFILE CHECKSUM: 14b3e43ac110b759f33cdbe473a6925738ff4645
22 |
23 | COCOAPODS: 1.5.3
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/tsrnd/swiftutils-ios)
2 | [](https://img.shields.io/cocoapods/v/SwiftUtils.svg)
3 | [](http://cocoadocs.org/docsets/SwiftUtils)
4 | [](https://codecov.io/github/tsrnd/swiftutils-ios?branch=master)
5 |
6 | [SwiftUtils](https://github.com/tsrnd/swiftutils-ios)
7 | ============
8 |
9 | ## Requirements
10 |
11 | - iOS 8.0+
12 | Version 4.0.2: - Xcode 9 ~ Swift 4.0+
13 | Version 4.2: - Xcode 10 ~ Swift 4.2+
14 |
15 | ## Installation
16 |
17 | ### CocoaPods
18 |
19 | [CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command:
20 |
21 | ```bash
22 | $ gem install cocoapods
23 | ```
24 |
25 | > CocoaPods 1.2.0+ is required to build SwiftUtils 4.0+.
26 |
27 | To integrate SwiftUtils into your Xcode project using CocoaPods, specify it in your `Podfile`:
28 |
29 | ```ruby
30 | source 'https://github.com/CocoaPods/Specs.git'
31 | platform :ios, '8.0'
32 | use_frameworks!
33 |
34 | pod 'SwiftUtils', '4.2'
35 | ```
36 |
37 | Then, run the following command:
38 |
39 | ```bash
40 | $ pod install
41 | ```
42 |
--------------------------------------------------------------------------------
/Sources/Classes/AlertController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIAlertController.swift
3 | // TimorAir
4 | //
5 | // Created by DaoNV on 8/23/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public enum AlertLevel: Int {
12 | case low
13 | case normal
14 | case high
15 | case require
16 | }
17 |
18 | public protocol AlertLevelProtocol: class {
19 | var level: AlertLevel { get }
20 | func dismiss(animated: Bool, completion: (() -> Void)?)
21 | }
22 |
23 | open class AlertController: UIAlertController, AlertLevelProtocol {
24 |
25 | open var level = AlertLevel.normal
26 |
27 | open func addAction(_ title: String?, style: UIAlertAction.Style = UIAlertAction.Style.default, handler: (() -> Void)? = nil) {
28 | let actionHandler: ((UIAlertAction) -> Void)? = handler != nil ? { (action: UIAlertAction) -> Void in
29 | handler?()
30 | }: nil
31 | let action = UIAlertAction(title: title, style: style, handler: actionHandler)
32 | addAction(action)
33 | }
34 |
35 | // Recommend `present` method for AlertController instead of default is `presentViewController`.
36 | open func present(from: UIViewController? = nil, animated: Bool = true, completion: (() -> Void)? = nil) {
37 | if let from = from, from.isViewLoaded {
38 | if let popup = from.presentedViewController {
39 | if let vc = popup as? AlertLevelProtocol {
40 | if level > vc.level {
41 | vc.dismiss(animated: animated, completion: { () -> Void in
42 | self.present(from: from, animated: animated, completion: completion)
43 | })
44 | }
45 | } else if level > .normal {
46 | popup.dismiss(animated: animated, completion: { () -> Void in
47 | self.present(from: from, animated: animated, completion: completion)
48 | })
49 | }
50 | } else {
51 | from.present(self, animated: animated, completion: completion)
52 | }
53 | } else if let root = UIApplication.shared.delegate?.window??.rootViewController, root.isViewLoaded {
54 | present(from: root, animated: animated, completion: completion)
55 | }
56 | }
57 |
58 | open func dismiss(_ animated: Bool = true, completion: (() -> Void)? = nil) {
59 | self.dismiss(animated: animated, completion: completion)
60 | }
61 |
62 | open class func alertWithError(_ error: NSError, level: AlertLevel = .normal, handler: (() -> Void)? = nil) -> AlertController {
63 | let alert = AlertController(
64 | title: Bundle.main.name.localized(),
65 | message: error.localizedDescription.localized(),
66 | preferredStyle: .alert
67 | )
68 | alert.addAction("OK".localized(), style: .cancel, handler: handler)
69 | return alert
70 | }
71 | }
72 |
73 | public func == (lhs: AlertLevel, rhs: AlertLevel) -> Bool {
74 | return lhs.rawValue == rhs.rawValue
75 | }
76 |
77 | public func > (lhs: AlertLevel, rhs: AlertLevel) -> Bool {
78 | return lhs.rawValue > rhs.rawValue
79 | }
80 |
81 | public func >= (lhs: AlertLevel, rhs: AlertLevel) -> Bool {
82 | return lhs.rawValue >= rhs.rawValue
83 | }
84 |
85 | public func < (lhs: AlertLevel, rhs: AlertLevel) -> Bool {
86 | return lhs.rawValue < rhs.rawValue
87 | }
88 |
89 | public func <= (lhs: AlertLevel, rhs: AlertLevel) -> Bool {
90 | return lhs.rawValue <= rhs.rawValue
91 | }
92 |
--------------------------------------------------------------------------------
/Sources/Classes/Label.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Label.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/5/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | open class Label: UILabel {
12 | open var edgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
13 |
14 | override open func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
15 | var rect = edgeInsets.inset(bounds)
16 | rect = super.textRect(forBounds: rect, limitedToNumberOfLines: numberOfLines)
17 | return edgeInsets.inverse.inset(rect)
18 | }
19 |
20 | override open func drawText(in rect: CGRect) {
21 | super.drawText(in: edgeInsets.inset(rect))
22 | }
23 |
24 | open override var intrinsicContentSize: CGSize {
25 | var size = super.intrinsicContentSize
26 | size.width += (edgeInsets.left + edgeInsets.right)
27 | size.height += (edgeInsets.top + edgeInsets.bottom)
28 | return size
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Sources/Classes/RefreshControl.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RefreshControl.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 5/7/16.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | open class RefreshControl: UIRefreshControl {
12 |
13 | override open func endRefreshing() {
14 | let scrollView = superview as? UIScrollView
15 | let scrollEnabled = scrollView?.isScrollEnabled ?? true
16 | scrollView?.isScrollEnabled = false
17 | super.endRefreshing()
18 | scrollView?.isScrollEnabled = scrollEnabled
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/Classes/SwiftUtils.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Type.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 12/30/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | typealias JSObject = [String: AnyObject]
12 | typealias JSArray = [JSObject]
13 |
14 | public enum DeviceType {
15 | case iPhone4
16 | case iPhone5
17 | case iPhone6
18 | case iPhone6p
19 | case iPhoneX
20 | case iPhoneXS
21 | case iPhoneXR
22 | case iPhoneXSMax
23 | case iPad
24 | case iPadPro105
25 | case iPadPro129
26 |
27 | public var size: CGSize {
28 | switch self {
29 | case .iPhone4: return CGSize(width: 320, height: 480)
30 | case .iPhone5: return CGSize(width: 320, height: 568)
31 | case .iPhone6: return CGSize(width: 375, height: 667)
32 | case .iPhone6p: return CGSize(width: 414, height: 736)
33 | case .iPhoneX: return CGSize(width: 375, height: 812)
34 | case .iPhoneXS: return CGSize(width: 375, height: 812)
35 | case .iPhoneXR: return CGSize(width: 414, height: 896)
36 | case .iPhoneXSMax: return CGSize(width: 414, height: 896)
37 | case .iPad: return CGSize(width: 768, height: 1024)
38 | case .iPadPro105: return CGSize(width: 834, height: 1112)
39 | case .iPadPro129: return CGSize(width: 1024, height: 1366)
40 | }
41 | }
42 | }
43 |
44 | public let kScreenSize = UIScreen.main.bounds.size
45 |
46 | public let iPhone = (UIDevice.current.userInterfaceIdiom == .phone)
47 | public let iPad = (UIDevice.current.userInterfaceIdiom == .pad)
48 |
49 | public let iPhone4 = (iPhone && DeviceType.iPhone4.size == kScreenSize)
50 | public let iPhone5 = (iPhone && DeviceType.iPhone5.size == kScreenSize)
51 | public let iPhone6 = (iPhone && DeviceType.iPhone6.size == kScreenSize)
52 | public let iPhone6p = (iPhone && DeviceType.iPhone6p.size == kScreenSize)
53 | public let iPhoneX = (iPhone && DeviceType.iPhoneX.size == kScreenSize)
54 | public let iPhoneXS = (iPhone && DeviceType.iPhoneXS.size == kScreenSize)
55 | public let iPhoneXR = (iPhone && DeviceType.iPhoneXR.size == kScreenSize)
56 | public let iPhoneXSMax = (iPhone && DeviceType.iPhoneXSMax.size == kScreenSize)
57 |
--------------------------------------------------------------------------------
/Sources/Classes/TableView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TableView.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/5/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | open class TableView: UITableView {
12 | open var allowHeaderViewsToFloat: Bool = false
13 | open var allowFooterViewsToFloat: Bool = false
14 |
15 | open func allowsHeaderViewsToFloat() -> Bool {
16 | return allowHeaderViewsToFloat
17 | }
18 |
19 | open func allowsFooterViewsToFloat() -> Bool {
20 | return allowFooterViewsToFloat
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Sources/Classes/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 12/31/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | open class ViewController: UIViewController {
12 | open fileprivate(set) var isViewDidAppear = false
13 | open fileprivate(set) var isViewFirstAppear = false
14 |
15 | public override init(nibName: String?, bundle: Bundle?) {
16 | super.init(nibName: nibName, bundle: bundle)
17 | setup()
18 | }
19 |
20 | public required init?(coder aDecoder: NSCoder) {
21 | super.init(coder: aDecoder)
22 | setup()
23 | }
24 |
25 | open func setup() {
26 | automaticallyAdjustsScrollViewInsets = false
27 | }
28 |
29 | deinit {
30 | NotificationCenter.default.removeObserver(self)
31 | }
32 |
33 | open override func viewDidLoad() {
34 | super.viewDidLoad()
35 | isViewFirstAppear = true
36 | }
37 |
38 | open override func viewDidAppear(_ animated: Bool) {
39 | super.viewDidAppear(animated)
40 | isViewDidAppear = true
41 | DispatchQueue.main.async { [weak self] in
42 | self?.isViewFirstAppear = false
43 | }
44 | }
45 |
46 | open override func viewWillDisappear(_ animated: Bool) {
47 | super.viewWillDisappear(animated)
48 | isViewDidAppear = false
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Sources/Extensions/Array.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Array.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/7/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension Array {
12 |
13 | public mutating func shuffle() {
14 | for i in (1 ..< count).reversed() {
15 | let j = Int.random(max: i - 1)
16 | swapAt(i, j)
17 | }
18 | }
19 |
20 | public func shuffled() -> [Element] {
21 | var array = self
22 | array.shuffle()
23 | return array
24 | }
25 |
26 | public func toJSONString() -> String? {
27 | guard let data = toJSONData() else {
28 | return nil
29 | }
30 | return String.init(data: data, encoding: .utf8)
31 | }
32 |
33 | public func toJSONData() -> Data? {
34 | do {
35 | let data = try JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
36 | return data
37 | } catch {
38 | return nil
39 | }
40 | }
41 | }
42 |
43 | extension Array where Element: Equatable {
44 | public mutating func remove(_ element: Element) -> Element? {
45 | guard let idx = index(of: element) else {
46 | return nil
47 | }
48 | return self.remove(at: idx)
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Sources/Extensions/Bool.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Bool.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/8/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension Bool {
12 | public func toInt() -> Int {
13 | return self ? 1 : 0
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Sources/Extensions/CGGeometry.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGPoint.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/8/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension CGPoint {
12 | public var isZero: Bool {
13 | return x == 0 && y == 0
14 | }
15 | }
16 |
17 | public prefix func - (point: CGPoint) -> CGPoint {
18 | return CGPoint(x: -point.x, y: -point.y)
19 | }
20 |
21 | public func == (lhs: CGPoint, rhs: CGPoint) -> Bool {
22 | return lhs.x == rhs.x && lhs.y == rhs.y
23 | }
24 |
25 | public func += (lhs: inout CGPoint, rhs: CGPoint) -> CGPoint {
26 | lhs.x += rhs.x
27 | lhs.y += rhs.y
28 | return lhs
29 | }
30 |
31 | public func += (lhs: inout CGPoint, rhs: CGSize) -> CGPoint {
32 | lhs.x += rhs.width
33 | lhs.y += rhs.height
34 | return lhs
35 | }
36 |
37 | public func += (lhs: inout CGPoint, rhs: CGVector) -> CGPoint {
38 | lhs.x += rhs.dx
39 | lhs.y += rhs.dy
40 | return lhs
41 | }
42 |
43 | public func += (lhs: inout CGPoint, rhs: CGFloat) -> CGPoint {
44 | lhs.x += rhs
45 | lhs.y += rhs
46 | return lhs
47 | }
48 |
49 | public func + (lhs: CGPoint, rhs: CGPoint) -> CGPoint {
50 | return CGPoint(x: lhs.x + rhs.x, y: lhs.y + rhs.y)
51 | }
52 |
53 | public func + (lhs: CGPoint, rhs: CGSize) -> CGPoint {
54 | return CGPoint(x: lhs.x + rhs.width, y: lhs.y + rhs.height)
55 | }
56 |
57 | public func + (lhs: CGPoint, rhs: CGVector) -> CGPoint {
58 | return CGPoint(x: lhs.x + rhs.dx, y: lhs.y + rhs.dy)
59 | }
60 |
61 | public func + (lhs: CGPoint, rhs: CGFloat) -> CGPoint {
62 | return CGPoint(x: lhs.x + rhs, y: lhs.y + rhs)
63 | }
64 |
65 | public func -= (lhs: inout CGPoint, rhs: CGPoint) -> CGPoint {
66 | lhs.x -= rhs.x
67 | lhs.y -= rhs.y
68 | return lhs
69 | }
70 |
71 | public func -= (lhs: inout CGPoint, rhs: CGSize) -> CGPoint {
72 | return CGPoint(x: lhs.x - rhs.width, y: lhs.y - rhs.height)
73 | }
74 |
75 | public func -= (lhs: inout CGPoint, rhs: CGVector) -> CGPoint {
76 | lhs.x -= rhs.dx
77 | lhs.y -= rhs.dy
78 | return lhs
79 | }
80 |
81 | public func -= (lhs: inout CGPoint, rhs: CGFloat) -> CGPoint {
82 | lhs.x -= rhs
83 | lhs.y -= rhs
84 | return lhs
85 | }
86 |
87 | public func - (lhs: CGPoint, rhs: CGPoint) -> CGPoint {
88 | return CGPoint(x: lhs.x - rhs.x, y: lhs.y - rhs.y)
89 | }
90 |
91 | public func - (lhs: CGPoint, rhs: CGSize) -> CGPoint {
92 | return CGPoint(x: lhs.x - rhs.width, y: lhs.y - rhs.height)
93 | }
94 |
95 | public func - (lhs: CGPoint, rhs: CGVector) -> CGPoint {
96 | return CGPoint(x: lhs.x - rhs.dx, y: lhs.y - rhs.dy)
97 | }
98 |
99 | public func - (lhs: CGPoint, rhs: CGFloat) -> CGPoint {
100 | return CGPoint(x: lhs.x - rhs, y: lhs.y - rhs)
101 | }
102 |
103 | public func *= (lhs: inout CGPoint, rhs: CGFloat) -> CGPoint {
104 | lhs.x *= rhs
105 | lhs.y *= rhs
106 | return lhs
107 | }
108 |
109 | public func * (lhs: CGPoint, rhs: CGFloat) -> CGPoint {
110 | return CGPoint(x: lhs.x * rhs, y: lhs.y * rhs)
111 | }
112 |
113 | public func /= (lhs: inout CGPoint, rhs: CGFloat) -> CGPoint {
114 | lhs.x /= rhs
115 | lhs.y /= rhs
116 | return lhs
117 | }
118 |
119 | public func / (lhs: CGPoint, rhs: CGFloat) -> CGPoint {
120 | return CGPoint(x: lhs.x / rhs, y: lhs.y / rhs)
121 | }
122 |
123 | extension CGSize {
124 | public init(size: CGFloat) {
125 | self.init(width: size, height: size)
126 | }
127 |
128 | public var isZero: Bool {
129 | return width <= 0 || height <= 0
130 | }
131 | }
132 |
133 | public func += (lhs: inout CGSize, rhs: CGSize) -> CGSize {
134 | lhs.width += rhs.width
135 | lhs.height += rhs.height
136 | return lhs
137 | }
138 |
139 | public func + (lhs: CGSize, rhs: CGSize) -> CGSize {
140 | return CGSize(width: lhs.width + rhs.width, height: lhs.height + rhs.height)
141 | }
142 |
143 | public func -= (lhs: inout CGSize, rhs: CGSize) -> CGSize {
144 | lhs.width -= rhs.width
145 | lhs.height -= rhs.height
146 | return lhs
147 | }
148 |
149 | public func - (lhs: CGSize, rhs: CGSize) -> CGSize {
150 | return CGSize(width: lhs.width - rhs.width, height: lhs.height - rhs.height)
151 | }
152 |
153 | public func *= (lhs: inout CGSize, rhs: CGFloat) -> CGSize {
154 | lhs.width *= rhs
155 | lhs.height *= rhs
156 | return lhs
157 | }
158 |
159 | public func * (lhs: CGSize, rhs: CGFloat) -> CGSize {
160 | return CGSize(width: lhs.width * rhs, height: lhs.height * rhs)
161 | }
162 |
163 | public func /= (lhs: inout CGSize, rhs: CGFloat) -> CGSize {
164 | lhs.width /= rhs
165 | lhs.height /= rhs
166 | return lhs
167 | }
168 |
169 | public func / (lhs: CGSize, rhs: CGFloat) -> CGSize {
170 | return CGSize(width: lhs.width / rhs, height: lhs.height / rhs)
171 | }
172 |
173 | extension CGVector {
174 | public var isZero: Bool {
175 | return dx == 0 && dy == 0
176 | }
177 | }
178 |
179 | public prefix func - (lhs: CGVector) -> CGVector {
180 | return CGVector(dx: -lhs.dx, dy: -lhs.dy)
181 | }
182 |
183 | public func == (lhs: CGVector, rhs: CGVector) -> Bool {
184 | return lhs.dx == rhs.dx && lhs.dy == rhs.dy
185 | }
186 |
187 | public func + (lhs: CGVector, rhs: CGVector) -> CGVector {
188 | return CGVector(dx: lhs.dx + rhs.dx, dy: lhs.dy + rhs.dy)
189 | }
190 |
191 | public func += (lhs: inout CGVector, rhs: CGVector) -> CGVector {
192 | lhs.dx += rhs.dx
193 | lhs.dy += rhs.dy
194 | return lhs
195 | }
196 |
197 | public func - (lhs: CGVector, rhs: CGVector) -> CGVector {
198 | return CGVector(dx: lhs.dx - rhs.dx, dy: lhs.dy - rhs.dy)
199 | }
200 |
201 | public func * (lhs: CGVector, rhs: CGVector) -> CGFloat {
202 | return lhs.dx * rhs.dy + lhs.dy * rhs.dx
203 | }
204 |
205 | public func * (lhs: CGVector, rhs: CGFloat) -> CGVector {
206 | return CGVector(dx: lhs.dx * rhs, dy: lhs.dy * rhs)
207 | }
208 |
209 | public func / (lhs: CGVector, rhs: CGFloat) -> CGVector {
210 | return CGVector(dx: lhs.dx / rhs, dy: lhs.dy / rhs)
211 | }
212 |
213 | public func /= (lhs: inout CGVector, rhs: CGFloat) -> CGVector {
214 | lhs.dx /= rhs
215 | lhs.dy /= rhs
216 | return lhs
217 | }
218 |
219 | extension CGRect {
220 | public var mid: CGPoint {
221 | return CGPoint(x: midX, y: midY)
222 | }
223 |
224 | public var topLeft: CGPoint {
225 | return CGPoint(x: minX, y: minY)
226 | }
227 |
228 | public var topCenter: CGPoint {
229 | return CGPoint(x: midX, y: minY)
230 | }
231 |
232 | public var topRight: CGPoint {
233 | return CGPoint(x: maxX, y: minY)
234 | }
235 |
236 | public var bottomLeft: CGPoint {
237 | return CGPoint(x: minX, y: maxY)
238 | }
239 |
240 | public var bottomCenter: CGPoint {
241 | return CGPoint(x: midX, y: maxY)
242 | }
243 |
244 | public var bottomRight: CGPoint {
245 | return CGPoint(x: maxX, y: maxY)
246 | }
247 | }
248 |
249 | public func + (lhs: CGRect, rhs: CGPoint) -> CGRect {
250 | let origin = CGPoint(x: lhs.origin.x + rhs.x, y: lhs.origin.y + rhs.y)
251 | return CGRect(origin: origin, size: lhs.size)
252 | }
253 |
254 | public func + (lhs: CGRect, rhs: CGVector) -> CGRect {
255 | let origin = CGPoint(x: lhs.origin.x + rhs.dx, y: lhs.origin.y + rhs.dy)
256 | return CGRect(origin: origin, size: lhs.size)
257 | }
258 |
259 | public func + (lhs: CGRect, rhs: CGSize) -> CGRect {
260 | let size = CGSize(width: lhs.size.width + rhs.width, height: lhs.size.height + rhs.height)
261 | return CGRect(origin: lhs.origin, size: size)
262 | }
263 |
264 | public func - (lhs: CGRect, rhs: CGPoint) -> CGRect {
265 | let origin = CGPoint(x: lhs.origin.x - rhs.x, y: lhs.origin.y - rhs.y)
266 | return CGRect(origin: origin, size: lhs.size)
267 | }
268 |
269 | public func - (lhs: CGRect, rhs: CGVector) -> CGRect {
270 | let origin = CGPoint(x: lhs.origin.x - rhs.dx, y: lhs.origin.y - rhs.dy)
271 | return CGRect(origin: origin, size: lhs.size)
272 | }
273 |
274 | public func - (lhs: CGRect, rhs: CGSize) -> CGRect {
275 | let size = CGSize(width: lhs.size.width - rhs.width, height: lhs.size.height - rhs.height)
276 | return CGRect(origin: lhs.origin, size: size)
277 | }
278 |
--------------------------------------------------------------------------------
/Sources/Extensions/Dictionary.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Dictionary.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/7/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension Dictionary {
12 | public var allKeys: [Key] {
13 | return Array(keys)
14 | }
15 |
16 | public var allValues: [Value] {
17 | return Array(values)
18 | }
19 |
20 | public mutating func updateValues(_ dic: [Key: Value]?) {
21 | if let dic = dic {
22 | for (key, value) in dic {
23 | self[key] = value
24 | }
25 | }
26 | }
27 |
28 | public func hasKey(_ key: Key) -> Bool {
29 | return index(forKey: key) != nil
30 | }
31 |
32 | public func toJSONData() -> Data? {
33 | do {
34 | return try JSONSerialization.data(withJSONObject: self, options: JSONSerialization.WritingOptions.prettyPrinted)
35 | } catch {
36 | return nil
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Sources/Extensions/Double.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Double.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/7/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension Double {
12 | public var abs: Double {
13 | return Foundation.fabs(self)
14 | }
15 |
16 | public var sqrt: Double {
17 | return Foundation.sqrt(self)
18 | }
19 |
20 | public var floor: Double {
21 | return Foundation.floor(self)
22 | }
23 |
24 | public var ceil: Double {
25 | return Foundation.ceil(self)
26 | }
27 |
28 | public var round: Double {
29 | return Foundation.round(self)
30 | }
31 |
32 | public func clamp(_ min: Double, _ max: Double) -> Double {
33 | return Swift.max(min, Swift.min(max, self))
34 | }
35 |
36 | public static func random(min: Double = 0, max: Double) -> Double {
37 | let diff = max - min
38 | let rand = Double(arc4random() % (UInt32(RAND_MAX) + 1))
39 | return ((rand / Double(RAND_MAX)) * diff) + min
40 | }
41 |
42 | public func distance(_ precision: Int = -1, meter: String = "m", kilometer: String = "km") -> String { // precision < 0: Auto
43 | var num = self
44 | var unit = meter
45 | if num > 1000.0 {
46 | unit = kilometer
47 | num /= 1000.0
48 | }
49 | if precision == -1 {
50 | if num == trunc(num) {
51 | return String(format: "%.0f%@", num, unit)
52 | } else {
53 | return String(format: "%.1f%@", num, unit)
54 | }
55 | } else {
56 | let format = "%.\(precision)f%@"
57 | return String(format: format, num, unit)
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Sources/Extensions/Float.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Float.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/7/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension Float {
12 | public var abs: Float {
13 | return Foundation.fabsf(self)
14 | }
15 |
16 | public var sqrt: Float {
17 | return Foundation.sqrt(self)
18 | }
19 |
20 | public var floor: Float {
21 | return Foundation.floor(self)
22 | }
23 |
24 | public var ceil: Float {
25 | return Foundation.ceil(self)
26 | }
27 |
28 | public var round: Float {
29 | return Foundation.round(self)
30 | }
31 |
32 | public func clamp(_ min: Float, _ max: Float) -> Float {
33 | return Swift.max(min, Swift.min(max, self))
34 | }
35 |
36 | public static func random(min: Float = 0, max: Float) -> Float {
37 | let diff = max - min
38 | let rand = Float(arc4random() % (UInt32(RAND_MAX) + 1))
39 | return ((rand / Float(RAND_MAX)) * diff) + min
40 | }
41 |
42 | public func distance(_ precision: Int = -1) -> String { // precision < 0: Auto
43 | var num = self
44 | var unit = "m"
45 | if num > 1000.0 {
46 | unit = "km"
47 | num /= 1000.0
48 | }
49 | if precision == -1 {
50 | if num == truncf(num) {
51 | return String(format: "%.0f%@", num, unit)
52 | } else {
53 | return String(format: "%.1f%@", num, unit)
54 | }
55 | } else {
56 | let format = "%.\(precision)f%@"
57 | return String(format: format, num, unit)
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Sources/Extensions/Int.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Int.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/7/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension Int {
12 | public func loop(_ block: () -> Void) {
13 | for _ in 0 ..< self {
14 | block()
15 | }
16 | }
17 |
18 | public var isEven: Bool {
19 | return (self % 2) == 0
20 | }
21 |
22 | public var isOdd: Bool {
23 | return (self % 2) == 1
24 | }
25 |
26 | public func clamp(_ range: Range) -> Int {
27 | return clamp(range.lowerBound, range.upperBound - 1)
28 | }
29 |
30 | public func clamp(_ min: Int, _ max: Int) -> Int {
31 | return Swift.max(min, Swift.min(max, self))
32 | }
33 |
34 | public var digits: [Int] {
35 | var result = [Int]()
36 | for char in String(self) {
37 | let string = String(char)
38 | if let toInt = Int(string) {
39 | result.append(toInt)
40 | }
41 | }
42 | return result
43 | }
44 |
45 | public var abs: Int {
46 | return Swift.abs(self)
47 | }
48 |
49 | public func gcd(_ num: Int) -> Int {
50 | return num == 0 ? self : num.gcd(self % num)
51 | }
52 |
53 | public func lcm(_ num: Int) -> Int {
54 | return (self * num).abs / gcd(num)
55 | }
56 |
57 | public var factorial: Int {
58 | return self == 0 ? 1 : self * (self - 1).factorial
59 | }
60 |
61 | public var ordinal: String {
62 | let suffix: [String] = ["th", "st", "nd", "rd", "th"]
63 | var index = 0
64 | if self < 11 || self > 13 {
65 | index = Swift.min(suffix.count - 1, self % 10)
66 | }
67 | return String(format: "%zd%@", self, suffix[index])
68 | }
69 |
70 | public static func random(min: Int = 0, max: Int) -> Int {
71 | return Int(arc4random_uniform(UInt32((max - min) + 1))) + min
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/Sources/Extensions/NSBundle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSBundle.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 2/27/16.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public let kCFBundleDisplayNameKey = "CFBundleDisplayName"
12 | public let kCFBundleNameKey = "CFBundleName"
13 | public let kCFBundleShortVersionKey = "CFBundleShortVersionString"
14 |
15 | extension Bundle {
16 | public var name: String {
17 | guard let info = infoDictionary else { return "" }
18 | return info[kCFBundleDisplayNameKey] as? String ?? info[kCFBundleNameKey] as? String ?? ""
19 | }
20 |
21 | public var version: String {
22 | guard let info = infoDictionary else { return "" }
23 | return info[kCFBundleShortVersionKey] as? String ?? ""
24 | }
25 |
26 | public var build: String {
27 | guard let info = infoDictionary else { return "" }
28 | return info[kCFBundleVersionKey as String] as? String ?? ""
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Sources/Extensions/NSData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSData.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 12/30/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension Data {
12 | public func toJSON() -> Any? {
13 | do {
14 | return try JSONSerialization.jsonObject(with: self, options: JSONSerialization.ReadingOptions.allowFragments)
15 | } catch {
16 | return nil
17 | }
18 | }
19 |
20 | public func toString(_ encoding: String.Encoding = String.Encoding.utf8) -> String? {
21 | return String(data: self, encoding: encoding)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Sources/Extensions/NSDate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSDate.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/7/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | private var _defaultCalendar = Calendar.current
12 |
13 | extension Calendar {
14 | public static func setDefaultCalendar(_ defaultCalendar: Calendar) {
15 | _defaultCalendar = defaultCalendar
16 | }
17 |
18 | public static func defaultCalendar() -> Calendar {
19 | return _defaultCalendar
20 | }
21 | }
22 |
23 | extension TimeZone {
24 | public static var UTC: TimeZone {
25 | return TimeZone(abbreviation: "UTC")!
26 | }
27 | }
28 |
29 | private var _defaultLocale = Locale.current
30 |
31 | extension Locale {
32 | public static func setDefaultLocale(_ defaultLocale: Locale) {
33 | _defaultLocale = defaultLocale
34 | }
35 |
36 | public static func defaultLocale() -> Locale {
37 | return _defaultLocale
38 | }
39 | }
40 |
41 | extension DateComponents {
42 |
43 | public init(year: Int, month: Int, day: Int, hour: Int = 0, minute: Int = 0, sec: Int = 0, nsec: Int = 0) {
44 | self.init()
45 | self.year = year
46 | self.month = month
47 | self.day = day
48 | self.hour = hour
49 | self.minute = minute
50 | self.second = sec
51 | self.nanosecond = nsec
52 | (self as NSDateComponents).calendar = Calendar.defaultCalendar()
53 | (self as NSDateComponents).timeZone = TimeZone.current
54 | }
55 |
56 | public init(hour: Int, minute: Int, sec: Int = 0, nsec: Int = 0) {
57 | self.init()
58 | self.year = 0
59 | self.month = 0
60 | self.day = 0
61 | self.hour = hour
62 | self.minute = minute
63 | self.second = sec
64 | self.nanosecond = nsec
65 | (self as NSDateComponents).calendar = Calendar.defaultCalendar()
66 | (self as NSDateComponents).timeZone = TimeZone.current
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Sources/Extensions/NSFileManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSFileManager.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/23/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension FileManager {
12 | public class var homeDir: String! {
13 | return NSHomeDirectory()
14 | }
15 |
16 | public class var homeUrl: URL! {
17 | return URL(fileURLWithPath: homeDir, isDirectory: true)
18 | }
19 |
20 | public class var docDir: String! {
21 | return NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
22 | }
23 |
24 | public class var docUrl: URL! {
25 | return URL(fileURLWithPath: docDir, isDirectory: true)
26 | }
27 |
28 | public class var libraryDir: String! {
29 | return NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true).first
30 | }
31 |
32 | public class var libraryUrl: URL! {
33 | return URL(fileURLWithPath: libraryDir, isDirectory: true)
34 | }
35 |
36 | public class var appSupportDir: String! {
37 | return NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).first
38 | }
39 |
40 | public class var appSupportUrl: URL! {
41 | return URL(fileURLWithPath: appSupportDir, isDirectory: true)
42 | }
43 |
44 | public class var tmpDir: String {
45 | return NSTemporaryDirectory()
46 | }
47 |
48 | public class var tmpUrl: URL {
49 | return URL(fileURLWithPath: tmpDir, isDirectory: true)
50 | }
51 |
52 | public class func skipBackup(_ path: String) -> Bool {
53 | let fileManager = `default`
54 | var isDir: ObjCBool = true
55 | if fileManager.fileExists(atPath: path, isDirectory: &isDir) {
56 | if isDir.boolValue {
57 | var success = true
58 | do {
59 | let urls = try fileManager.contentsOfDirectory(atPath: path)
60 | for url in urls {
61 | success = success && skipBackup(url)
62 | }
63 | return success
64 | } catch { }
65 | } else {
66 | do {
67 | let url = URL(fileURLWithPath: path)
68 | try (url as NSURL).setResourceValue(true, forKey: URLResourceKey.isExcludedFromBackupKey)
69 | return true
70 | } catch { }
71 | }
72 | }
73 | return false
74 | }
75 |
76 | public class func skipBackup() {
77 | _ = skipBackup(docDir)
78 | _ = skipBackup(libraryDir)
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/Sources/Extensions/NSLock.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSLock.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 12/7/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension NSLock {
12 | public func sync(_ block: () -> Void) {
13 | let locked = `try`()
14 | block()
15 | if locked {
16 | unlock()
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Sources/Extensions/NSURL.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSURL.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/7/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public enum HTTPStatus: Int {
12 | // Informational 1xx
13 | case `continue` = 100
14 | case switchingProtocols = 101
15 | case processing = 102
16 | case checkpoint = 103
17 |
18 | // Successful 2xx
19 | case success = 200
20 | case created = 201
21 | case accepted = 202
22 | case nonAuthoritativeInformation = 203
23 | case noContent = 204
24 | case resetContent = 205
25 | case partialContent = 206
26 | case multiStatus = 207
27 | case alreadyReported = 208
28 | case imUsed = 226
29 |
30 | // Redirection 3xx
31 | case multipleChoices = 300
32 | case movedPermanently = 301
33 | case found = 302
34 | case seeOther = 303
35 | case notModified = 304
36 | case useProxy = 305
37 | case switchProxy = 306
38 | case temporaryRedirect = 307
39 | case resumeIncomplete = 308
40 |
41 | // Client Error 4xx
42 | case badRequest = 400
43 | case unauthorized = 401
44 | case paymentRequired = 402
45 | case forbidden = 403
46 | case notFound = 404
47 | case methodNotAllowed = 405
48 | case notAcceptable = 406
49 | case proxyAuthenticationRequired = 407
50 | case requestTimeout = 408
51 | case conflict = 409
52 | case gone = 410
53 | case lengthRequired = 411
54 | case preconditionFailed = 412
55 | case requestEntityTooLarge = 413
56 | case requestURITooLong = 414
57 | case unsupportedMediaType = 415
58 | case requestedRangeNotSatisfiable = 416
59 | case expectationFailed = 417
60 | case imATeapot = 418
61 | case authenticationTimeout = 419
62 | case enhanceYourCalm = 420
63 | case misdirectedRequest = 421
64 | case unprocessableEntity = 422
65 | case locked = 423
66 | case failedDependency = 424
67 | case upgradeRequired = 426
68 | case preconditionRequired = 428
69 | case tooManyRequests = 429
70 | case requestHeaderFieldsTooLarge = 431
71 | case loginTimeout = 440
72 | case noResponse = 444
73 | case retryWith = 449
74 | case blockedByWindowsParentalControls = 450
75 | case wrongExchangeServer = 451
76 | case requestHeaderTooLarge = 494
77 | case certError = 495
78 | case noCert = 496
79 | case httPtoHTTPS = 497
80 | case tokenExpiredOrInvalid = 498
81 | case cientClosedRequest = 499
82 |
83 | // Server Error 5xx
84 | case internalServerError = 500
85 | case notImplemented = 501
86 | case badGateway = 502
87 | case serviceUnavailable = 503
88 | case gatewayTimeout = 504
89 | case httpVersionNotSupported = 505
90 | case variantAlsoNegotiates = 506
91 | case insufficientStorage = 507
92 | case loopDetected = 508
93 | case bandwidthLimitExceeded = 509
94 | case notExtended = 510
95 | case networkAuthenticationRequired = 511
96 | case networkReadTimeout = 598
97 | case networkConnectTimeout = 599
98 |
99 | public init?(code: Int) {
100 | self.init(rawValue: code)
101 | }
102 |
103 | public var code: Int {
104 | return rawValue
105 | }
106 | }
107 |
108 | extension HTTPStatus: CustomStringConvertible {
109 | public var description: String {
110 | switch self {
111 | case .continue: // 100
112 | return "The server has received the request headers, and the client should proceed to send the request body."
113 | case .switchingProtocols: // 101
114 | return "The requester has asked the server to switch protocols."
115 | case .processing:
116 | return "Server has received and is processing the request."
117 | case .checkpoint: // 103
118 | return "Used in the resumable requests proposal to resume aborted PUT or POST requests."
119 | case .success: // 200
120 | return "The request is OK."
121 | case .created: // 201
122 | return "The request has been fulfilled, and a new resource is created ."
123 | case .accepted: // 202
124 | return "The request has been accepted for processing, but the processing has not been completed."
125 | case .nonAuthoritativeInformation: // 203
126 | return "The request has been successfully processed, but is returning information that may be from another source."
127 | case .noContent: // 204
128 | return "The request has been successfully processed, but is not returning any content."
129 | case .resetContent: // 205
130 | return "The request has been successfully processed, but is not returning any content, and requires that the requester reset the document view."
131 | case .partialContent: // 206
132 | return "The server is delivering only part of the resource due to a range header sent by the client."
133 | case .multiStatus: // 207
134 | return "XML, can contain multiple separate responses."
135 | case .alreadyReported: // 208
136 | return "Results previously returned."
137 | case .imUsed: // 226
138 | return "Request fulfilled, reponse is instance-manipulations."
139 | case .multipleChoices: // 300
140 | return "A link list. The user can select a link and go to that location. Maximum five addresses."
141 | case .movedPermanently: // 301
142 | return "The requested page has moved to a new URL."
143 | case .found: // 302
144 | return "The requested page has moved temporarily to a new URL."
145 | case .seeOther: // 303
146 | return "The requested page can be found under a different URL."
147 | case .notModified: // 304
148 | return "Indicates the requested page has not been modified since last requested."
149 | case .useProxy: // 305
150 | return "The requested resource must be accessed through the proxy given by the Location field."
151 | case .switchProxy: // 306
152 | return "No longer used."
153 | case .temporaryRedirect: // 307
154 | return "The requested page has moved temporarily to a new URL"
155 | case .resumeIncomplete: // 308
156 | return "Used in the resumable requests proposal to resume aborted PUT or POST requests."
157 | case .badRequest: // 400
158 | return "The request cannot be fulfilled due to bad syntax."
159 | case .unauthorized: // 401
160 | return "The request was a legal request, but the server is refusing to respond to it. For use when authentication is possible but has failed or not yet been provided."
161 | case .paymentRequired: // 402
162 | return "Reserved for future use."
163 | case .forbidden: // 403
164 | return "The request was a legal request, but the server is refusing to respond to it."
165 | case .notFound: // 404
166 | return "The requested page could not be found but may be available again in the future."
167 | case .methodNotAllowed: // 405
168 | return "A request was made of a page using a request method not supported by that page."
169 | case .notAcceptable: // 406
170 | return "The server can only generate a response that is not accepted by the client."
171 | case .proxyAuthenticationRequired: // 407
172 | return "The client must first authenticate itself with the proxy."
173 | case .requestTimeout: // 408
174 | return "The server timed out waiting for the request."
175 | case .conflict: // 409
176 | return "The request could not be completed because of a conflict in the request."
177 | case .gone: // 410
178 | return "The requested page is no longer available."
179 | case .lengthRequired: // 411
180 | return "The \"Content-Length\" is not defined. The server will not accept the request without it."
181 | case .preconditionFailed: // 412
182 | return "The precondition given in the request evaluated to false by the server."
183 | case .requestEntityTooLarge: // 413
184 | return "The server will not accept the request, because the request entity is too large."
185 | case .requestURITooLong: // 414
186 | return "The server will not accept the request, because the URL is too long. Occurs when you convert a POST request to a GET request with a long query information."
187 | case .unsupportedMediaType: // 415
188 | return "The server will not accept the request, because the media type is not supported."
189 | case .requestedRangeNotSatisfiable: // 416
190 | return "The client has asked for a portion of the file, but the server cannot supply that portion."
191 | case .expectationFailed: // 417
192 | return "The server cannot meet the requirements of the Expect request-header field."
193 | case .imATeapot: // 418
194 | return "I'm a teapot"
195 | case .authenticationTimeout: // 419
196 | return "Previously valid authentication has expired."
197 | case .enhanceYourCalm: // 420
198 | return "Twitter rate limiting."
199 | case .misdirectedRequest: // 421
200 | return "The request was directed at a server that is not able to produce a response."
201 | case .unprocessableEntity: // 422
202 | return "Request unable to be followed due to semantic errors."
203 | case .locked: // 423
204 | return "The resource that is being accessed is locked."
205 | case .failedDependency: // 424
206 | return "The request failed due to failure of a previous request."
207 | case .upgradeRequired: // 426
208 | return "The client should switch to a different protocol."
209 | case .preconditionRequired: // 428
210 | return "The origin server requires the request to be conditional."
211 | case .tooManyRequests: // 429
212 | return "The user has sent too many requests in a given amount of time."
213 | case .requestHeaderFieldsTooLarge: // 431
214 | return "Server is unwilling to process the request."
215 | case .loginTimeout: // 440
216 | return "Your session has expired."
217 | case .noResponse: // 444
218 | return "Server returns no information and closes the connection."
219 | case .retryWith: // 449
220 | return "Request should be retried after performing action."
221 | case .blockedByWindowsParentalControls: // 450
222 | return "Windows Parental Controls blocking access to webpage."
223 | case .wrongExchangeServer: // 451
224 | return "Resource access is denied for legal reasons."
225 | case .requestHeaderTooLarge: // 494
226 | return "Server is unwilling to process the request."
227 | case .certError: // 495
228 | return "SSL client certificate error occurred to distinguish it from 4XX in a log and an error page redirection."
229 | case .noCert: // 496
230 | return "Client didn't provide certificate to distinguish it from 4XX in a log and an error page redirection."
231 | case .httPtoHTTPS: // 497
232 | return "The plain HTTP requests are sent to HTTPS port to distinguish it from 4XX in a log and an error page redirection."
233 | case .tokenExpiredOrInvalid: // 498
234 | return "An expired or otherwise invalid token."
235 | case .cientClosedRequest: // 499
236 | return "Connection closed by client while HTTP server is processing."
237 | case .internalServerError: // 500
238 | return "A generic error message, given when no more specific message is suitable."
239 | case .notImplemented: // 501
240 | return "The server either does not recognize the request method, or it lacks the ability to fulfill the request."
241 | case .badGateway: // 502
242 | return "The server was acting as a gateway or proxy and received an invalid response from the upstream server."
243 | case .serviceUnavailable: // 503
244 | return "The server is currently unavailable (overloaded or down)."
245 | case .gatewayTimeout: // 504
246 | return "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server."
247 | case .httpVersionNotSupported: // 505
248 | return "The server does not support the HTTP protocol version used in the request."
249 | case .variantAlsoNegotiates: // 506
250 | return "Transparent content negotiation for the request results in a circular reference."
251 | case .insufficientStorage: // 507
252 | return "The server is unable to store the representation needed to complete the request."
253 | case .loopDetected: // 508
254 | return "The server detected an infinite loop while processing the request."
255 | case .bandwidthLimitExceeded: // 509
256 | return "Server reached the bandwidth limit that the system administrator imposed."
257 | case .notExtended: // 510
258 | return "Further extensions to the request are required for the server to fulfil it."
259 | case .networkAuthenticationRequired: // 511
260 | return "The client needs to authenticate to gain network access."
261 | case .networkReadTimeout: // 598
262 | return "Network read timeout behind the proxy."
263 | case .networkConnectTimeout: // 599
264 | return "Network connect timeout behind the proxy."
265 | }
266 | }
267 | }
268 |
269 | extension NSError {
270 | public convenience init(domain: String? = nil, status: HTTPStatus, message: String? = nil) {
271 | let domain = domain ?? Bundle.main.bundleIdentifier ?? ""
272 | let userInfo: [String: String] = [NSLocalizedDescriptionKey: message ?? status.description]
273 | self.init(domain: domain, code: status.code, userInfo: userInfo)
274 | }
275 |
276 | public convenience init(domain: String? = nil, code: Int = -999, message: String) {
277 | let domain = domain ?? Bundle.main.bundleIdentifier ?? ""
278 | let userInfo: [String: String] = [NSLocalizedDescriptionKey: message]
279 | self.init(domain: domain, code: code, userInfo: userInfo)
280 | }
281 | }
282 |
283 | extension URL {
284 | public var imageRequest: NSMutableURLRequest {
285 | let request = NSMutableURLRequest(url: self)
286 | request.addValue("image/*", forHTTPHeaderField: "Accept")
287 | return request
288 | }
289 | }
290 |
--------------------------------------------------------------------------------
/Sources/Extensions/Range.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Range.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/9/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension Range {
12 | public static func random(from min: Int, to max: Int) -> ClosedRange {
13 | let lowerBound = Int.random(min: min, max: max)
14 | let upperBound = Int.random(min: lowerBound, max: max)
15 | return lowerBound ... upperBound
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Sources/Extensions/Regex.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Regex.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/9/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension NSRegularExpression {
12 | public class func regex(_ pattern: String, ignoreCase: Bool = false) -> NSRegularExpression? {
13 | let options: NSRegularExpression.Options = ignoreCase ? [.caseInsensitive]: []
14 | let regex: NSRegularExpression?
15 | do {
16 | regex = try NSRegularExpression(pattern: pattern, options: options)
17 | } catch {
18 | regex = nil
19 | }
20 | return regex
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Sources/Extensions/String.swift:
--------------------------------------------------------------------------------
1 | //
2 | // String.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/7/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension String {
12 |
13 | public subscript(idx: Int) -> String? {
14 | guard idx >= 0 && idx < count else { return nil }
15 | return String(self[index(startIndex, offsetBy: idx)])
16 | }
17 |
18 | public subscript(idx: Int) -> Character? {
19 | guard idx >= 0 && idx < count else { return nil }
20 | return self[index(startIndex, offsetBy: idx)]
21 | }
22 |
23 | public subscript(range: Range) -> String? {
24 | let lowerIndex = index(startIndex, offsetBy: max(0, range.lowerBound), limitedBy: endIndex) ?? endIndex
25 | let higherIndex = index(lowerIndex, offsetBy: range.upperBound - range.lowerBound, limitedBy: endIndex) ?? endIndex
26 | return String(self[lowerIndex..) -> String {
30 | let lowerIndex = index(startIndex, offsetBy: max(0, range.lowerBound), limitedBy: endIndex) ?? endIndex
31 | let higherIndex = index(lowerIndex, offsetBy: range.upperBound - range.lowerBound + 1, limitedBy: endIndex) ?? endIndex
32 | return String(self[lowerIndex.. [NSTextCheckingResult]? {
42 | if let regex = NSRegularExpression.regex(pattern, ignoreCase: ignoreCase) {
43 | let range = NSRange(location: 0, length: length)
44 | return regex.matches(in: self, options: [], range: range).map { $0 }
45 | }
46 | return nil
47 | }
48 |
49 | public func contains(_ pattern: String, ignoreCase: Bool) -> Bool {
50 | guard let regex = NSRegularExpression.regex(pattern, ignoreCase: ignoreCase) else {
51 | return false
52 | }
53 | let range = NSRange(location: 0, length: count)
54 | return regex.firstMatch(in: self, options: [], range: range) != nil
55 | }
56 |
57 | public func replace(_ pattern: String, withString replacementString: String, ignoreCase: Bool = false) -> String? {
58 | if let regex = NSRegularExpression.regex(pattern, ignoreCase: ignoreCase) {
59 | let range = NSRange(location: 0, length: count)
60 | return regex.stringByReplacingMatches(in: self, options: [], range: range, withTemplate: replacementString)
61 | }
62 | return nil
63 | }
64 |
65 | public func insert(_ index: Int, _ string: String) -> String {
66 | if index > length {
67 | return self + string
68 | } else if index < 0 {
69 | return string + self
70 | }
71 | return self[0 ..< index]! + string + self[index ..< length]!
72 | }
73 |
74 | public func trimmedLeft(characterSet set: CharacterSet = CharacterSet.whitespacesAndNewlines) -> String {
75 | if let range = rangeOfCharacter(from: set.inverted) {
76 | return String(self[range.lowerBound ..< endIndex])
77 | }
78 | return ""
79 | }
80 |
81 | public func trimmedRight(characterSet set: CharacterSet = CharacterSet.whitespacesAndNewlines) -> String {
82 | if let range = rangeOfCharacter(from: set.inverted, options: NSString.CompareOptions.backwards) {
83 | return String(self[startIndex ..< range.upperBound])
84 | }
85 | return ""
86 | }
87 |
88 | public func trimmed(characterSet set: CharacterSet = CharacterSet.whitespacesAndNewlines) -> String {
89 | return trimmedLeft(characterSet: set).trimmedRight(characterSet: set)
90 | }
91 |
92 | public func trimmedLeftCJK() -> String {
93 | var text = self
94 | while text.first == Character("\n") || text.first == Character(" ") {
95 | text.removeFirst(1)
96 | }
97 | return text
98 | }
99 |
100 | public func trimmedRightCJK() -> String {
101 | var text = self
102 | while text.last == Character("\n") || text.last == Character(" ") {
103 | text.removeLast(1)
104 | }
105 | return text
106 | }
107 |
108 | public func trimmedCJK() -> String {
109 | return trimmedLeftCJK().trimmedRightCJK()
110 | }
111 |
112 | public static func random(length len: Int = 0, charset: String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") -> String {
113 | let len = len < 1 ? len : Int.random(max: 16)
114 | var result = String()
115 | let max = charset.length - 1
116 | for _ in 0 ..< len {
117 | result += String(charset[Int.random(min: 0, max: max)]!)
118 | }
119 | return result
120 | }
121 |
122 | public var intValue: Int {
123 | return Int(self) ?? 0
124 | }
125 |
126 | public var doubleValue: Double {
127 | return Double(self) ?? 0.0
128 | }
129 |
130 | public var floatValue: Float {
131 | return Float(self) ?? 0.0
132 | }
133 |
134 | public var boolValue: Bool {
135 | return (self as NSString).boolValue
136 | }
137 |
138 | public func replaceKeysByValues(_ values: [String: AnyObject]) -> String {
139 | let str: NSMutableString = NSMutableString(string: self)
140 | let range = NSRange(location: 0, length: str.length)
141 | for (key, value) in values {
142 | str.replaceOccurrences(of: key, with: "\(value)", options: [.caseInsensitive, .literal], range: range)
143 | }
144 | return str as NSString as String
145 | }
146 |
147 | public func appending(path: String) -> String {
148 | let set = CharacterSet(charactersIn: "/")
149 | let left = trimmedRight(characterSet: set)
150 | let right = path.trimmed(characterSet: set)
151 | return left + "/" + right
152 | }
153 |
154 | /// The file-system path components of the receiver. (read-only)
155 | public var pathComponents: [String] {
156 | return (self as NSString).pathComponents
157 | }
158 |
159 | /// The last path component of the receiver. (read-only)
160 | public var lastPathComponent: String {
161 | return (self as NSString).lastPathComponent
162 | }
163 |
164 | /// The path extension, if any, of the string as interpreted as a path. (read-only)
165 | public var pathExtension: String {
166 | return (self as NSString).pathExtension
167 | }
168 |
169 | /// Initializes an NSURL object with a provided URL string. (read-only)
170 | public var url: URL? {
171 | return URL(string: self)
172 | }
173 |
174 | /// The host, conforming to RFC 1808. (read-only)
175 | public var host: String {
176 | if let url = url, let host = url.host {
177 | return host
178 | }
179 | return ""
180 | }
181 |
182 | // Returns a localized string, using the main bundle.
183 |
184 | public func localized(_ comment: String = "") -> String {
185 | return NSLocalizedString(self, comment: comment)
186 | }
187 |
188 | /// Returns data with NSUTF8StringEncoding
189 |
190 | public func toData() -> Data! {
191 | return data(using: String.Encoding.utf8)
192 | }
193 |
194 | // MARK: Validation
195 | public struct Regex {
196 | public static let Number = "^(?:|0|[1-9]\\d*)(?:\\.\\d*)?$"
197 | public static let Name = "[a-zA-Z\\s]+"
198 | public static let Email1 = ".+@([A-Za-z0-9]+\\.)+[A-Za-z]{2}[A-Za-z]*"
199 | public static let Email2 = "[A-Z0-9a-z\\._%+-]+@([A-Za-z0-9-]+\\.)+[A-Za-z]{2,4}"
200 | public static let Password = "[a-zA-Z0-9_]+"
201 | public static let URL = "(http|https)://((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+"
202 | }
203 |
204 | public func validate(_ regex: String) -> Bool {
205 | let pre = NSPredicate(format: "SELF MATCHES %@", regex)
206 | return pre.evaluate(with: self)
207 | }
208 | }
209 |
210 | extension Character {
211 | public var intValue: Int {
212 | return (String(self) as NSString).integerValue
213 | }
214 | }
215 |
216 | extension NSMutableAttributedString {
217 | public func append(string: String, attributes: [NSAttributedString.Key: Any]) {
218 | let str = NSMutableAttributedString(string: string, attributes: attributes)
219 | append(str)
220 | }
221 | }
222 |
223 | extension NSMutableParagraphStyle {
224 | public class func defaultStyle() -> NSMutableParagraphStyle! {
225 | let style = NSMutableParagraphStyle()
226 | let defaultStyle = NSParagraphStyle.default
227 | style.lineSpacing = defaultStyle.lineSpacing
228 | style.paragraphSpacing = defaultStyle.paragraphSpacing
229 | style.alignment = defaultStyle.alignment
230 | style.firstLineHeadIndent = defaultStyle.firstLineHeadIndent
231 | style.headIndent = defaultStyle.headIndent
232 | style.tailIndent = defaultStyle.tailIndent
233 | style.lineBreakMode = defaultStyle.lineBreakMode
234 | style.minimumLineHeight = defaultStyle.minimumLineHeight
235 | style.maximumLineHeight = defaultStyle.maximumLineHeight
236 | style.baseWritingDirection = defaultStyle.baseWritingDirection
237 | style.lineHeightMultiple = defaultStyle.lineHeightMultiple
238 | style.paragraphSpacingBefore = defaultStyle.paragraphSpacingBefore
239 | style.hyphenationFactor = defaultStyle.hyphenationFactor
240 | style.tabStops = defaultStyle.tabStops
241 | style.defaultTabInterval = defaultStyle.defaultTabInterval
242 | return style
243 | }
244 | }
245 |
--------------------------------------------------------------------------------
/Sources/Extensions/UICollectionView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UICollectionView.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/22/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UICollectionView {
12 | open func register(_ aClass: T.Type) {
13 | let name = String(describing: aClass)
14 | let bundle = Bundle.main
15 | if bundle.path(forResource: name, ofType: "nib") != nil {
16 | let nib = UINib(nibName: name, bundle: bundle)
17 | register(nib, forCellWithReuseIdentifier: name)
18 | } else {
19 | register(aClass, forCellWithReuseIdentifier: name)
20 | }
21 | }
22 |
23 | open func register(header aClass: T.Type) {
24 | let name = String(describing: aClass)
25 | let kind = UICollectionView.elementKindSectionHeader
26 | let bundle = Bundle.main
27 | if bundle.path(forResource: name, ofType: "nib") != nil {
28 | let nib = UINib(nibName: name, bundle: bundle)
29 | register(nib, forSupplementaryViewOfKind: kind, withReuseIdentifier: name)
30 | } else {
31 | register(aClass, forSupplementaryViewOfKind: kind, withReuseIdentifier: name)
32 | }
33 | }
34 |
35 | open func register(footer aClass: T.Type) {
36 | let name = String(describing: aClass)
37 | let kind = UICollectionView.elementKindSectionFooter
38 | let bundle = Bundle.main
39 | if bundle.path(forResource: name, ofType: "nib") != nil {
40 | let nib = UINib(nibName: name, bundle: bundle)
41 | register(nib, forSupplementaryViewOfKind: kind, withReuseIdentifier: name)
42 | } else {
43 | register(aClass, forSupplementaryViewOfKind: kind, withReuseIdentifier: name)
44 | }
45 | }
46 |
47 | open func dequeue(_ aClass: T.Type, forIndexPath indexPath: IndexPath) -> T {
48 | let name = String(describing: aClass)
49 | guard let cell = dequeueReusableCell(withReuseIdentifier: name, for: indexPath) as? T else {
50 | fatalError("\(name) is not registed")
51 | }
52 | return cell
53 | }
54 |
55 | open func dequeue(header aClass: T.Type, forIndexPath indexPath: IndexPath) -> T {
56 | let name = String(describing: aClass)
57 | guard let cell = dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: name, for: indexPath) as? T else {
58 | fatalError("\(name) is not registed")
59 | }
60 | return cell
61 | }
62 |
63 | open func dequeue(footer aClass: T.Type, forIndexPath indexPath: IndexPath) -> T {
64 | let name = String(describing: aClass)
65 | guard let cell = dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: name, for: indexPath) as? T else {
66 | fatalError("\(name) is not registed")
67 | }
68 | return cell
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Sources/Extensions/UIColor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/7/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIColor {
12 | public class func RGB(_ red: Int, _ green: Int, _ blue: Int, _ alpha: CGFloat = 1) -> UIColor {
13 | let red = max(0.0, min(CGFloat(red) / 255.0, 1.0))
14 | let green = max(0.0, min(CGFloat(green) / 255.0, 1.0))
15 | let blue = max(0.0, min(CGFloat(blue) / 255.0, 1.0))
16 | let alpha = max(0.0, min(alpha, 1.0))
17 | return UIColor(red: red, green: green, blue: blue, alpha: alpha)
18 | }
19 |
20 | public func image(_ size: CGSize = CGSize(width: 1, height: 1)) -> UIImage {
21 | UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale)
22 | let ctx = UIGraphicsGetCurrentContext()
23 | setFill()
24 | ctx?.fillPath()
25 | let img = UIGraphicsGetImageFromCurrentImageContext()
26 | UIGraphicsEndImageContext()
27 | return img!
28 | }
29 | }
30 |
31 | public func == (lhs: UIColor, rhs: UIColor) -> Bool {
32 | return lhs.isEqual(rhs)
33 | }
34 |
--------------------------------------------------------------------------------
/Sources/Extensions/UIGeometry.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIEdgeInsets.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/7/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIEdgeInsets {
12 | public init(inset: CGFloat) {
13 | self.init(top: inset, left: inset, bottom: inset, right: inset)
14 | }
15 |
16 | public var inverse: UIEdgeInsets {
17 | return UIEdgeInsets(top: -top, left: -left, bottom: -bottom, right: -right)
18 | }
19 |
20 | public func inset(_ rect: CGRect) -> CGRect {
21 | return rect.inset(by: self)
22 | }
23 |
24 | public var isZero: Bool {
25 | return top == 0 && left == 0 && bottom == 0 && right == 0
26 | }
27 | }
28 |
29 | public func + (lhs: UIEdgeInsets, rhs: CGFloat) -> UIEdgeInsets {
30 | var insets = lhs
31 | insets.top += rhs
32 | insets.left += rhs
33 | insets.bottom += rhs
34 | insets.right += rhs
35 | return insets
36 | }
37 |
38 | public func - (lhs: UIEdgeInsets, rhs: CGFloat) -> UIEdgeInsets {
39 | var insets = lhs
40 | insets.top -= rhs
41 | insets.left -= rhs
42 | insets.bottom -= rhs
43 | insets.right -= rhs
44 | return insets
45 | }
46 |
47 | public func * (lhs: UIEdgeInsets, rhs: CGFloat) -> UIEdgeInsets {
48 | var insets = lhs
49 | insets.top *= rhs
50 | insets.left *= rhs
51 | insets.bottom *= rhs
52 | insets.right *= rhs
53 | return insets
54 | }
55 |
56 | public func / (lhs: UIEdgeInsets, rhs: CGFloat) -> UIEdgeInsets {
57 | var insets = lhs
58 | insets.top /= rhs
59 | insets.left /= rhs
60 | insets.bottom /= rhs
61 | insets.right /= rhs
62 | return insets
63 | }
64 |
65 | public func += (lhs: inout UIEdgeInsets, rhs: CGFloat) -> UIEdgeInsets {
66 | lhs.top += rhs
67 | lhs.left += rhs
68 | lhs.bottom += rhs
69 | lhs.right += rhs
70 | return lhs
71 | }
72 |
73 | public func -= (lhs: inout UIEdgeInsets, rhs: CGFloat) -> UIEdgeInsets {
74 | lhs.top -= rhs
75 | lhs.left -= rhs
76 | lhs.bottom -= rhs
77 | lhs.right -= rhs
78 | return lhs
79 | }
80 |
81 | public func *= (lhs: inout UIEdgeInsets, rhs: CGFloat) -> UIEdgeInsets {
82 | lhs.top *= rhs
83 | lhs.left *= rhs
84 | lhs.bottom *= rhs
85 | lhs.right *= rhs
86 | return lhs
87 | }
88 |
89 | public func /= (lhs: inout UIEdgeInsets, rhs: CGFloat) -> UIEdgeInsets {
90 | lhs.top /= rhs
91 | lhs.left /= rhs
92 | lhs.bottom /= rhs
93 | lhs.right /= rhs
94 | return lhs
95 | }
96 |
--------------------------------------------------------------------------------
/Sources/Extensions/UIImage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/23/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIImage {
12 | public func scaleToSize(_ newSize: CGSize, aspectFill: Bool = false) -> UIImage {
13 | let scaleFactorWidth = newSize.width / size.width
14 | let scaleFactorHeight = newSize.height / size.height
15 | let scaleFactor = aspectFill ? max(scaleFactorWidth, scaleFactorHeight) : min(scaleFactorWidth, scaleFactorHeight)
16 |
17 | var scaledSize = size
18 | scaledSize.width *= scaleFactor
19 | scaledSize.height *= scaleFactor
20 |
21 | UIGraphicsBeginImageContextWithOptions(scaledSize, false, UIScreen.main.scale)
22 | let scaledImageRect = CGRect(x: 0.0, y: 0.0, width: scaledSize.width, height: scaledSize.height)
23 | draw(in: scaledImageRect)
24 | let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
25 | UIGraphicsEndImageContext()
26 |
27 | return scaledImage!
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Sources/Extensions/UILayoutPriority.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UILayoutPriority.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/7/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UILayoutPriority {
12 | public static var Required: Float { return 1000.0 }
13 | public static var DefaultHigh: Float { return 750.0 }
14 | public static var FittingSizeLevel: Float { return 500.0 }
15 | public static var DefaultLow: Float { return 250.0 }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/Extensions/UITableView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UITableView.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/7/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UITableView {
12 | override open var delaysContentTouches: Bool {
13 | didSet {
14 | for view in subviews {
15 | if let scroll = view as? UIScrollView {
16 | scroll.delaysContentTouches = delaysContentTouches
17 | }
18 | break
19 | }
20 | }
21 | }
22 |
23 | public func setSeparatorInsets(_ insets: UIEdgeInsets) {
24 | separatorInset = insets
25 | layoutMargins = insets
26 | }
27 |
28 | public func scrollsToBottom(_ animated: Bool) {
29 | let section = numberOfSections - 1
30 | let row = numberOfRows(inSection: section) - 1
31 | if section < 0 || row < 0 {
32 | return
33 | }
34 | let path = IndexPath(row: row, section: section)
35 | let offset = contentOffset.y
36 | scrollToRow(at: path, at: .top, animated: animated)
37 | let delay = (animated ? 0.2 : 0.0) * Double(NSEC_PER_SEC)
38 | let time = DispatchTime.now() + Double(Int64(delay)) / Double(NSEC_PER_SEC)
39 | DispatchQueue.main.asyncAfter(deadline: time, execute: { () -> Void in
40 | if self.contentOffset.y != offset {
41 | self.scrollsToBottom(false)
42 | }
43 | })
44 | }
45 |
46 | public func register(_ aClass: T.Type) {
47 | let name = String(describing: aClass)
48 | let bundle = Bundle.main
49 | if bundle.path(forResource: name, ofType: "nib") != nil {
50 | let nib = UINib(nibName: name, bundle: bundle)
51 | register(nib, forCellReuseIdentifier: name)
52 | } else {
53 | register(aClass, forCellReuseIdentifier: name)
54 | }
55 | }
56 |
57 | public func register(_ aClass: T.Type) {
58 | let name = String(describing: aClass)
59 | let bundle = Bundle.main
60 | if bundle.path(forResource: name, ofType: "nib") != nil {
61 | let nib = UINib(nibName: name, bundle: bundle)
62 | register(nib, forHeaderFooterViewReuseIdentifier: name)
63 | } else {
64 | register(aClass, forHeaderFooterViewReuseIdentifier: name)
65 | }
66 | }
67 |
68 | public func dequeue(_ aClass: T.Type) -> T {
69 | let name = String(describing: aClass)
70 | guard let cell = dequeueReusableCell(withIdentifier: name) as? T else {
71 | fatalError("`\(name)` is not registed")
72 | }
73 | return cell
74 | }
75 |
76 | public func dequeue(_ aClass: T.Type) -> T {
77 | let name = String(describing: aClass)
78 | guard let cell = dequeueReusableHeaderFooterView(withIdentifier: name) as? T else {
79 | fatalError("`\(name)` is not registed")
80 | }
81 | return cell
82 | }
83 | }
84 |
85 | extension UITableViewCell {
86 | public func setSeparatorInsets(_ insets: UIEdgeInsets) {
87 | separatorInset = insets
88 | layoutMargins = insets
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/Sources/Extensions/UIView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/7/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | open class IntrinsicContentView: UIView {
12 | open var intrinsicContentSizeEnabled = true
13 | }
14 |
15 | extension UIView {
16 | public class func nib() -> UINib {
17 | return UINib(nibName: String(describing: self), bundle: nil)
18 | }
19 |
20 | public class func loadNib() -> T {
21 | let name = String(describing: self)
22 | let bundle = Bundle(for: T.self)
23 | guard let xib = bundle.loadNibNamed(name, owner: nil, options: nil)?.first as? T else {
24 | fatalError("Cannot load nib named `\(name)`")
25 | }
26 | return xib
27 | }
28 | }
29 |
30 | // MARK: Appearance
31 | extension UIView {
32 | public func clearSubViews() {
33 | backgroundColor = UIColor.clear
34 | for sub in subviews {
35 | sub.clearSubViews()
36 | }
37 | }
38 |
39 | public func border(color: UIColor, width: CGFloat) {
40 | layer.borderColor = color.cgColor
41 | layer.borderWidth = width
42 | layer.cornerRadius = corner
43 | layer.masksToBounds = true
44 | }
45 |
46 | public var corner: CGFloat {
47 | set {
48 | layer.cornerRadius = newValue
49 | layer.masksToBounds = true
50 | }
51 | get {
52 | return layer.cornerRadius
53 | }
54 | }
55 |
56 | public func circle() {
57 | layer.cornerRadius = min(bounds.width, bounds.height) / 2
58 | layer.masksToBounds = true
59 | }
60 |
61 | public enum BorderPostition {
62 | case top
63 | case left
64 | case bottom
65 | case right
66 | }
67 |
68 | public func border(_ pos: BorderPostition, color: UIColor = UIColor.black, width: CGFloat = 0.5, insets: UIEdgeInsets = UIEdgeInsets.zero) {
69 | let rect: CGRect = {
70 | switch pos {
71 | case .top: return CGRect(x: 0, y: 0, width: frame.width, height: width)
72 | case .left: return CGRect(x: 0, y: 0, width: width, height: frame.height)
73 | case .bottom: return CGRect(x: 0, y: frame.height - width, width: frame.width, height: width)
74 | case .right: return CGRect(x: frame.width - width, y: 0, width: width, height: frame.height)
75 | }
76 | }()
77 | let border = UIView(frame: rect)
78 | border.backgroundColor = color
79 | border.autoresizingMask = {
80 | switch pos {
81 | case .top: return [.flexibleWidth, .flexibleBottomMargin]
82 | case .left: return [.flexibleHeight, .flexibleRightMargin]
83 | case .bottom: return [.flexibleWidth, .flexibleTopMargin]
84 | case .right: return [.flexibleHeight, .flexibleLeftMargin]
85 | }
86 | }()
87 | addSubview(border)
88 | }
89 |
90 | public func shadow(color: UIColor, offset: CGSize = CGSize(width: 0, height: 0), opacity: Float = 1.0, radius: CGFloat = 3.0) {
91 | layer.shadowColor = color.cgColor
92 | layer.shadowOffset = offset
93 | layer.shadowOpacity = opacity
94 | layer.shadowRadius = radius
95 | layer.shouldRasterize = true
96 | layer.rasterizationScale = UIScreen.main.scale
97 | }
98 | }
99 |
100 | // MARK: Layout
101 | extension UIView {
102 | public func removeSubviewsConstraints() {
103 | removeConstraints(constraints.filter({ (constraint: NSLayoutConstraint) -> Bool in
104 | let first = constraint.firstItem as? UIView
105 | let second = constraint.secondItem as? UIView
106 | if (first == self && second == self) || (first == self && second == nil) || (first == nil && second == self) {
107 | return false
108 | }
109 | return true
110 | }))
111 | for sub in subviews {
112 | sub.translatesAutoresizingMaskIntoConstraints = false
113 | sub.removeAllConstraints()
114 | }
115 | }
116 |
117 | public func removeAllConstraints() {
118 | if let view = self as? IntrinsicContentView {
119 | if view.intrinsicContentSizeEnabled {
120 | return
121 | }
122 | }
123 | var parent = superview
124 | while parent != nil {
125 | for constraint in parent!.constraints {
126 | let first = constraint.firstItem as? UIView
127 | let second = constraint.secondItem as? UIView
128 | if first == self || second == self {
129 | parent!.removeConstraint(constraint)
130 | }
131 | }
132 | parent = parent!.superview
133 | }
134 | removeConstraints(constraints)
135 | let subviews = self.subviews
136 | for sub in subviews {
137 | sub.removeAllConstraints()
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/Sources/Extensions/UIViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 10/7/15.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIViewController {
12 | @objc open class func vc() -> Self {
13 | return self.init(nibName: String(describing: self), bundle: nil)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Sources/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 4.2
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/SwiftUtils.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'SwiftUtils'
3 | s.version = '4.2.1'
4 | s.license = 'MIT'
5 | s.summary = 'SwiftUtils'
6 | s.homepage = 'https://github.com/tsrnd/swiftutils-ios'
7 | s.authors = { 'Dao Nguyen' => 'zendobk' }
8 | s.source = { :git => 'https://github.com/tsrnd/swiftutils-ios.git', :tag => s.version}
9 | s.requires_arc = true
10 | s.ios.deployment_target = '8.0'
11 | s.ios.frameworks = 'Foundation', 'UIKit'
12 | s.source_files = 'Sources/Classes/*.swift', 'Sources/Extensions/*.swift'
13 | end
14 |
--------------------------------------------------------------------------------
/SwiftUtils.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 12C986317B77D7ABFB3C3C6F /* Pods_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD2BECCF992B0D91E960C280 /* Pods_Tests.framework */; };
11 | 69AD6313F4C2A7AB30B2FC17 /* Pods_SwiftUtils.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F43597B3367AFF025FC6DDF7 /* Pods_SwiftUtils.framework */; };
12 | B204CC319B099051C03BDD4C /* Pods_PodTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CC90DFF29AB37B6D0DEBE45A /* Pods_PodTest.framework */; };
13 | EC21919C1D49D65000CA1314 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC21919B1D49D65000CA1314 /* String.swift */; };
14 | EC41F5E91D7BFD820081758D /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC41F5E81D7BFD820081758D /* UIView.swift */; };
15 | EC41F5EC1D7BFE4A0081758D /* TestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC41F5EB1D7BFE4A0081758D /* TestView.swift */; };
16 | EC41F5EE1D7BFE550081758D /* TestView.xib in Resources */ = {isa = PBXBuildFile; fileRef = EC41F5ED1D7BFE550081758D /* TestView.xib */; };
17 | EC45F2871D92A26F00A26AF0 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC45F2861D92A26F00A26AF0 /* AppDelegate.swift */; };
18 | EC45F2891D92A26F00A26AF0 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC45F2881D92A26F00A26AF0 /* ViewController.swift */; };
19 | EC45F28C1D92A26F00A26AF0 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EC45F28A1D92A26F00A26AF0 /* Main.storyboard */; };
20 | EC45F28E1D92A26F00A26AF0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EC45F28D1D92A26F00A26AF0 /* Assets.xcassets */; };
21 | EC45F2911D92A26F00A26AF0 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EC45F28F1D92A26F00A26AF0 /* LaunchScreen.storyboard */; };
22 | EC7343EF1D05698C00FE3F92 /* Bool.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC7343EE1D05698C00FE3F92 /* Bool.swift */; };
23 | ECA6D5DA1C83E68E00A3D848 /* SwiftUtils.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ECD9E6D81BC24428001F8738 /* SwiftUtils.framework */; };
24 | ECA6D5E11C83E89B00A3D848 /* Array.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA6D5E01C83E89B00A3D848 /* Array.swift */; };
25 | ECBAE7971DB773A600E520CE /* AlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE7761DB773A600E520CE /* AlertController.swift */; };
26 | ECBAE7981DB773A600E520CE /* Label.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE7771DB773A600E520CE /* Label.swift */; };
27 | ECBAE7991DB773A600E520CE /* RefreshControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE7781DB773A600E520CE /* RefreshControl.swift */; };
28 | ECBAE79A1DB773A600E520CE /* SwiftUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE7791DB773A600E520CE /* SwiftUtils.swift */; };
29 | ECBAE79B1DB773A600E520CE /* TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE77A1DB773A600E520CE /* TableView.swift */; };
30 | ECBAE79C1DB773A600E520CE /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE77B1DB773A600E520CE /* ViewController.swift */; };
31 | ECBAE79D1DB773A600E520CE /* Array.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE77D1DB773A600E520CE /* Array.swift */; };
32 | ECBAE79E1DB773A600E520CE /* Bool.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE77E1DB773A600E520CE /* Bool.swift */; };
33 | ECBAE79F1DB773A600E520CE /* CGGeometry.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE77F1DB773A600E520CE /* CGGeometry.swift */; };
34 | ECBAE7A01DB773A600E520CE /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE7801DB773A600E520CE /* Dictionary.swift */; };
35 | ECBAE7A11DB773A600E520CE /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE7811DB773A600E520CE /* Double.swift */; };
36 | ECBAE7A21DB773A600E520CE /* Float.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE7821DB773A600E520CE /* Float.swift */; };
37 | ECBAE7A31DB773A600E520CE /* Int.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE7831DB773A600E520CE /* Int.swift */; };
38 | ECBAE7A41DB773A600E520CE /* NSBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE7841DB773A600E520CE /* NSBundle.swift */; };
39 | ECBAE7A61DB773A600E520CE /* NSData.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE7861DB773A600E520CE /* NSData.swift */; };
40 | ECBAE7A71DB773A600E520CE /* NSDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE7871DB773A600E520CE /* NSDate.swift */; };
41 | ECBAE7A81DB773A600E520CE /* NSFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE7881DB773A600E520CE /* NSFileManager.swift */; };
42 | ECBAE7A91DB773A600E520CE /* NSLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE7891DB773A600E520CE /* NSLock.swift */; };
43 | ECBAE7AA1DB773A600E520CE /* NSURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE78A1DB773A600E520CE /* NSURL.swift */; };
44 | ECBAE7AB1DB773A600E520CE /* Range.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE78B1DB773A600E520CE /* Range.swift */; };
45 | ECBAE7AC1DB773A600E520CE /* Regex.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE78C1DB773A600E520CE /* Regex.swift */; };
46 | ECBAE7AD1DB773A600E520CE /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE78D1DB773A600E520CE /* String.swift */; };
47 | ECBAE7AE1DB773A600E520CE /* UICollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE78E1DB773A600E520CE /* UICollectionView.swift */; };
48 | ECBAE7AF1DB773A600E520CE /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE78F1DB773A600E520CE /* UIColor.swift */; };
49 | ECBAE7B01DB773A600E520CE /* UIGeometry.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE7901DB773A600E520CE /* UIGeometry.swift */; };
50 | ECBAE7B11DB773A600E520CE /* UIImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE7911DB773A600E520CE /* UIImage.swift */; };
51 | ECBAE7B21DB773A600E520CE /* UILayoutPriority.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE7921DB773A600E520CE /* UILayoutPriority.swift */; };
52 | ECBAE7B31DB773A600E520CE /* UITableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE7931DB773A600E520CE /* UITableView.swift */; };
53 | ECBAE7B41DB773A600E520CE /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE7941DB773A600E520CE /* UIView.swift */; };
54 | ECBAE7B51DB773A600E520CE /* UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBAE7951DB773A600E520CE /* UIViewController.swift */; };
55 | /* End PBXBuildFile section */
56 |
57 | /* Begin PBXContainerItemProxy section */
58 | ECA6D5DB1C83E68E00A3D848 /* PBXContainerItemProxy */ = {
59 | isa = PBXContainerItemProxy;
60 | containerPortal = ECD9E6CF1BC24428001F8738 /* Project object */;
61 | proxyType = 1;
62 | remoteGlobalIDString = ECD9E6D71BC24428001F8738;
63 | remoteInfo = SwiftUtils;
64 | };
65 | ECE5D8A61DB8762B00193DD5 /* PBXContainerItemProxy */ = {
66 | isa = PBXContainerItemProxy;
67 | containerPortal = ECD9E6CF1BC24428001F8738 /* Project object */;
68 | proxyType = 1;
69 | remoteGlobalIDString = ECD9E6D71BC24428001F8738;
70 | remoteInfo = SwiftUtils;
71 | };
72 | /* End PBXContainerItemProxy section */
73 |
74 | /* Begin PBXFileReference section */
75 | 024427016ED960227D9A8CC7 /* Pods-Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.release.xcconfig"; sourceTree = ""; };
76 | 5A78C09A78B70F30AE14F808 /* Pods-PodTest.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PodTest.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PodTest/Pods-PodTest.debug.xcconfig"; sourceTree = ""; };
77 | 71476F41AA0C7E0C7C36A603 /* Pods-SwiftUtils.releasetest.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftUtils.releasetest.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftUtils/Pods-SwiftUtils.releasetest.xcconfig"; sourceTree = ""; };
78 | 759E4A4DB4B0314C10C71ACD /* Pods-SwiftUtils.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftUtils.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftUtils/Pods-SwiftUtils.release.xcconfig"; sourceTree = ""; };
79 | 90CAB0307928F923616893B0 /* Pods-PodTest.releasetest.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PodTest.releasetest.xcconfig"; path = "Pods/Target Support Files/Pods-PodTest/Pods-PodTest.releasetest.xcconfig"; sourceTree = ""; };
80 | AD2BECCF992B0D91E960C280 /* Pods_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
81 | BA6749A325B44D0D074C6081 /* Pods-Tests.releasetest.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.releasetest.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.releasetest.xcconfig"; sourceTree = ""; };
82 | CC90DFF29AB37B6D0DEBE45A /* Pods_PodTest.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PodTest.framework; sourceTree = BUILT_PRODUCTS_DIR; };
83 | D36ADDDB6B5360976D618F19 /* Pods-PodTest.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PodTest.release.xcconfig"; path = "Pods/Target Support Files/Pods-PodTest/Pods-PodTest.release.xcconfig"; sourceTree = ""; };
84 | E127B7F845E47BA2468CDBF1 /* Pods-SwiftUtils.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftUtils.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftUtils/Pods-SwiftUtils.debug.xcconfig"; sourceTree = ""; };
85 | EC21919B1D49D65000CA1314 /* String.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = ""; };
86 | EC41F5E81D7BFD820081758D /* UIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = ""; };
87 | EC41F5EB1D7BFE4A0081758D /* TestView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestView.swift; sourceTree = ""; };
88 | EC41F5ED1D7BFE550081758D /* TestView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TestView.xib; sourceTree = ""; };
89 | EC45F2841D92A26F00A26AF0 /* PodTest.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PodTest.app; sourceTree = BUILT_PRODUCTS_DIR; };
90 | EC45F2861D92A26F00A26AF0 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
91 | EC45F2881D92A26F00A26AF0 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
92 | EC45F28B1D92A26F00A26AF0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
93 | EC45F28D1D92A26F00A26AF0 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
94 | EC45F2901D92A26F00A26AF0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
95 | EC45F2921D92A26F00A26AF0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
96 | EC7343EE1D05698C00FE3F92 /* Bool.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Bool.swift; sourceTree = ""; };
97 | ECA6D5D51C83E68E00A3D848 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
98 | ECA6D5D91C83E68E00A3D848 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
99 | ECA6D5E01C83E89B00A3D848 /* Array.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Array.swift; sourceTree = ""; };
100 | ECBAE7761DB773A600E520CE /* AlertController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertController.swift; sourceTree = ""; };
101 | ECBAE7771DB773A600E520CE /* Label.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Label.swift; sourceTree = ""; };
102 | ECBAE7781DB773A600E520CE /* RefreshControl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RefreshControl.swift; sourceTree = ""; };
103 | ECBAE7791DB773A600E520CE /* SwiftUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftUtils.swift; sourceTree = ""; };
104 | ECBAE77A1DB773A600E520CE /* TableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableView.swift; sourceTree = ""; };
105 | ECBAE77B1DB773A600E520CE /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
106 | ECBAE77D1DB773A600E520CE /* Array.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Array.swift; sourceTree = ""; };
107 | ECBAE77E1DB773A600E520CE /* Bool.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Bool.swift; sourceTree = ""; };
108 | ECBAE77F1DB773A600E520CE /* CGGeometry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CGGeometry.swift; sourceTree = ""; };
109 | ECBAE7801DB773A600E520CE /* Dictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Dictionary.swift; sourceTree = ""; };
110 | ECBAE7811DB773A600E520CE /* Double.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Double.swift; sourceTree = ""; };
111 | ECBAE7821DB773A600E520CE /* Float.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Float.swift; sourceTree = ""; };
112 | ECBAE7831DB773A600E520CE /* Int.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Int.swift; sourceTree = ""; };
113 | ECBAE7841DB773A600E520CE /* NSBundle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSBundle.swift; sourceTree = ""; };
114 | ECBAE7861DB773A600E520CE /* NSData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSData.swift; sourceTree = ""; };
115 | ECBAE7871DB773A600E520CE /* NSDate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSDate.swift; sourceTree = ""; };
116 | ECBAE7881DB773A600E520CE /* NSFileManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSFileManager.swift; sourceTree = ""; };
117 | ECBAE7891DB773A600E520CE /* NSLock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSLock.swift; sourceTree = ""; };
118 | ECBAE78A1DB773A600E520CE /* NSURL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSURL.swift; sourceTree = ""; };
119 | ECBAE78B1DB773A600E520CE /* Range.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Range.swift; sourceTree = ""; };
120 | ECBAE78C1DB773A600E520CE /* Regex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Regex.swift; sourceTree = ""; };
121 | ECBAE78D1DB773A600E520CE /* String.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = ""; };
122 | ECBAE78E1DB773A600E520CE /* UICollectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UICollectionView.swift; sourceTree = ""; };
123 | ECBAE78F1DB773A600E520CE /* UIColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIColor.swift; sourceTree = ""; };
124 | ECBAE7901DB773A600E520CE /* UIGeometry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIGeometry.swift; sourceTree = ""; };
125 | ECBAE7911DB773A600E520CE /* UIImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImage.swift; sourceTree = ""; };
126 | ECBAE7921DB773A600E520CE /* UILayoutPriority.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UILayoutPriority.swift; sourceTree = ""; };
127 | ECBAE7931DB773A600E520CE /* UITableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UITableView.swift; sourceTree = ""; };
128 | ECBAE7941DB773A600E520CE /* UIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = ""; };
129 | ECBAE7951DB773A600E520CE /* UIViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewController.swift; sourceTree = ""; };
130 | ECBAE7961DB773A600E520CE /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
131 | ECD9E6D81BC24428001F8738 /* SwiftUtils.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftUtils.framework; sourceTree = BUILT_PRODUCTS_DIR; };
132 | EDED78491C4F0F2B41A9E9B0 /* Pods-Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.debug.xcconfig"; sourceTree = ""; };
133 | F43597B3367AFF025FC6DDF7 /* Pods_SwiftUtils.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwiftUtils.framework; sourceTree = BUILT_PRODUCTS_DIR; };
134 | /* End PBXFileReference section */
135 |
136 | /* Begin PBXFrameworksBuildPhase section */
137 | EC45F2811D92A26F00A26AF0 /* Frameworks */ = {
138 | isa = PBXFrameworksBuildPhase;
139 | buildActionMask = 2147483647;
140 | files = (
141 | B204CC319B099051C03BDD4C /* Pods_PodTest.framework in Frameworks */,
142 | );
143 | runOnlyForDeploymentPostprocessing = 0;
144 | };
145 | ECA6D5D21C83E68E00A3D848 /* Frameworks */ = {
146 | isa = PBXFrameworksBuildPhase;
147 | buildActionMask = 2147483647;
148 | files = (
149 | ECA6D5DA1C83E68E00A3D848 /* SwiftUtils.framework in Frameworks */,
150 | 12C986317B77D7ABFB3C3C6F /* Pods_Tests.framework in Frameworks */,
151 | );
152 | runOnlyForDeploymentPostprocessing = 0;
153 | };
154 | ECD9E6D41BC24428001F8738 /* Frameworks */ = {
155 | isa = PBXFrameworksBuildPhase;
156 | buildActionMask = 2147483647;
157 | files = (
158 | 69AD6313F4C2A7AB30B2FC17 /* Pods_SwiftUtils.framework in Frameworks */,
159 | );
160 | runOnlyForDeploymentPostprocessing = 0;
161 | };
162 | /* End PBXFrameworksBuildPhase section */
163 |
164 | /* Begin PBXGroup section */
165 | 95562877CEECB0905E1E2050 /* Pods */ = {
166 | isa = PBXGroup;
167 | children = (
168 | 5A78C09A78B70F30AE14F808 /* Pods-PodTest.debug.xcconfig */,
169 | D36ADDDB6B5360976D618F19 /* Pods-PodTest.release.xcconfig */,
170 | 90CAB0307928F923616893B0 /* Pods-PodTest.releasetest.xcconfig */,
171 | E127B7F845E47BA2468CDBF1 /* Pods-SwiftUtils.debug.xcconfig */,
172 | 759E4A4DB4B0314C10C71ACD /* Pods-SwiftUtils.release.xcconfig */,
173 | 71476F41AA0C7E0C7C36A603 /* Pods-SwiftUtils.releasetest.xcconfig */,
174 | EDED78491C4F0F2B41A9E9B0 /* Pods-Tests.debug.xcconfig */,
175 | 024427016ED960227D9A8CC7 /* Pods-Tests.release.xcconfig */,
176 | BA6749A325B44D0D074C6081 /* Pods-Tests.releasetest.xcconfig */,
177 | );
178 | name = Pods;
179 | sourceTree = "";
180 | };
181 | EC41F5EA1D7BFE310081758D /* Data */ = {
182 | isa = PBXGroup;
183 | children = (
184 | EC41F5EB1D7BFE4A0081758D /* TestView.swift */,
185 | EC41F5ED1D7BFE550081758D /* TestView.xib */,
186 | );
187 | path = Data;
188 | sourceTree = "";
189 | };
190 | EC45F2851D92A26F00A26AF0 /* PodTest */ = {
191 | isa = PBXGroup;
192 | children = (
193 | EC45F2861D92A26F00A26AF0 /* AppDelegate.swift */,
194 | EC45F2881D92A26F00A26AF0 /* ViewController.swift */,
195 | EC45F28A1D92A26F00A26AF0 /* Main.storyboard */,
196 | EC45F28D1D92A26F00A26AF0 /* Assets.xcassets */,
197 | EC45F28F1D92A26F00A26AF0 /* LaunchScreen.storyboard */,
198 | EC45F2921D92A26F00A26AF0 /* Info.plist */,
199 | );
200 | path = PodTest;
201 | sourceTree = "";
202 | };
203 | ECA6D5D61C83E68E00A3D848 /* Tests */ = {
204 | isa = PBXGroup;
205 | children = (
206 | EC41F5EA1D7BFE310081758D /* Data */,
207 | ECA6D5D91C83E68E00A3D848 /* Info.plist */,
208 | ECA6D5E01C83E89B00A3D848 /* Array.swift */,
209 | EC7343EE1D05698C00FE3F92 /* Bool.swift */,
210 | EC21919B1D49D65000CA1314 /* String.swift */,
211 | EC41F5E81D7BFD820081758D /* UIView.swift */,
212 | );
213 | path = Tests;
214 | sourceTree = "";
215 | };
216 | ECBAE7741DB773A600E520CE /* Sources */ = {
217 | isa = PBXGroup;
218 | children = (
219 | ECBAE7751DB773A600E520CE /* Classes */,
220 | ECBAE77C1DB773A600E520CE /* Extensions */,
221 | ECBAE7961DB773A600E520CE /* Info.plist */,
222 | );
223 | path = Sources;
224 | sourceTree = "";
225 | };
226 | ECBAE7751DB773A600E520CE /* Classes */ = {
227 | isa = PBXGroup;
228 | children = (
229 | ECBAE7761DB773A600E520CE /* AlertController.swift */,
230 | ECBAE7771DB773A600E520CE /* Label.swift */,
231 | ECBAE7781DB773A600E520CE /* RefreshControl.swift */,
232 | ECBAE7791DB773A600E520CE /* SwiftUtils.swift */,
233 | ECBAE77A1DB773A600E520CE /* TableView.swift */,
234 | ECBAE77B1DB773A600E520CE /* ViewController.swift */,
235 | );
236 | path = Classes;
237 | sourceTree = "";
238 | };
239 | ECBAE77C1DB773A600E520CE /* Extensions */ = {
240 | isa = PBXGroup;
241 | children = (
242 | ECBAE77D1DB773A600E520CE /* Array.swift */,
243 | ECBAE77E1DB773A600E520CE /* Bool.swift */,
244 | ECBAE77F1DB773A600E520CE /* CGGeometry.swift */,
245 | ECBAE7801DB773A600E520CE /* Dictionary.swift */,
246 | ECBAE7811DB773A600E520CE /* Double.swift */,
247 | ECBAE7821DB773A600E520CE /* Float.swift */,
248 | ECBAE7831DB773A600E520CE /* Int.swift */,
249 | ECBAE7841DB773A600E520CE /* NSBundle.swift */,
250 | ECBAE7861DB773A600E520CE /* NSData.swift */,
251 | ECBAE7871DB773A600E520CE /* NSDate.swift */,
252 | ECBAE7881DB773A600E520CE /* NSFileManager.swift */,
253 | ECBAE7891DB773A600E520CE /* NSLock.swift */,
254 | ECBAE78A1DB773A600E520CE /* NSURL.swift */,
255 | ECBAE78B1DB773A600E520CE /* Range.swift */,
256 | ECBAE78C1DB773A600E520CE /* Regex.swift */,
257 | ECBAE78D1DB773A600E520CE /* String.swift */,
258 | ECBAE78E1DB773A600E520CE /* UICollectionView.swift */,
259 | ECBAE78F1DB773A600E520CE /* UIColor.swift */,
260 | ECBAE7901DB773A600E520CE /* UIGeometry.swift */,
261 | ECBAE7911DB773A600E520CE /* UIImage.swift */,
262 | ECBAE7921DB773A600E520CE /* UILayoutPriority.swift */,
263 | ECBAE7931DB773A600E520CE /* UITableView.swift */,
264 | ECBAE7941DB773A600E520CE /* UIView.swift */,
265 | ECBAE7951DB773A600E520CE /* UIViewController.swift */,
266 | );
267 | path = Extensions;
268 | sourceTree = "";
269 | };
270 | ECD9E6CE1BC24428001F8738 = {
271 | isa = PBXGroup;
272 | children = (
273 | ECBAE7741DB773A600E520CE /* Sources */,
274 | ECA6D5D61C83E68E00A3D848 /* Tests */,
275 | EC45F2851D92A26F00A26AF0 /* PodTest */,
276 | ECD9E6D91BC24428001F8738 /* Products */,
277 | F492F990E42B525FD024519F /* Frameworks */,
278 | 95562877CEECB0905E1E2050 /* Pods */,
279 | );
280 | indentWidth = 4;
281 | sourceTree = "";
282 | tabWidth = 4;
283 | };
284 | ECD9E6D91BC24428001F8738 /* Products */ = {
285 | isa = PBXGroup;
286 | children = (
287 | ECD9E6D81BC24428001F8738 /* SwiftUtils.framework */,
288 | ECA6D5D51C83E68E00A3D848 /* Tests.xctest */,
289 | EC45F2841D92A26F00A26AF0 /* PodTest.app */,
290 | );
291 | name = Products;
292 | sourceTree = "";
293 | };
294 | F492F990E42B525FD024519F /* Frameworks */ = {
295 | isa = PBXGroup;
296 | children = (
297 | CC90DFF29AB37B6D0DEBE45A /* Pods_PodTest.framework */,
298 | F43597B3367AFF025FC6DDF7 /* Pods_SwiftUtils.framework */,
299 | AD2BECCF992B0D91E960C280 /* Pods_Tests.framework */,
300 | );
301 | name = Frameworks;
302 | sourceTree = "";
303 | };
304 | /* End PBXGroup section */
305 |
306 | /* Begin PBXHeadersBuildPhase section */
307 | ECD9E6D51BC24428001F8738 /* Headers */ = {
308 | isa = PBXHeadersBuildPhase;
309 | buildActionMask = 2147483647;
310 | files = (
311 | );
312 | runOnlyForDeploymentPostprocessing = 0;
313 | };
314 | /* End PBXHeadersBuildPhase section */
315 |
316 | /* Begin PBXNativeTarget section */
317 | EC45F2831D92A26F00A26AF0 /* PodTest */ = {
318 | isa = PBXNativeTarget;
319 | buildConfigurationList = EC45F2961D92A26F00A26AF0 /* Build configuration list for PBXNativeTarget "PodTest" */;
320 | buildPhases = (
321 | A927849F26EAEA248B0C62BF /* [CP] Check Pods Manifest.lock */,
322 | EC45F2801D92A26F00A26AF0 /* Sources */,
323 | EC45F2811D92A26F00A26AF0 /* Frameworks */,
324 | EC45F2821D92A26F00A26AF0 /* Resources */,
325 | 30031D9544B626F63DAA2061 /* [CP] Embed Pods Frameworks */,
326 | );
327 | buildRules = (
328 | );
329 | dependencies = (
330 | ECE5D8A71DB8762B00193DD5 /* PBXTargetDependency */,
331 | );
332 | name = PodTest;
333 | productName = PodTest;
334 | productReference = EC45F2841D92A26F00A26AF0 /* PodTest.app */;
335 | productType = "com.apple.product-type.application";
336 | };
337 | ECA6D5D41C83E68E00A3D848 /* Tests */ = {
338 | isa = PBXNativeTarget;
339 | buildConfigurationList = ECA6D5DF1C83E68E00A3D848 /* Build configuration list for PBXNativeTarget "Tests" */;
340 | buildPhases = (
341 | 747DA2BBEED0102CB32F978B /* [CP] Check Pods Manifest.lock */,
342 | ECA6D5D11C83E68E00A3D848 /* Sources */,
343 | ECA6D5D21C83E68E00A3D848 /* Frameworks */,
344 | ECA6D5D31C83E68E00A3D848 /* Resources */,
345 | );
346 | buildRules = (
347 | );
348 | dependencies = (
349 | ECA6D5DC1C83E68E00A3D848 /* PBXTargetDependency */,
350 | );
351 | name = Tests;
352 | productName = Tests;
353 | productReference = ECA6D5D51C83E68E00A3D848 /* Tests.xctest */;
354 | productType = "com.apple.product-type.bundle.unit-test";
355 | };
356 | ECD9E6D71BC24428001F8738 /* SwiftUtils */ = {
357 | isa = PBXNativeTarget;
358 | buildConfigurationList = ECD9E6E01BC24428001F8738 /* Build configuration list for PBXNativeTarget "SwiftUtils" */;
359 | buildPhases = (
360 | F9DB3F586B76A7B756F7345A /* [CP] Check Pods Manifest.lock */,
361 | EC887CD71CA3DE3D00E04007 /* Swift-Lint */,
362 | ECD9E6D31BC24428001F8738 /* Sources */,
363 | ECD9E6D41BC24428001F8738 /* Frameworks */,
364 | ECD9E6D51BC24428001F8738 /* Headers */,
365 | ECD9E6D61BC24428001F8738 /* Resources */,
366 | );
367 | buildRules = (
368 | );
369 | dependencies = (
370 | );
371 | name = SwiftUtils;
372 | productName = SwiftUtils;
373 | productReference = ECD9E6D81BC24428001F8738 /* SwiftUtils.framework */;
374 | productType = "com.apple.product-type.framework";
375 | };
376 | /* End PBXNativeTarget section */
377 |
378 | /* Begin PBXProject section */
379 | ECD9E6CF1BC24428001F8738 /* Project object */ = {
380 | isa = PBXProject;
381 | attributes = {
382 | LastSwiftUpdateCheck = 0730;
383 | LastUpgradeCheck = 1000;
384 | ORGANIZATIONNAME = "Astraler Technology";
385 | TargetAttributes = {
386 | EC45F2831D92A26F00A26AF0 = {
387 | CreatedOnToolsVersion = 7.3.1;
388 | DevelopmentTeam = 6KVPTGZPCD;
389 | LastSwiftMigration = 0910;
390 | ProvisioningStyle = Manual;
391 | };
392 | ECA6D5D41C83E68E00A3D848 = {
393 | CreatedOnToolsVersion = 7.2.1;
394 | DevelopmentTeam = 2T879AQ94V;
395 | LastSwiftMigration = 1000;
396 | ProvisioningStyle = Manual;
397 | };
398 | ECD9E6D71BC24428001F8738 = {
399 | CreatedOnToolsVersion = 7.0;
400 | LastSwiftMigration = 1000;
401 | };
402 | };
403 | };
404 | buildConfigurationList = ECD9E6D21BC24428001F8738 /* Build configuration list for PBXProject "SwiftUtils" */;
405 | compatibilityVersion = "Xcode 3.2";
406 | developmentRegion = English;
407 | hasScannedForEncodings = 0;
408 | knownRegions = (
409 | Base,
410 | );
411 | mainGroup = ECD9E6CE1BC24428001F8738;
412 | productRefGroup = ECD9E6D91BC24428001F8738 /* Products */;
413 | projectDirPath = "";
414 | projectRoot = "";
415 | targets = (
416 | ECD9E6D71BC24428001F8738 /* SwiftUtils */,
417 | ECA6D5D41C83E68E00A3D848 /* Tests */,
418 | EC45F2831D92A26F00A26AF0 /* PodTest */,
419 | );
420 | };
421 | /* End PBXProject section */
422 |
423 | /* Begin PBXResourcesBuildPhase section */
424 | EC45F2821D92A26F00A26AF0 /* Resources */ = {
425 | isa = PBXResourcesBuildPhase;
426 | buildActionMask = 2147483647;
427 | files = (
428 | EC45F2911D92A26F00A26AF0 /* LaunchScreen.storyboard in Resources */,
429 | EC45F28E1D92A26F00A26AF0 /* Assets.xcassets in Resources */,
430 | EC45F28C1D92A26F00A26AF0 /* Main.storyboard in Resources */,
431 | );
432 | runOnlyForDeploymentPostprocessing = 0;
433 | };
434 | ECA6D5D31C83E68E00A3D848 /* Resources */ = {
435 | isa = PBXResourcesBuildPhase;
436 | buildActionMask = 2147483647;
437 | files = (
438 | EC41F5EE1D7BFE550081758D /* TestView.xib in Resources */,
439 | );
440 | runOnlyForDeploymentPostprocessing = 0;
441 | };
442 | ECD9E6D61BC24428001F8738 /* Resources */ = {
443 | isa = PBXResourcesBuildPhase;
444 | buildActionMask = 2147483647;
445 | files = (
446 | );
447 | runOnlyForDeploymentPostprocessing = 0;
448 | };
449 | /* End PBXResourcesBuildPhase section */
450 |
451 | /* Begin PBXShellScriptBuildPhase section */
452 | 30031D9544B626F63DAA2061 /* [CP] Embed Pods Frameworks */ = {
453 | isa = PBXShellScriptBuildPhase;
454 | buildActionMask = 2147483647;
455 | files = (
456 | );
457 | inputPaths = (
458 | "${SRCROOT}/Pods/Target Support Files/Pods-PodTest/Pods-PodTest-frameworks.sh",
459 | "${BUILT_PRODUCTS_DIR}/SwiftUtils/SwiftUtils.framework",
460 | );
461 | name = "[CP] Embed Pods Frameworks";
462 | outputPaths = (
463 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftUtils.framework",
464 | );
465 | runOnlyForDeploymentPostprocessing = 0;
466 | shellPath = /bin/sh;
467 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-PodTest/Pods-PodTest-frameworks.sh\"\n";
468 | showEnvVarsInLog = 0;
469 | };
470 | 747DA2BBEED0102CB32F978B /* [CP] Check Pods Manifest.lock */ = {
471 | isa = PBXShellScriptBuildPhase;
472 | buildActionMask = 2147483647;
473 | files = (
474 | );
475 | inputPaths = (
476 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
477 | "${PODS_ROOT}/Manifest.lock",
478 | );
479 | name = "[CP] Check Pods Manifest.lock";
480 | outputPaths = (
481 | "$(DERIVED_FILE_DIR)/Pods-Tests-checkManifestLockResult.txt",
482 | );
483 | runOnlyForDeploymentPostprocessing = 0;
484 | shellPath = /bin/sh;
485 | 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";
486 | showEnvVarsInLog = 0;
487 | };
488 | A927849F26EAEA248B0C62BF /* [CP] Check Pods Manifest.lock */ = {
489 | isa = PBXShellScriptBuildPhase;
490 | buildActionMask = 2147483647;
491 | files = (
492 | );
493 | inputPaths = (
494 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
495 | "${PODS_ROOT}/Manifest.lock",
496 | );
497 | name = "[CP] Check Pods Manifest.lock";
498 | outputPaths = (
499 | "$(DERIVED_FILE_DIR)/Pods-PodTest-checkManifestLockResult.txt",
500 | );
501 | runOnlyForDeploymentPostprocessing = 0;
502 | shellPath = /bin/sh;
503 | 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";
504 | showEnvVarsInLog = 0;
505 | };
506 | EC887CD71CA3DE3D00E04007 /* Swift-Lint */ = {
507 | isa = PBXShellScriptBuildPhase;
508 | buildActionMask = 2147483647;
509 | files = (
510 | );
511 | inputPaths = (
512 | );
513 | name = "Swift-Lint";
514 | outputPaths = (
515 | );
516 | runOnlyForDeploymentPostprocessing = 0;
517 | shellPath = /bin/sh;
518 | shellScript = "\"${PODS_ROOT}/SwiftLint/swiftlint\"\n";
519 | };
520 | F9DB3F586B76A7B756F7345A /* [CP] Check Pods Manifest.lock */ = {
521 | isa = PBXShellScriptBuildPhase;
522 | buildActionMask = 2147483647;
523 | files = (
524 | );
525 | inputPaths = (
526 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
527 | "${PODS_ROOT}/Manifest.lock",
528 | );
529 | name = "[CP] Check Pods Manifest.lock";
530 | outputPaths = (
531 | "$(DERIVED_FILE_DIR)/Pods-SwiftUtils-checkManifestLockResult.txt",
532 | );
533 | runOnlyForDeploymentPostprocessing = 0;
534 | shellPath = /bin/sh;
535 | 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";
536 | showEnvVarsInLog = 0;
537 | };
538 | /* End PBXShellScriptBuildPhase section */
539 |
540 | /* Begin PBXSourcesBuildPhase section */
541 | EC45F2801D92A26F00A26AF0 /* Sources */ = {
542 | isa = PBXSourcesBuildPhase;
543 | buildActionMask = 2147483647;
544 | files = (
545 | EC45F2891D92A26F00A26AF0 /* ViewController.swift in Sources */,
546 | EC45F2871D92A26F00A26AF0 /* AppDelegate.swift in Sources */,
547 | );
548 | runOnlyForDeploymentPostprocessing = 0;
549 | };
550 | ECA6D5D11C83E68E00A3D848 /* Sources */ = {
551 | isa = PBXSourcesBuildPhase;
552 | buildActionMask = 2147483647;
553 | files = (
554 | EC41F5E91D7BFD820081758D /* UIView.swift in Sources */,
555 | EC41F5EC1D7BFE4A0081758D /* TestView.swift in Sources */,
556 | ECA6D5E11C83E89B00A3D848 /* Array.swift in Sources */,
557 | EC21919C1D49D65000CA1314 /* String.swift in Sources */,
558 | EC7343EF1D05698C00FE3F92 /* Bool.swift in Sources */,
559 | );
560 | runOnlyForDeploymentPostprocessing = 0;
561 | };
562 | ECD9E6D31BC24428001F8738 /* Sources */ = {
563 | isa = PBXSourcesBuildPhase;
564 | buildActionMask = 2147483647;
565 | files = (
566 | ECBAE7A81DB773A600E520CE /* NSFileManager.swift in Sources */,
567 | ECBAE79C1DB773A600E520CE /* ViewController.swift in Sources */,
568 | ECBAE7AD1DB773A600E520CE /* String.swift in Sources */,
569 | ECBAE7B21DB773A600E520CE /* UILayoutPriority.swift in Sources */,
570 | ECBAE7A31DB773A600E520CE /* Int.swift in Sources */,
571 | ECBAE7A61DB773A600E520CE /* NSData.swift in Sources */,
572 | ECBAE7B01DB773A600E520CE /* UIGeometry.swift in Sources */,
573 | ECBAE7B11DB773A600E520CE /* UIImage.swift in Sources */,
574 | ECBAE7A01DB773A600E520CE /* Dictionary.swift in Sources */,
575 | ECBAE7AE1DB773A600E520CE /* UICollectionView.swift in Sources */,
576 | ECBAE7B41DB773A600E520CE /* UIView.swift in Sources */,
577 | ECBAE79E1DB773A600E520CE /* Bool.swift in Sources */,
578 | ECBAE7AB1DB773A600E520CE /* Range.swift in Sources */,
579 | ECBAE79F1DB773A600E520CE /* CGGeometry.swift in Sources */,
580 | ECBAE7991DB773A600E520CE /* RefreshControl.swift in Sources */,
581 | ECBAE79D1DB773A600E520CE /* Array.swift in Sources */,
582 | ECBAE7AA1DB773A600E520CE /* NSURL.swift in Sources */,
583 | ECBAE79B1DB773A600E520CE /* TableView.swift in Sources */,
584 | ECBAE7A41DB773A600E520CE /* NSBundle.swift in Sources */,
585 | ECBAE7A91DB773A600E520CE /* NSLock.swift in Sources */,
586 | ECBAE79A1DB773A600E520CE /* SwiftUtils.swift in Sources */,
587 | ECBAE7A21DB773A600E520CE /* Float.swift in Sources */,
588 | ECBAE7B31DB773A600E520CE /* UITableView.swift in Sources */,
589 | ECBAE7AF1DB773A600E520CE /* UIColor.swift in Sources */,
590 | ECBAE7981DB773A600E520CE /* Label.swift in Sources */,
591 | ECBAE7A71DB773A600E520CE /* NSDate.swift in Sources */,
592 | ECBAE7B51DB773A600E520CE /* UIViewController.swift in Sources */,
593 | ECBAE7A11DB773A600E520CE /* Double.swift in Sources */,
594 | ECBAE7971DB773A600E520CE /* AlertController.swift in Sources */,
595 | ECBAE7AC1DB773A600E520CE /* Regex.swift in Sources */,
596 | );
597 | runOnlyForDeploymentPostprocessing = 0;
598 | };
599 | /* End PBXSourcesBuildPhase section */
600 |
601 | /* Begin PBXTargetDependency section */
602 | ECA6D5DC1C83E68E00A3D848 /* PBXTargetDependency */ = {
603 | isa = PBXTargetDependency;
604 | target = ECD9E6D71BC24428001F8738 /* SwiftUtils */;
605 | targetProxy = ECA6D5DB1C83E68E00A3D848 /* PBXContainerItemProxy */;
606 | };
607 | ECE5D8A71DB8762B00193DD5 /* PBXTargetDependency */ = {
608 | isa = PBXTargetDependency;
609 | target = ECD9E6D71BC24428001F8738 /* SwiftUtils */;
610 | targetProxy = ECE5D8A61DB8762B00193DD5 /* PBXContainerItemProxy */;
611 | };
612 | /* End PBXTargetDependency section */
613 |
614 | /* Begin PBXVariantGroup section */
615 | EC45F28A1D92A26F00A26AF0 /* Main.storyboard */ = {
616 | isa = PBXVariantGroup;
617 | children = (
618 | EC45F28B1D92A26F00A26AF0 /* Base */,
619 | );
620 | name = Main.storyboard;
621 | sourceTree = "";
622 | };
623 | EC45F28F1D92A26F00A26AF0 /* LaunchScreen.storyboard */ = {
624 | isa = PBXVariantGroup;
625 | children = (
626 | EC45F2901D92A26F00A26AF0 /* Base */,
627 | );
628 | name = LaunchScreen.storyboard;
629 | sourceTree = "";
630 | };
631 | /* End PBXVariantGroup section */
632 |
633 | /* Begin XCBuildConfiguration section */
634 | EC45F2931D92A26F00A26AF0 /* Debug */ = {
635 | isa = XCBuildConfiguration;
636 | baseConfigurationReference = 5A78C09A78B70F30AE14F808 /* Pods-PodTest.debug.xcconfig */;
637 | buildSettings = {
638 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";
639 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
640 | CLANG_ANALYZER_NONNULL = YES;
641 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
642 | DEVELOPMENT_TEAM = "";
643 | INFOPLIST_FILE = PodTest/Info.plist;
644 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
645 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
646 | PRODUCT_BUNDLE_IDENTIFIER = vn.asiantech.test.PodTest;
647 | PRODUCT_NAME = "$(TARGET_NAME)";
648 | PROVISIONING_PROFILE = "";
649 | PROVISIONING_PROFILE_SPECIFIER = "";
650 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
651 | SWIFT_VERSION = 4.2;
652 | };
653 | name = Debug;
654 | };
655 | EC45F2941D92A26F00A26AF0 /* Release */ = {
656 | isa = XCBuildConfiguration;
657 | baseConfigurationReference = D36ADDDB6B5360976D618F19 /* Pods-PodTest.release.xcconfig */;
658 | buildSettings = {
659 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";
660 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
661 | CLANG_ANALYZER_NONNULL = YES;
662 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
663 | DEVELOPMENT_TEAM = "";
664 | INFOPLIST_FILE = PodTest/Info.plist;
665 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
666 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
667 | PRODUCT_BUNDLE_IDENTIFIER = vn.asiantech.test.PodTest;
668 | PRODUCT_NAME = "$(TARGET_NAME)";
669 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
670 | SWIFT_VERSION = 4.2;
671 | };
672 | name = Release;
673 | };
674 | EC45F2951D92A26F00A26AF0 /* ReleaseTest */ = {
675 | isa = XCBuildConfiguration;
676 | baseConfigurationReference = 90CAB0307928F923616893B0 /* Pods-PodTest.releasetest.xcconfig */;
677 | buildSettings = {
678 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";
679 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
680 | CLANG_ANALYZER_NONNULL = YES;
681 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
682 | DEVELOPMENT_TEAM = "";
683 | INFOPLIST_FILE = PodTest/Info.plist;
684 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
685 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
686 | PRODUCT_BUNDLE_IDENTIFIER = vn.asiantech.test.PodTest;
687 | PRODUCT_NAME = "$(TARGET_NAME)";
688 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
689 | SWIFT_VERSION = 4.2;
690 | };
691 | name = ReleaseTest;
692 | };
693 | ECA6D5DD1C83E68E00A3D848 /* Debug */ = {
694 | isa = XCBuildConfiguration;
695 | baseConfigurationReference = EDED78491C4F0F2B41A9E9B0 /* Pods-Tests.debug.xcconfig */;
696 | buildSettings = {
697 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";
698 | DEVELOPMENT_TEAM = "";
699 | INFOPLIST_FILE = Tests/Info.plist;
700 | IPHONEOS_DEPLOYMENT_TARGET = 9.2;
701 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
702 | PRODUCT_BUNDLE_IDENTIFIER = com.at.dev.Tests;
703 | PRODUCT_NAME = "$(TARGET_NAME)";
704 | SWIFT_VERSION = 4.2;
705 | };
706 | name = Debug;
707 | };
708 | ECA6D5DE1C83E68E00A3D848 /* Release */ = {
709 | isa = XCBuildConfiguration;
710 | baseConfigurationReference = 024427016ED960227D9A8CC7 /* Pods-Tests.release.xcconfig */;
711 | buildSettings = {
712 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";
713 | DEVELOPMENT_TEAM = "";
714 | INFOPLIST_FILE = Tests/Info.plist;
715 | IPHONEOS_DEPLOYMENT_TARGET = 9.2;
716 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
717 | PRODUCT_BUNDLE_IDENTIFIER = com.at.dev.Tests;
718 | PRODUCT_NAME = "$(TARGET_NAME)";
719 | SWIFT_VERSION = 4.2;
720 | };
721 | name = Release;
722 | };
723 | ECD9E6DE1BC24428001F8738 /* Debug */ = {
724 | isa = XCBuildConfiguration;
725 | buildSettings = {
726 | ALWAYS_SEARCH_USER_PATHS = NO;
727 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
728 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
729 | CLANG_CXX_LIBRARY = "libc++";
730 | CLANG_ENABLE_MODULES = YES;
731 | CLANG_ENABLE_OBJC_ARC = YES;
732 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
733 | CLANG_WARN_BOOL_CONVERSION = YES;
734 | CLANG_WARN_COMMA = YES;
735 | CLANG_WARN_CONSTANT_CONVERSION = YES;
736 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
737 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
738 | CLANG_WARN_EMPTY_BODY = YES;
739 | CLANG_WARN_ENUM_CONVERSION = YES;
740 | CLANG_WARN_INFINITE_RECURSION = YES;
741 | CLANG_WARN_INT_CONVERSION = YES;
742 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
743 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
744 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
745 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
746 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
747 | CLANG_WARN_STRICT_PROTOTYPES = YES;
748 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
749 | CLANG_WARN_UNREACHABLE_CODE = YES;
750 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
751 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
752 | COPY_PHASE_STRIP = NO;
753 | CURRENT_PROJECT_VERSION = 1;
754 | DEBUG_INFORMATION_FORMAT = dwarf;
755 | ENABLE_STRICT_OBJC_MSGSEND = YES;
756 | ENABLE_TESTABILITY = YES;
757 | GCC_C_LANGUAGE_STANDARD = gnu99;
758 | GCC_DYNAMIC_NO_PIC = NO;
759 | GCC_NO_COMMON_BLOCKS = YES;
760 | GCC_OPTIMIZATION_LEVEL = 0;
761 | GCC_PREPROCESSOR_DEFINITIONS = (
762 | "DEBUG=1",
763 | "$(inherited)",
764 | );
765 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
766 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
767 | GCC_WARN_UNDECLARED_SELECTOR = YES;
768 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
769 | GCC_WARN_UNUSED_FUNCTION = YES;
770 | GCC_WARN_UNUSED_VARIABLE = YES;
771 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
772 | MTL_ENABLE_DEBUG_INFO = YES;
773 | ONLY_ACTIVE_ARCH = YES;
774 | SDKROOT = iphoneos;
775 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
776 | SWIFT_VERSION = 4.2;
777 | TARGETED_DEVICE_FAMILY = "1,2";
778 | VERSIONING_SYSTEM = "apple-generic";
779 | VERSION_INFO_PREFIX = "";
780 | };
781 | name = Debug;
782 | };
783 | ECD9E6DF1BC24428001F8738 /* Release */ = {
784 | isa = XCBuildConfiguration;
785 | buildSettings = {
786 | ALWAYS_SEARCH_USER_PATHS = NO;
787 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
788 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
789 | CLANG_CXX_LIBRARY = "libc++";
790 | CLANG_ENABLE_MODULES = YES;
791 | CLANG_ENABLE_OBJC_ARC = YES;
792 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
793 | CLANG_WARN_BOOL_CONVERSION = YES;
794 | CLANG_WARN_COMMA = YES;
795 | CLANG_WARN_CONSTANT_CONVERSION = YES;
796 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
797 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
798 | CLANG_WARN_EMPTY_BODY = YES;
799 | CLANG_WARN_ENUM_CONVERSION = YES;
800 | CLANG_WARN_INFINITE_RECURSION = YES;
801 | CLANG_WARN_INT_CONVERSION = YES;
802 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
803 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
804 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
805 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
806 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
807 | CLANG_WARN_STRICT_PROTOTYPES = YES;
808 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
809 | CLANG_WARN_UNREACHABLE_CODE = YES;
810 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
811 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
812 | COPY_PHASE_STRIP = NO;
813 | CURRENT_PROJECT_VERSION = 1;
814 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
815 | ENABLE_NS_ASSERTIONS = NO;
816 | ENABLE_STRICT_OBJC_MSGSEND = YES;
817 | GCC_C_LANGUAGE_STANDARD = gnu99;
818 | GCC_NO_COMMON_BLOCKS = YES;
819 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
820 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
821 | GCC_WARN_UNDECLARED_SELECTOR = YES;
822 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
823 | GCC_WARN_UNUSED_FUNCTION = YES;
824 | GCC_WARN_UNUSED_VARIABLE = YES;
825 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
826 | MTL_ENABLE_DEBUG_INFO = NO;
827 | SDKROOT = iphoneos;
828 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
829 | SWIFT_VERSION = 4.2;
830 | TARGETED_DEVICE_FAMILY = "1,2";
831 | VALIDATE_PRODUCT = YES;
832 | VERSIONING_SYSTEM = "apple-generic";
833 | VERSION_INFO_PREFIX = "";
834 | };
835 | name = Release;
836 | };
837 | ECD9E6E11BC24428001F8738 /* Debug */ = {
838 | isa = XCBuildConfiguration;
839 | baseConfigurationReference = E127B7F845E47BA2468CDBF1 /* Pods-SwiftUtils.debug.xcconfig */;
840 | buildSettings = {
841 | CLANG_ENABLE_MODULES = YES;
842 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
843 | DEFINES_MODULE = YES;
844 | DYLIB_COMPATIBILITY_VERSION = 1;
845 | DYLIB_CURRENT_VERSION = 1;
846 | DYLIB_INSTALL_NAME_BASE = "@rpath";
847 | INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist";
848 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
849 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
850 | PRODUCT_BUNDLE_IDENTIFIER = com.astraler.SwiftUtils;
851 | PRODUCT_NAME = "$(TARGET_NAME)";
852 | SKIP_INSTALL = YES;
853 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
854 | SWIFT_VERSION = 4.2;
855 | };
856 | name = Debug;
857 | };
858 | ECD9E6E21BC24428001F8738 /* Release */ = {
859 | isa = XCBuildConfiguration;
860 | baseConfigurationReference = 759E4A4DB4B0314C10C71ACD /* Pods-SwiftUtils.release.xcconfig */;
861 | buildSettings = {
862 | CLANG_ENABLE_MODULES = YES;
863 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
864 | DEFINES_MODULE = YES;
865 | DYLIB_COMPATIBILITY_VERSION = 1;
866 | DYLIB_CURRENT_VERSION = 1;
867 | DYLIB_INSTALL_NAME_BASE = "@rpath";
868 | INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist";
869 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
870 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
871 | PRODUCT_BUNDLE_IDENTIFIER = com.astraler.SwiftUtils;
872 | PRODUCT_NAME = "$(TARGET_NAME)";
873 | SKIP_INSTALL = YES;
874 | SWIFT_VERSION = 4.2;
875 | };
876 | name = Release;
877 | };
878 | ECDE5BE41CC7C7F200D613C7 /* ReleaseTest */ = {
879 | isa = XCBuildConfiguration;
880 | buildSettings = {
881 | ALWAYS_SEARCH_USER_PATHS = NO;
882 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
883 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
884 | CLANG_CXX_LIBRARY = "libc++";
885 | CLANG_ENABLE_MODULES = YES;
886 | CLANG_ENABLE_OBJC_ARC = YES;
887 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
888 | CLANG_WARN_BOOL_CONVERSION = YES;
889 | CLANG_WARN_COMMA = YES;
890 | CLANG_WARN_CONSTANT_CONVERSION = YES;
891 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
892 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
893 | CLANG_WARN_EMPTY_BODY = YES;
894 | CLANG_WARN_ENUM_CONVERSION = YES;
895 | CLANG_WARN_INFINITE_RECURSION = YES;
896 | CLANG_WARN_INT_CONVERSION = YES;
897 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
898 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
899 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
900 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
901 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
902 | CLANG_WARN_STRICT_PROTOTYPES = YES;
903 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
904 | CLANG_WARN_UNREACHABLE_CODE = YES;
905 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
906 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
907 | COPY_PHASE_STRIP = NO;
908 | CURRENT_PROJECT_VERSION = 1;
909 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
910 | ENABLE_NS_ASSERTIONS = NO;
911 | ENABLE_STRICT_OBJC_MSGSEND = YES;
912 | ENABLE_TESTABILITY = YES;
913 | GCC_C_LANGUAGE_STANDARD = gnu99;
914 | GCC_NO_COMMON_BLOCKS = YES;
915 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
916 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
917 | GCC_WARN_UNDECLARED_SELECTOR = YES;
918 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
919 | GCC_WARN_UNUSED_FUNCTION = YES;
920 | GCC_WARN_UNUSED_VARIABLE = YES;
921 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
922 | MTL_ENABLE_DEBUG_INFO = NO;
923 | SDKROOT = iphoneos;
924 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
925 | SWIFT_VERSION = 4.2;
926 | TARGETED_DEVICE_FAMILY = "1,2";
927 | VALIDATE_PRODUCT = YES;
928 | VERSIONING_SYSTEM = "apple-generic";
929 | VERSION_INFO_PREFIX = "";
930 | };
931 | name = ReleaseTest;
932 | };
933 | ECDE5BE51CC7C7F200D613C7 /* ReleaseTest */ = {
934 | isa = XCBuildConfiguration;
935 | baseConfigurationReference = 71476F41AA0C7E0C7C36A603 /* Pods-SwiftUtils.releasetest.xcconfig */;
936 | buildSettings = {
937 | CLANG_ENABLE_MODULES = YES;
938 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
939 | DEFINES_MODULE = YES;
940 | DYLIB_COMPATIBILITY_VERSION = 1;
941 | DYLIB_CURRENT_VERSION = 1;
942 | DYLIB_INSTALL_NAME_BASE = "@rpath";
943 | INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist";
944 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
945 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
946 | PRODUCT_BUNDLE_IDENTIFIER = com.astraler.SwiftUtils;
947 | PRODUCT_NAME = "$(TARGET_NAME)";
948 | SKIP_INSTALL = YES;
949 | SWIFT_VERSION = 4.2;
950 | };
951 | name = ReleaseTest;
952 | };
953 | ECDE5BE61CC7C7F200D613C7 /* ReleaseTest */ = {
954 | isa = XCBuildConfiguration;
955 | baseConfigurationReference = BA6749A325B44D0D074C6081 /* Pods-Tests.releasetest.xcconfig */;
956 | buildSettings = {
957 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";
958 | DEVELOPMENT_TEAM = "";
959 | INFOPLIST_FILE = Tests/Info.plist;
960 | IPHONEOS_DEPLOYMENT_TARGET = 9.2;
961 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
962 | PRODUCT_BUNDLE_IDENTIFIER = com.at.dev.Tests;
963 | PRODUCT_NAME = "$(TARGET_NAME)";
964 | SWIFT_VERSION = 4.2;
965 | };
966 | name = ReleaseTest;
967 | };
968 | /* End XCBuildConfiguration section */
969 |
970 | /* Begin XCConfigurationList section */
971 | EC45F2961D92A26F00A26AF0 /* Build configuration list for PBXNativeTarget "PodTest" */ = {
972 | isa = XCConfigurationList;
973 | buildConfigurations = (
974 | EC45F2931D92A26F00A26AF0 /* Debug */,
975 | EC45F2941D92A26F00A26AF0 /* Release */,
976 | EC45F2951D92A26F00A26AF0 /* ReleaseTest */,
977 | );
978 | defaultConfigurationIsVisible = 0;
979 | defaultConfigurationName = Release;
980 | };
981 | ECA6D5DF1C83E68E00A3D848 /* Build configuration list for PBXNativeTarget "Tests" */ = {
982 | isa = XCConfigurationList;
983 | buildConfigurations = (
984 | ECA6D5DD1C83E68E00A3D848 /* Debug */,
985 | ECA6D5DE1C83E68E00A3D848 /* Release */,
986 | ECDE5BE61CC7C7F200D613C7 /* ReleaseTest */,
987 | );
988 | defaultConfigurationIsVisible = 0;
989 | defaultConfigurationName = Release;
990 | };
991 | ECD9E6D21BC24428001F8738 /* Build configuration list for PBXProject "SwiftUtils" */ = {
992 | isa = XCConfigurationList;
993 | buildConfigurations = (
994 | ECD9E6DE1BC24428001F8738 /* Debug */,
995 | ECD9E6DF1BC24428001F8738 /* Release */,
996 | ECDE5BE41CC7C7F200D613C7 /* ReleaseTest */,
997 | );
998 | defaultConfigurationIsVisible = 0;
999 | defaultConfigurationName = Release;
1000 | };
1001 | ECD9E6E01BC24428001F8738 /* Build configuration list for PBXNativeTarget "SwiftUtils" */ = {
1002 | isa = XCConfigurationList;
1003 | buildConfigurations = (
1004 | ECD9E6E11BC24428001F8738 /* Debug */,
1005 | ECD9E6E21BC24428001F8738 /* Release */,
1006 | ECDE5BE51CC7C7F200D613C7 /* ReleaseTest */,
1007 | );
1008 | defaultConfigurationIsVisible = 0;
1009 | defaultConfigurationName = Release;
1010 | };
1011 | /* End XCConfigurationList section */
1012 | };
1013 | rootObject = ECD9E6CF1BC24428001F8738 /* Project object */;
1014 | }
1015 |
--------------------------------------------------------------------------------
/SwiftUtils.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SwiftUtils.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SwiftUtils.xcodeproj/xcshareddata/xcschemes/PodTest.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
64 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
83 |
85 |
91 |
92 |
93 |
94 |
96 |
97 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/SwiftUtils.xcodeproj/xcshareddata/xcschemes/SwiftUtils.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
64 |
65 |
71 |
72 |
73 |
74 |
75 |
76 |
82 |
83 |
89 |
90 |
91 |
92 |
94 |
95 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/SwiftUtils.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
12 |
13 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/SwiftUtils.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SwiftUtils.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Tests/Array.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ArrayTests.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 2/29/16.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import SwiftUtils
11 |
12 | class ArrayTests: XCTestCase {
13 | let origin: [Int] = {
14 | var numbers = [Int]()
15 | for i in 0 ... 100_000 {
16 | numbers.append(i)
17 | }
18 | return numbers
19 | }()
20 |
21 | func test_shuffled() {
22 | var shuffled: [Int]!
23 | self.measure { () -> Void in
24 | shuffled = self.origin.shuffled()
25 | }
26 | let test = { (lhs: Int, rhs: Int) -> Bool in
27 | return lhs < rhs
28 | }
29 | XCTAssertEqual(shuffled.sorted(by: test), origin.sorted(by: test), "sorted shuffled should equal to sorted origin")
30 | }
31 |
32 | func test_map() {
33 | let nilInts: [Int?] = [0, 1, nil, 3]
34 | let ints: [Int] = nilInts.compactMap { $0 }
35 | let exp: [Int] = [0, 1, 3]
36 | XCTAssertEqual(ints, exp)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Tests/Bool.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BoolTests.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 6/6/16.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import SwiftUtils
11 |
12 | class BoolTests: XCTestCase {
13 | func test_toggle() {
14 | var bool = true
15 | _ = bool.toggle()
16 | XCTAssertFalse(bool)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Tests/Data/TestView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestView.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 9/4/16.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class TestView: UIView { }
12 |
--------------------------------------------------------------------------------
/Tests/Data/TestView.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Tests/String.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StringTests.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 7/28/16.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import SwiftUtils
11 |
12 | class StringTests: XCTestCase {
13 | func test_initWithClass() {
14 | let clazz = String(describing: UIViewController.self)
15 | XCTAssertEqual(clazz, "UIViewController")
16 | }
17 |
18 | func test_subscriptCharacter() {
19 | let str = "hello world"
20 | let sub: Character! = str[0]
21 | XCTAssertNotNil(sub)
22 | XCTAssertEqual(sub, "h")
23 | }
24 |
25 | func test_subscriptString() {
26 | let str = "hello world"
27 | let sub: String! = str[0]
28 | XCTAssertNotNil(sub)
29 | XCTAssertEqual(sub, "h")
30 | }
31 |
32 | func test_subscriptStringWithRange() {
33 | let str = "hello world"
34 | var sub: String!
35 | sub = str[0...1]
36 | XCTAssertNotNil(sub)
37 | XCTAssertEqual(sub, "he")
38 | sub = str[0...10]
39 | XCTAssertNotNil(sub)
40 | XCTAssertEqual(sub, "hello world")
41 | }
42 |
43 | func test_appending_path() {
44 | let str = "http://google.com"
45 | var path: String
46 | path = str.appending(path: "api/v3")
47 | XCTAssertEqual(path, "http://google.com/api/v3")
48 | path = str.appending(path: "/api/v3")
49 | XCTAssertEqual(path, "http://google.com/api/v3")
50 | path = str.appending(path: "/api/v3/")
51 | XCTAssertEqual(path, "http://google.com/api/v3")
52 | }
53 |
54 | func test_validate() {
55 | var email: String
56 | email = "supports@example.com"
57 | XCTAssertTrue(email.validate(String.Regex.Email2))
58 | email = "supports$@example.com"
59 | XCTAssertFalse(email.validate(String.Regex.Email2))
60 | email = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.com.vn"
61 | measure {
62 | XCTAssertTrue(email.validate(String.Regex.Email2))
63 | }
64 | }
65 |
66 | func test_trimmedLeftCJK() {
67 | let str = " \n hello \n world"
68 | let sub = str.trimmedLeftCJK()
69 | XCTAssertNotNil(sub)
70 | XCTAssertEqual(sub, "hello \n world")
71 | }
72 |
73 | func test_trimmedRightCJK() {
74 | let str = "hello \n world \n "
75 | let sub = str.trimmedRightCJK()
76 | XCTAssertNotNil(sub)
77 | XCTAssertEqual(sub, "hello \n world")
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Tests/UIView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView.swift
3 | // SwiftUtils
4 | //
5 | // Created by DaoNV on 9/4/16.
6 | // Copyright © 2016 Asian Tech Co., Ltd. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import SwiftUtils
11 |
12 | class UIViewTests: XCTestCase {
13 | func test_loadNib() {
14 | let xib: TestView = TestView.loadNib()
15 | XCTAssertNotNil(xib)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/fastlane/Fastfile:
--------------------------------------------------------------------------------
1 | default_platform :ios
2 |
3 | platform :ios do
4 | desc "Runs all the tests"
5 | lane :test do
6 | scan
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/fastlane/Scanfile:
--------------------------------------------------------------------------------
1 | scheme "PodTest"
2 | devices ["iPhone 6s"]
3 | clean true
--------------------------------------------------------------------------------
/scripts/branch:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | echo "Branch name: $TRAVIS_PULL_REQUEST_BRANCH"
4 |
5 | if [[ "$TRAVIS_PULL_REQUEST_BRANCH" == 'master' ]]; then
6 | exit 0
7 | fi
8 |
9 | for PREFIX in feature bugfix hotfix release; do
10 | if [[ "$TRAVIS_PULL_REQUEST_BRANCH" == $PREFIX/* ]]; then
11 | exit 0
12 | fi
13 | for CODE in app lib; do
14 | if [[ "$TRAVIS_PULL_REQUEST_BRANCH" == $CODE/$PREFIX/* ]]; then
15 | exit 0
16 | fi
17 | done
18 | done
19 |
20 | echo "Branch name does not pass convention."
21 | exit 1
22 |
--------------------------------------------------------------------------------
/scripts/codecov:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | bash <(curl -s https://codecov.io/bash)
4 |
--------------------------------------------------------------------------------
/scripts/install:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # DEV ENV
4 |
5 | # update submodule if need
6 | if [[ "$CI" != 'true' ]]; then
7 | git submodule update --init --recursive
8 | mkdir -p .git/hooks
9 | yes | cp -rf scripts/git/hooks/* .git/hooks/
10 | fi
11 |
12 | # homebrew
13 | if ! which brew > /dev/null; then
14 | sudo chown -R "$(whoami)":admin '/usr/local'
15 | /usr/bin/ruby -e "$(curl -fsSL 'https://raw.githubusercontent.com/Homebrew/install/master/install')"
16 | mkdir -p '/Library/Caches/Homebrew'
17 | sudo chown -R "$(whoami)":admin '/Library/Caches/Homebrew'
18 | fi
19 |
20 | brew update
21 |
22 | # rbenv if need
23 | if [[ "$CI" != 'true' ]]; then
24 | if ! which rbenv > /dev/null; then
25 | echo 'install rbenv'
26 | brew install rbenv
27 | eval "$(rbenv init -)"
28 | echo 'which rbenv > /dev/null && eval "$(rbenv init -)"' >> ~/.bashrc
29 | fi
30 | brew outdated ruby-build || brew upgrade ruby-build
31 | echo 'n' | rbenv install || true
32 | rbenv rehash
33 | fi
34 |
35 | gem install bundler
36 |
37 | # PROJECT DEPENDENCES
38 |
39 | bundle install --path=vendor/bundle --jobs 4 --retry 3
40 |
41 | brew tap Homebrew/bundle
42 | brew bundle
43 |
44 | if ! bundle exec pod install; then
45 | bundle exec pod install --repo-update
46 | fi
47 |
--------------------------------------------------------------------------------
/scripts/lint:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ./Pods/SwiftLint/swiftlint lint --reporter json > swiftlint-report.json || false
4 |
5 | echo "REPO_SLUG = $TRAVIS_REPO_SLUG"
6 | echo "PR_NUMBER = $TRAVIS_PULL_REQUEST"
7 |
8 | if [[ -z "$TRAVIS_PULL_REQUEST" ]]; then
9 | echo 'Not in a Pull Request, skip report.'
10 | else
11 | bundle exec linterbot "$TRAVIS_REPO_SLUG" "$TRAVIS_PULL_REQUEST" < swiftlint-report.json
12 | fi
13 |
--------------------------------------------------------------------------------
/scripts/pod_test:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [[ "$CI" != 'true' ]]; then
4 | echo 'Exporting build environment variables...'
5 | export SDK='iphonesimulator11.1'
6 | export WORKSPACE='SwiftUtils.xcworkspace'
7 | export DESTINATION='OS=11.1,name=iPhone 6'
8 | fi
9 |
10 | xcodebuild build \
11 | -workspace "$WORKSPACE" \
12 | -scheme "PodTest" \
13 | -sdk "$SDK" \
14 | -destination "$DESTINATION" \
15 | -derivedDataPath build \
16 | ONLY_ACTIVE_ARCH=YES \
17 | -configuration Debug | bundle exec xcpretty; exit ${PIPESTATUS[0]}
18 |
--------------------------------------------------------------------------------
/scripts/pr_number:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | USERNAME="$(echo ${REPO_SLUG%/*})"
4 | URL="https://api.github.com/repos/$REPO_SLUG/pulls?head=$USERNAME:$SRC_BRANCH"
5 | RESULT="$(curl -X GET -u $GITHUB_ACCESS_TOKEN:x-oauth-basic $URL | jq -r '.[0].url')"
6 | [[ "$RESULT" == 'null' ]] && PR_NUMBER='' || PR_NUMBER="${RESULT//\"}"
7 | PR_NUMBER="$(basename "$PR_NUMBER")"
8 | echo "$PR_NUMBER"
9 |
--------------------------------------------------------------------------------
/scripts/setup:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | brew update
3 | gem install bundler
4 | bundle install --path=vendor/bundle --jobs 4 --retry 3
5 | brew tap Homebrew/bundle
6 | brew bundle
7 |
8 | setup_cocoapods() {
9 | echo 'Setup cocoapods...'
10 | bundle exec pod setup --silent > /dev/null
11 | bundle exec pod repo update --silent
12 | bundle exec pod install
13 | }
14 |
15 | bundle exec pod install || setup_cocoapods
16 |
--------------------------------------------------------------------------------
/scripts/setup_rbenv:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | which rbenv > /dev/null && exit 0
4 |
5 | echo 'install rbenv'
6 | brew install rbenv
7 | eval "$(rbenv init -)"
8 | echo 'which rbenv > /dev/null && eval "$(rbenv init -)"' >> ~/.bashrc
9 |
10 | rbver="$(rbenv local)"
11 | [[ -z "$rbver" ]] && rbver=$(head -n 1 '.ruby-version')
12 | if [[ ! $(rbenv versions | grep "$rbver") ]]; then
13 | echo "install gem $rbver"
14 | rbenv install $rbver
15 | rbenv rehash
16 | fi
17 |
18 | rbenv global "$rbver"
19 |
20 | gem install bundler
21 |
--------------------------------------------------------------------------------
/scripts/src_branch:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [[ "$CIRCLECI" == 'true' ]]; then
4 | echo "$CIRCLE_BRANCH"
5 | exit 0
6 | fi
7 |
8 | if [[ "$TRAVIS_PULL_REQUEST" == 'false' ]]; then
9 | echo "$TRAVIS_BRANCH"
10 | else
11 | URL="https://api.github.com/repos/$TRAVIS_REPO_SLUG/pulls/$TRAVIS_PULL_REQUEST"
12 | RESULT="$(curl -X GET -u $GITHUB_ACCESS_TOKEN:x-oauth-basic $URL | jq -r '.head.ref')"
13 | [[ "$RESULT" == 'null' ]] && TRAVIS_BRANCH='' || TRAVIS_BRANCH="${RESULT//\"}"
14 | echo "$TRAVIS_BRANCH"
15 | fi
16 |
--------------------------------------------------------------------------------
/scripts/test:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [[ "$CI" != 'true' ]]; then
4 | echo 'Exporting build environment variables...'
5 | export WORKSPACE='SwiftUtils.xcworkspace'
6 | export SDK='iphonesimulator11.1'
7 | export SCHEME='SwiftUtils'
8 | export DESTINATION='OS=11.1,name=iPhone 6'
9 | fi
10 |
11 | rm -rf './build'
12 |
13 | xcodebuild build test \
14 | -workspace "$WORKSPACE" \
15 | -scheme "$SCHEME" \
16 | -sdk "$SDK" \
17 | -destination "$DESTINATION" \
18 | -derivedDataPath build \
19 | ONLY_ACTIVE_ARCH=YES \
20 | -configuration Debug | bundle exec xcpretty; exit ${PIPESTATUS[0]}
21 |
--------------------------------------------------------------------------------
/scripts/validate_branch:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | echo "Branch name: $SRC_BRANCH"
4 |
5 | [[ "$SRC_BRANCH" == master ]] && exit 0
6 |
7 | for PREFIX in feature bugfix hotfix release; do
8 | [[ "$SRC_BRANCH" == $PREFIX/* ]] && exit 0
9 | done
10 |
11 | echo "Branch name does not pass convention."
12 | exit 1
13 |
--------------------------------------------------------------------------------