+ - **Large Data -** [Downloading Data to a File](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#downloading-data-to-a-file), [Uploading Data to a Server](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#uploading-data-to-a-server)
+In order to keep Alamofire focused specifically on core networking implementations, additional component libraries have been created by the [Alamofire Software Foundation](https://github.com/Alamofire/Foundation) to bring additional functionality to the Alamofire ecosystem.
+
+- [AlamofireImage](https://github.com/Alamofire/AlamofireImage) - An image library including image response serializers, `UIImage` and `UIImageView` extensions, custom image filters, an auto-purging in-memory cache, and a priority-based image downloading system.
+- [AlamofireNetworkActivityIndicator](https://github.com/Alamofire/AlamofireNetworkActivityIndicator) - Controls the visibility of the network activity indicator on iOS using Alamofire. It contains configurable delay timers to help mitigate flicker and can support `URLSession` instances not managed by Alamofire.
+
+## Requirements
+
+| Platform | Minimum Swift Version | Installation | Status |
+| Linux | Latest Only | [Swift Package Manager](#swift-package-manager) | Building But Unsupported |
+| Windows | Latest Only | [Swift Package Manager](#swift-package-manager) | Building But Unsupported |
+
+#### Known Issues on Linux and Windows
+
+Alamofire builds on Linux and Windows but there are missing features and many issues in the underlying `swift-corelibs-foundation` that prevent full functionality and may cause crashes. These include:
+- `ServerTrustManager` and associated certificate functionality is unavailable, so there is no certificate pinning and no client certificate support.
+- Various methods of HTTP authentication may crash, including HTTP Basic and HTTP Digest. Crashes may occur if responses contain server challenges.
+- Cache control through `CachedResponseHandler` and associated APIs is unavailable, as the underlying delegate methods aren't called.
+- `URLSessionTaskMetrics` are never gathered.
+
+Due to these issues, Alamofire is unsupported on Linux and Windows. Please report any crashes to the [Swift bug reporter](https://bugs.swift.org).
+- If you **need help with making network requests** using Alamofire, use [Stack Overflow](https://stackoverflow.com/questions/tagged/alamofire) and tag `alamofire`.
+- If you need to **find or understand an API**, check [our documentation](http://alamofire.github.io/Alamofire/) or [Apple's documentation for `URLSession`](https://developer.apple.com/documentation/foundation/url_loading_system), on top of which Alamofire is built.
+- If you need **help with an Alamofire feature**, use [our forum on swift.org](https://forums.swift.org/c/related-projects/alamofire).
+- If you'd like to **discuss Alamofire best practices**, use [our forum on swift.org](https://forums.swift.org/c/related-projects/alamofire).
+- If you'd like to **discuss a feature request**, use [our forum on swift.org](https://forums.swift.org/c/related-projects/alamofire).
+- If you **found a bug**, open an issue here on GitHub and follow the guide. The more detail the better!
+
+## Installation
+
+### CocoaPods
+
+[CocoaPods](https://cocoapods.org) is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate Alamofire into your Xcode project using CocoaPods, specify it in your `Podfile`:
+
+```ruby
+pod 'Alamofire'
+```
+
+### Carthage
+
+[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. To integrate Alamofire into your Xcode project using Carthage, specify it in your `Cartfile`:
+
+```ogdl
+github "Alamofire/Alamofire"
+```
+
+### Swift Package Manager
+
+The [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler.
+
+Once you have your Swift package set up, adding Alamofire as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`.
+If you prefer not to use any of the aforementioned dependency managers, you can integrate Alamofire into your project manually.
+
+#### Embedded Framework
+
+- Open up Terminal, `cd` into your top-level project directory, and run the following command "if" your project is not initialized as a git repository:
+
+ ```bash
+ $ git init
+ ```
+
+- Add Alamofire as a git [submodule](https://git-scm.com/docs/git-submodule) by running the following command:
+- Open the new `Alamofire` folder, and drag the `Alamofire.xcodeproj` into the Project Navigator of your application's Xcode project.
+
+ > It should appear nested underneath your application's blue project icon. Whether it is above or below all the other Xcode groups does not matter.
+
+- Select the `Alamofire.xcodeproj` in the Project Navigator and verify the deployment target matches that of your application target.
+- Next, select your application project in the Project Navigator (blue project icon) to navigate to the target configuration window and select the application target under the "Targets" heading in the sidebar.
+- In the tab bar at the top of that window, open the "General" panel.
+- Click on the `+` button under the "Embedded Binaries" section.
+- You will see two different `Alamofire.xcodeproj` folders each with two different versions of the `Alamofire.framework` nested inside a `Products` folder.
+
+ > It does not matter which `Products` folder you choose from, but it does matter whether you choose the top or bottom `Alamofire.framework`.
+
+- Select the top `Alamofire.framework` for iOS and the bottom one for macOS.
+
+ > You can verify which one you selected by inspecting the build log for your project. The build target for `Alamofire` will be listed as `Alamofire iOS`, `Alamofire macOS`, `Alamofire tvOS`, or `Alamofire watchOS`.
+
+- And that's it!
+
+ > The `Alamofire.framework` is automagically added as a target dependency, linked framework and embedded framework in a copy files build phase which is all you need to build on the simulator and a device.
+
+## Contributing
+
+Before contributing to Alamofire, please read the instructions detailed in our [contribution guide](https://github.com/Alamofire/Alamofire/blob/master/CONTRIBUTING.md).
+
+## Open Radars
+
+The following radars have some effect on the current implementation of Alamofire.
+
+- [`rdar://21349340`](http://www.openradar.me/radar?id=5517037090635776) - Compiler throwing warning due to toll-free bridging issue in the test case
+- `rdar://26870455` - Background URL Session Configurations do not work in the simulator
+- `rdar://26849668` - Some URLProtocol APIs do not properly handle `URLRequest`
+
+## Resolved Radars
+
+The following radars have been resolved over time after being filed against the Alamofire project.
+
+- [`rdar://26761490`](http://www.openradar.me/radar?id=5010235949318144) - Swift string interpolation causing memory leak with common usage.
+ - (Resolved): 9/1/17 in Xcode 9 beta 6.
+- [`rdar://36082113`](http://openradar.appspot.com/radar?id=4942308441063424) - `URLSessionTaskMetrics` failing to link on watchOS 3.0+
+ - (Resolved): Just add `CFNetwork` to your linked frameworks.
+- `FB7624529` - `urlSession(_:task:didFinishCollecting:)` never called on watchOS
+ - (Resolved): Metrics now collected on watchOS 7+.
+
+## FAQ
+
+### What's the origin of the name Alamofire?
+
+Alamofire is named after the [Alamo Fire flower](https://aggie-horticulture.tamu.edu/wildseed/alamofire.html), a hybrid variant of the Bluebonnet, the official state flower of Texas.
+
+## Credits
+
+Alamofire is owned and maintained by the [Alamofire Software Foundation](http://alamofire.org). You can follow them on Twitter at [@AlamofireSF](https://twitter.com/AlamofireSF) for project updates and releases.
+
+### Security Disclosure
+
+If you believe you have identified a security vulnerability with Alamofire, you should report it as soon as possible via email to security@alamofire.org. Please do not post it to a public issue tracker.
+
+## Sponsorship
+
+The [ASF](https://github.com/Alamofire/Foundation#members) is looking to raise money to officially stay registered as a federal non-profit organization.
+Registering will allow Foundation members to gain some legal protections and also allow us to put donations to use, tax-free.
+Sponsoring the ASF will enable us to:
+
+- Pay our yearly legal fees to keep the non-profit in good status
+- Pay for our mail servers to help us stay on top of all questions and security issues
+- Potentially fund test servers to make it easier for us to test the edge cases
+- Potentially fund developers to work on one of our projects full-time
+
+The community adoption of the ASF libraries has been amazing.
+We are greatly humbled by your enthusiasm around the projects and want to continue to do everything we can to move the needle forward.
+With your continued support, the ASF will be able to improve its reach and also provide better legal safety for the core members.
+If you use any of our libraries for work, see if your employers would be interested in donating.
+Any amount you can donate, whether once or monthly, to help us reach our goal would be greatly appreciated.
+ /// Event called during `URLSessionDownloadDelegate`'s `urlSession(_:downloadTask:didResumeAtOffset:expectedTotalBytes:)` method.
+ func urlSession(_ session: URLSession,
+ downloadTask: URLSessionDownloadTask,
+ didResumeAtOffset fileOffset: Int64,
+ expectedTotalBytes: Int64)
+
+ /// Event called during `URLSessionDownloadDelegate`'s `urlSession(_:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:)` method.
+ func urlSession(_ session: URLSession,
+ downloadTask: URLSessionDownloadTask,
+ didWriteData bytesWritten: Int64,
+ totalBytesWritten: Int64,
+ totalBytesExpectedToWrite: Int64)
+
+ /// Event called during `URLSessionDownloadDelegate`'s `urlSession(_:downloadTask:didFinishDownloadingTo:)` method.
+ Invalid JSON object provided for parameter or object encoding. \
+ This is most likely due to a value which can't be represented in Objective-C.
+ """
+ }
+}
+
+// MARK: -
+
+extension NSNumber {
+ fileprivate var isBool: Bool {
+ // Use Obj-C type encoding to check whether the underlying type is a `Bool`, as it's guaranteed as part of
+ // swift-corelibs-foundation, per [this discussion on the Swift forums](https://forums.swift.org/t/alamofire-on-linux-possible-but-not-release-ready/34553/22).
+ /// Creates a download file destination closure which uses the default file manager to move the temporary file to a
+ /// file URL in the first available directory with the specified search path directory and search path domain mask.
+ ///
+ /// - Parameters:
+ /// - directory: The search path directory. `.documentDirectory` by default.
+ /// - domain: The search path domain mask. `.userDomainMask` by default.
+ /// - options: `DownloadRequest.Options` used when moving the downloaded file to its destination. None by
+ /// default.
+ /// - Returns: The `Destination` closure.
+ public class func suggestedDownloadDestination(for directory: FileManager.SearchPathDirectory = .documentDirectory,
+ in domain: FileManager.SearchPathDomainMask = .userDomainMask,
+ options: Options = []) -> Destination {
+ { temporaryURL, response in
+ let directoryURLs = FileManager.default.urls(for: directory, in: domain)
+ let url = directoryURLs.first?.appendingPathComponent(response.suggestedFilename!) ?? temporaryURL
+
+ return (url, options)
+ }
+ }
+
+ /// Default `Destination` used by Alamofire to ensure all downloads persist. This `Destination` prepends
+ /// `Alamofire_` to the automatically generated download name and moves it within the temporary directory. Files
+ /// with this destination must be additionally moved if they should survive the system reclamation of temporary
+ /// space.
+ static let defaultDestination: Destination = { url, _ in
+ (defaultDestinationURL(url), [])
+ }
+
+ /// Default `URL` creation closure. Creates a `URL` in the temporary directory with `Alamofire_` prepended to the
+ /// provided file name.
+ static let defaultDestinationURL: (URL) -> URL = { url in
+ let filename = "Alamofire_\(url.lastPathComponent)"
+ let destination = url.deletingLastPathComponent().appendingPathComponent(filename)
+
+ return destination
+ }
+
+ // MARK: Downloadable
+
+ /// Type describing the source used to create the underlying `URLSessionDownloadTask`.
+ public enum Downloadable {
+ /// Download should be started from the `URLRequest` produced by the associated `URLRequestConvertible` value.
+ case request(URLRequestConvertible)
+ /// Download should be started from the associated resume `Data` value.
+ case resumeData(Data)
+ }
+
+ // MARK: Mutable State
+
+ /// Type containing all mutable state for `DownloadRequest` instances.
+ private struct DownloadRequestMutableState {
+ /// Possible resume `Data` produced when cancelling the instance.
+ var resumeData: Data?
+ /// `URL` to which `Data` is being downloaded.
+ var fileURL: URL?
+ }
+
+ /// Protected mutable state specific to `DownloadRequest`.
+ @Protected
+ private var mutableDownloadState = DownloadRequestMutableState()
+
+ /// If the download is resumable and is eventually cancelled or fails, this value may be used to resume the download
+ /// using the `download(resumingWith data:)` API.
+ ///
+ /// - Note: For more information about `resumeData`, see [Apple's documentation](https://developer.apple.com/documentation/foundation/urlsessiondownloadtask/1411634-cancel).
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+/// A retry policy that retries requests using an exponential backoff for allowed HTTP methods and HTTP status codes
+/// as well as certain types of networking errors.
+open class RetryPolicy: RequestInterceptor {
+ /// The default retry limit for retry policies.
+ public static let defaultRetryLimit: UInt = 2
+
+ /// The default exponential backoff base for retry policies (must be a minimum of 2).
+ public static let defaultExponentialBackoffBase: UInt = 2
+
+ /// The default exponential backoff scale for retry policies.
+ public static let defaultExponentialBackoffScale: Double = 0.5
+
+ /// The default HTTP methods to retry.
+ /// See [RFC 2616 - Section 9.1.2](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html) for more information.
+ public static let defaultRetryableHTTPMethods: Set<HTTPMethod> = [.delete, // [Delete](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.7) - not always idempotent
+ .get, // [GET](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.3) - generally idempotent
+ .head, // [HEAD](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4) - generally idempotent
+ public static let defaultRetryableURLErrorCodes: Set<URLError.Code> = [// [Security] App Transport Security disallowed a connection because there is no secure network connection.
+ // - [Disabled] ATS settings do not change at runtime.
+/// An evaluator which Uses the default and revoked server trust evaluations allowing you to control whether to validate
+/// the host provided by the challenge as well as specify the revocation flags for testing for revoked certificates.
+/// Apple platforms did not start testing for revoked certificates automatically until iOS 10.1, macOS 10.12 and tvOS
+/// 10.1 which is demonstrated in our TLS tests. Applications are encouraged to always validate the host in production
+/// environments to guarantee the validity of the server's certificate chain.
+public final class RevocationTrustEvaluator: ServerTrustEvaluating {
+ /// Represents the options to be use when evaluating the status of a certificate.
+ /// Only Revocation Policy Constants are valid, and can be found in [Apple's documentation](https://developer.apple.com/documentation/security/certificate_key_and_trust_services/policies/1563600-revocation_policy_constants).
+ public struct Options: OptionSet {
+ /// Perform revocation checking using the CRL (Certification Revocation List) method.
+ public static let crl = Options(rawValue: kSecRevocationCRLMethod)
+ /// Consult only locally cached replies; do not use network access.
+ public static let networkAccessDisabled = Options(rawValue: kSecRevocationNetworkAccessDisabled)
+ /// Perform revocation checking using OCSP (Online Certificate Status Protocol).
+ public static let ocsp = Options(rawValue: kSecRevocationOCSPMethod)
+ /// Prefer CRL revocation checking over OCSP; by default, OCSP is preferred.
+ public static let preferCRL = Options(rawValue: kSecRevocationPreferCRL)
+ /// Require a positive response to pass the policy. If the flag is not set, revocation checking is done on a
+ /// "best attempt" basis, where failure to reach the server is not considered fatal.
+ public static let requirePositiveResponse = Options(rawValue: kSecRevocationRequirePositiveResponse)
+ /// Perform either OCSP or CRL checking. The checking is performed according to the method(s) specified in the
+ /// certificate and the value of `preferCRL`.
+ public static let any = Options(rawValue: kSecRevocationUseAnyAvailableMethod)
+
+ /// The raw value of the option.
+ public let rawValue: CFOptionFlags
+
+ /// Creates an `Options` value with the given `CFOptionFlags`.
+ ///
+ /// - Parameter rawValue: The `CFOptionFlags` value to initialize with.
+ public init(rawValue: CFOptionFlags) {
+ self.rawValue = rawValue
+ }
+ }
+
+ private let performDefaultValidation: Bool
+ private let validateHost: Bool
+ private let options: Options
+
+ /// Creates a `RevocationTrustEvaluator` using the provided parameters.
+ ///
+ /// - Note: Default and host validation will fail when using this evaluator with self-signed certificates. Use
+ /// `PinnedCertificatesTrustEvaluator` if you need to use self-signed certificates.
+ ///
+ /// - Parameters:
+ /// - performDefaultValidation: Determines whether default validation should be performed in addition to
+ /// evaluating the pinned certificates. `true` by default.
+ /// - validateHost: Determines whether or not the evaluator should validate the host, in addition to
+ /// performing the default evaluation, even if `performDefaultValidation` is `false`.
+ /// `true` by default.
+ /// - options: The `Options` to use to check the revocation status of the certificate. `.any` by
+ /// This type is derived from [`JSONEncoder`'s `KeyEncodingStrategy`](https://github.com/apple/swift/blob/6aa313b8dd5f05135f7f878eccc1db6f9fbe34ff/stdlib/public/Darwin/Foundation/JSONEncoder.swift#L128)
+ /// and [`XMLEncoder`s `KeyEncodingStrategy`](https://github.com/MaxDesiatov/XMLCoder/blob/master/Sources/XMLCoder/Encoder/XMLEncoder.swift#L102).
+ public enum KeyEncoding {
+ /// Use the keys specified by each type. This is the default encoding.
+ case useDefaultKeys
+ /// Convert from "camelCaseKeys" to "snake_case_keys" before writing a key.
+ ///
+ /// Capital characters are determined by testing membership in
+ /// `CharacterSet.uppercaseLetters` and `CharacterSet.lowercaseLetters`
+ /// (Unicode General Categories Lu and Lt).
+ /// The conversion to lower case uses `Locale.system`, also known as
+ /// the ICU "root" locale. This means the result is consistent
+ /// regardless of the current user's locale and language preferences.
+ ///
+ /// Converting from camel case to snake case:
+ /// 1. Splits words at the boundary of lower-case to upper-case
+ /// 2. Inserts `_` between words
+ /// 3. Lowercases the entire string
+ /// 4. Preserves starting and ending `_`.
+ ///
+ /// For example, `oneTwoThree` becomes `one_two_three`. `_oneTwoThree_` becomes `_one_two_three_`.
+ ///
+ /// - Note: Using a key encoding strategy has a nominal performance cost, as each string key has to be converted.
+ case convertToSnakeCase
+ /// Same as convertToSnakeCase, but using `-` instead of `_`.
+ /// For example `oneTwoThree` becomes `one-two-three`.
+ case convertToKebabCase
+ /// Capitalize the first letter only.
+ /// For example `oneTwoThree` becomes `OneTwoThree`.
+ case capitalized
+ /// Uppercase all letters.
+ /// For example `oneTwoThree` becomes `ONETWOTHREE`.
+ case uppercased
+ /// Lowercase all letters.
+ /// For example `oneTwoThree` becomes `onetwothree`.
+ case lowercased
+ /// A custom encoding using the provided closure.
+ case custom((String) -> String)
+
+ func encode(_ key: String) -> String {
+ switch self {
+ case .useDefaultKeys: return key
+ case .convertToSnakeCase: return convertToSnakeCase(key)
+ case .convertToKebabCase: return convertToKebabCase(key)
+ case .capitalized: return String(key.prefix(1).uppercased() + key.dropFirst())
+ case .uppercased: return key.uppercased()
+ case .lowercased: return key.lowercased()
+ case let .custom(encoding): return encoding(key)
+Currently in SwiftUI, the only way to inform the user about some process that finished for example, is by using `Alert`. Sometimes, you just want to pop a message that tells the user that something completed, or his message was sent. Apple doesn't provide any other method rather than using `Alert` even though Apple using all kinds of different pop-ups. The results are poor UX where the user would need to tap "OK/Dismiss" for every little information that he should be notified about.
+
+Alert Toast is an open-source library in Github to use with SwiftUI. It allows you to present popups that don't need any user action to dismiss or to validate. Some great usage examples: `Message Sent`, `Poor Network Connection`, `Profile Updated`, `Logged In/Out`, `Favorited`, `Loading` and so on...
+CocoaPods is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate `AlertToast` into your Xcode project using CocoaPods, specify it in your Podfile:
+
+```ruby
+pod 'AlertToast'
+```
+
+------
+
+### Swift Package Manager
+
+The [Swift Package Manager](https://swift.org/package-manager/) is a tool for managing the distribution of Swift code. It’s integrated with the Swift build system to automate the process of downloading, compiling, and linking dependencies.
+
+To integrate `AlertToast` into your Xcode project using Xcode 12, specify it in `File > Swift Packages > Add Package Dependency...`:
+If you prefer not to use any of dependency managers, you can integrate `AlertToast` into your project manually. Put `Sources/AlertToast` folder in your Xcode project. Make sure to enable `Copy items if needed` and `Create groups`.
+
+## 🧳 Requirements
+
+- iOS 13.0+ | macOS 11+
+- Xcode 12.0+ | Swift 5+
+
+## 🛠 Usage
+
+First, add `import AlertToast` on every `swift` file you would like to use `AlertToast`.
+
+Then, use the `.toast` view modifier:
+
+**Parameters:**
+
+- `isPresenting`: (MUST) assign a `Binding<Bool>` to show or dismiss alert.
+- `duration`: default is 2, set 0 to disable auto dismiss.
+- `tapToDismiss`: default is `true`, set `false` to disable.
+//Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+//
+//The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ Execute the closure without triggering change events.
+
+ Any `Defaults` key changes made within the closure will not propagate to `Defaults` event listeners (`Defaults.observe()` and `Defaults.publisher()`). This can be useful to prevent infinite recursion when you want to change a key in the callback listening to changes for the same key.
+
+ - Note: This only works with `Defaults.observe()` and `Defaults.publisher()`. User-made KVO will not be affected.
+
+ ```
+ let observer = Defaults.observe(keys: .key1, .key2) {
+ // …
+
+ Defaults.withoutPropagation {
+ // Update `.key1` without propagating the change to listeners.
+ Defaults[.key1] = 11
+ }
+
+ // This will be propagated.
+ Defaults[.someKey] = true
+ }
+ ```
+ */
+ public static func withoutPropagation(_ closure: () -> Void) {
+ // How does it work?
+ // KVO observation callbacks are executed right after a change is made, and run on the same thread as the caller. So it works by storing a flag in the current thread's dictionary, which is then evaluated in the callback.
+
+ let key = preventPropagationThreadDictionaryKey
+ Thread.current.threadDictionary[key] = true
+ closure()
+ Thread.current.threadDictionary[key] = false
+ }
+
+ final class UserDefaultsKeyObservation: NSObject, Observation {
+ Reset the given string keys back to their default values.
+
+ Prefer using the strongly-typed keys instead whenever possible. This method can be useful if you need to store some keys in a collection, as it's not possible to store `Defaults.Key` in a collection because it's generic.
+
+ - Parameter keys: String keys to reset.
+ - Parameter suite: `UserDefaults` suite.
+
+ ```
+ extension Defaults.Keys {
+ static let isUnicornMode = Key<Bool>("isUnicornMode", default: false)
+ Reset the given string keys back to their default values.
+
+ Prefer using the strongly-typed keys instead whenever possible. This method can be useful if you need to store some keys in a collection, as it's not possible to store `Defaults.Key` in a collection because it's generic.
+
+ - Parameter keys: String keys to reset.
+ - Parameter suite: `UserDefaults` suite.
+
+ ```
+ extension Defaults.Keys {
+ static let isUnicornMode = Key<Bool>("isUnicornMode", default: false)
+ is Bool?.Type, // swiftlint:disable:this discouraged_optional_boolean
+ is String.Type,
+ is String?.Type,
+ is Int.Type,
+ is Int?.Type,
+ is Double.Type,
+ is Double?.Type,
+ is Float.Type,
+ is Float?.Type,
+ is Date.Type,
+ is Date?.Type,
+ is Data.Type,
+ is Data?.Type:
+ return true
+ default:
+ return false
+ }
+ }
+}
+
+extension UserDefaults {
+ /**
+ Remove all entries.
+
+ - Note: This only removes user-defined entries. System-defined entries will remain.
+ */
+ public func removeAll() {
+ // We're not using `.removePersistentDomain(forName:)` as it requires knowing the suite name and also because it doesn't emit change events for each key, but rather just `UserDefaults.didChangeNotification`, which we don't subscribe to.
+ private static let associatedObjects = ObjectAssociation<[ObjectLifetimeTracker]>()
+ private weak var wrappedObject: ObjectLifetimeTracker?
+ private weak var owner: AnyObject?
+
+ /**
+ Causes the given target object to live at least as long as either the given owner object or the resulting `LifetimeAssociation`, whichever is deallocated first.
+
+ When either the owner or the new `LifetimeAssociation` is destroyed, the given deinit handler, if any, is called.
+
+ ```
+ class Ghost {
+ var association: LifetimeAssociation?
+
+ func haunt(_ host: Furniture) {
+ association = LifetimeAssociation(of: self, with: host) { [weak self] in
+ // Host has been deinitialized
+ self?.haunt(seekHost())
+ }
+ }
+ }
+
+ let piano = Piano()
+ Ghost().haunt(piano)
+ // The Ghost will remain alive as long as `piano` remains alive.
+ ```
+
+ - Parameter target: The object whose lifetime will be extended.
+ - Parameter owner: The object whose lifetime extends the target object's lifetime.
+ - Parameter deinitHandler: An optional closure to call when either `owner` or the resulting `LifetimeAssociation` is deallocated.
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+> Swifty and modern [UserDefaults](https://developer.apple.com/documentation/foundation/userdefaults)
+
+Store key-value pairs persistently across launches of your app.
+
+It uses `NSUserDefaults` underneath but exposes a type-safe facade with lots of nice conveniences.
+
+It's used in production by apps like [Gifski](https://github.com/sindresorhus/Gifski), [Dato](https://sindresorhus.com/dato), [Lungo](https://sindresorhus.com/lungo), [Battery Indicator](https://sindresorhus.com/battery-indicator), and [HEIC Converter](https://sindresorhus.com/heic-converter).
+
+For a real-world example, see my [Plash app](https://github.com/sindresorhus/Plash/blob/533dbc888d8ba3bd9581e60320af282a22c53f85/Plash/Constants.swift#L9-L18).
+
+## Highlights
+
+- **Strongly typed:** You declare the type and default value upfront.
+- **Codable support:** You can store any [Codable](https://developer.apple.com/documentation/swift/codable) value, like an enum.
+- **NSSecureCoding support:** You can store any [NSSecureCoding](https://developer.apple.com/documentation/foundation/nssecurecoding) value.
+- **SwiftUI:** Property wrapper that updates the view when the `UserDefaults` value changes.
+- **Publishers:** Combine publishers built-in.
+- **Observation:** Observe changes to keys.
+- **Debuggable:** The data is stored as JSON-serialized values.
+
+## Compatibility
+
+- macOS 10.12+
+- iOS 10+
+- tvOS 10+
+- watchOS 3+
+
+## Install
+
+#### Swift Package Manager
+
+Add `https://github.com/sindresorhus/Defaults` in the [“Swift Package Manager” tab in Xcode](https://developer.apple.com/documentation/xcode/adding_package_dependencies_to_your_app).
+
+#### Carthage
+
+```
+github "sindresorhus/Defaults"
+```
+
+#### CocoaPods
+
+```ruby
+pod 'Defaults'
+```
+
+## Usage
+
+You declare the defaults keys upfront with type and default value.
+
+```swift
+import Cocoa
+import Defaults
+
+extension Defaults.Keys {
+ static let quality = Key<Double>("quality", default: 0.8)
+ // ^ ^ ^ ^
+ // Key Type UserDefaults name Default value
+}
+```
+
+You can then access it as a subscript on the `Defaults` global:
+
+```swift
+Defaults[.quality]
+//=> 0.8
+
+Defaults[.quality] = 0.5
+//=> 0.5
+
+Defaults[.quality] += 0.1
+//=> 0.6
+
+Defaults[.quality] = "🦄"
+//=> [Cannot assign value of type 'String' to type 'Double']
+```
+
+You can also declare optional keys for when you don't want to declare a default value upfront:
+
+```swift
+extension Defaults.Keys {
+ static let name = Key<Double?>("name")
+}
+
+if let name = Defaults[.name] {
+ print(name)
+}
+```
+
+The default value is then `nil`.
+
+---
+
+If you have `NSSecureCoding` classes which you want to save, you can use them as follows:
+You can use the `@Default` property wrapper to get/set a `Defaults` item and also have the view be updated when the value changes. This is similar to `@State`.
+
+```swift
+extension Defaults.Keys {
+ static let hasUnicorn = Key<Bool>("hasUnicorn", default: false)
+}
+
+struct ContentView: View {
+ @Default(.hasUnicorn) var hasUnicorn
+
+ var body: some View {
+ Text("Has Unicorn: \(hasUnicorn)")
+ Toggle("Toggle Unicorn", isOn: $hasUnicorn)
+ }
+}
+```
+
+Note that it's `@Default`, not `@Defaults`.
+
+You cannot use `@Default` in an `ObservableObject`. It's meant to be used in a `View`.
+
+This is only implemented for `Defaults.Key`. PR welcome for `Defaults.NSSecureCoding` if you need it.
+
+### Observe changes to a key
+
+```swift
+extension Defaults.Keys {
+ static let isUnicornMode = Key<Bool>("isUnicornMode", default: false)
+}
+
+let observer = Defaults.observe(.isUnicornMode) { change in
+ // Initial event
+ print(change.oldValue)
+ //=> false
+ print(change.newValue)
+ //=> false
+
+ // First actual event
+ print(change.oldValue)
+ //=> false
+ print(change.newValue)
+ //=> true
+}
+
+Defaults[.isUnicornMode] = true
+```
+
+In contrast to the native `UserDefaults` key observation, here you receive a strongly-typed change object.
+
+There is also an observation API using the [Combine](https://developer.apple.com/documentation/combine) framework, exposing a [Publisher](https://developer.apple.com/documentation/combine/publisher) for key changes:
+ static let isUnicornMode = Key<Bool>("isUnicornMode", default: false)
+}
+
+final class Foo {
+ init() {
+ Defaults.observe(.isUnicornMode) { change in
+ print(change.oldValue)
+ print(change.newValue)
+ }.tieToLifetime(of: self)
+ }
+}
+
+Defaults[.isUnicornMode] = true
+```
+
+The observation will be valid until `self` is deinitialized.
+
+### Reset keys to their default values
+
+```swift
+extension Defaults.Keys {
+ static let isUnicornMode = Key<Bool>("isUnicornMode", default: false)
+}
+
+Defaults[.isUnicornMode] = true
+//=> true
+
+Defaults.reset(.isUnicornMode)
+
+Defaults[.isUnicornMode]
+//=> false
+```
+
+This works for a `Key` with an optional too, which will be reset back to `nil`.
+
+### Control propagation of change events
+
+Changes made within the `Defaults.withoutPropagation` closure will not be propagated to observation callbacks (`Defaults.observe()` or `Defaults.publisher()`), and therefore could prevent infinite recursion.
+ static let isUnicorn = Key<Bool>("isUnicorn", default: true, suite: extensionDefaults)
+}
+
+Defaults[.isUnicorn]
+//=> true
+
+// Or
+
+extensionDefaults[.isUnicorn]
+//=> true
+```
+
+### Default values are registered with `UserDefaults`
+
+When you create a `Defaults.Key`, it automatically registers the `default` value with normal `UserDefaults`. This means you can make use of the default value in, for example, bindings in Interface Builder.
+
+```swift
+extension Defaults.Keys {
+ static let isUnicornMode = Key<Bool>("isUnicornMode", default: true)
+Create a NSSecureCoding key with an optional value.
+
+#### `Defaults.reset(keys…)`
+
+Type: `func`
+
+Reset the given keys back to their default values.
+
+You can specify up to 10 keys. If you need to specify more, call this method multiple times.
+
+You can also specify string keys, which can be useful if you need to store some keys in a collection, as it's not possible to store `Defaults.Key` in a collection because it's generic.
+By default, it will also trigger an initial event on creation. This can be useful for setting default values on controls. You can override this behavior with the `options` argument.
+
+#### `Defaults.observe(keys: keys..., options:)`
+
+Type: `func`
+
+Observe multiple keys of any type, but without any information about the changes.
+
+Options are the same as in `.observe(…)` for a single key.
+Observation API using [Publisher](https://developer.apple.com/documentation/combine/publisher) from the [Combine](https://developer.apple.com/documentation/combine) framework.
+
+Available on macOS 10.15+, iOS 13.0+, tvOS 13.0+, and watchOS 6.0+.
+
+#### `Defaults.publisher(keys: keys…, options:)`
+
+Type: `func`
+
+[Combine](https://developer.apple.com/documentation/combine) observation API for multiple key observation, but without specific information about changes.
+
+Available on macOS 10.15+, iOS 13.0+, tvOS 13.0+, and watchOS 6.0+.
+Keep the observation alive for as long as, and no longer than, another object exists.
+
+When `weaklyHeldObject` is deinitialized, the observation is invalidated automatically.
+
+#### `Defaults.Observation.removeLifetimeTie`
+
+```swift
+Defaults.Observation#removeLifetimeTie()
+```
+
+Type: `func`
+
+Break the lifetime tie created by `tieToLifetime(of:)`, if one exists.
+
+The effects of any call to `tieToLifetime(of:)` are reversed. Note however that if the tied-to object has already died, then the observation is already invalid and this method has no logical effect.
+
+#### `Defaults.withoutPropagation(_ closure:)`
+
+Execute the closure without triggering change events.
+
+Any `Defaults` key changes made within the closure will not propagate to `Defaults` event listeners (`Defaults.observe()` and `Defaults.publisher()`). This can be useful to prevent infinite recursion when you want to change a key in the callback listening to changes for the same key.
+
+### `@Default(_ key:)`
+
+Get/set a `Defaults` item and also have the view be updated when the value changes.
+
+This is only implemented for `Defaults.Key`. PR welcome for `Defaults.NSSecureCoding` if you need it.
+
+## FAQ
+
+### How can I store a dictionary of arbitrary values?
+
+You cannot store `[String: Any]` directly as it cannot conform to `Codable`. However, you can use the [`AnyCodable`](https://github.com/Flight-School/AnyCodable) package to work around this `Codable` limitation:
+
+```swift
+import AnyCodable
+
+extension Defaults.Keys {
+ static let magic = Key<[String: AnyCodable]>("magic", default: [:])
+}
+
+// …
+
+Defaults[.magic]["unicorn"] = "🦄"
+
+if let value = Defaults[.magic]["unicorn"]?.value {
+ print(value)
+ //=> "🦄"
+}
+
+Defaults[.magic]["number"] = 3
+Defaults[.magic]["boolean"] = true
+```
+
+### How is this different from [`SwiftyUserDefaults`](https://github.com/radex/SwiftyUserDefaults)?
+
+It's inspired by that package and other solutions. The main difference is that this module doesn't hardcode the default values and comes with Codable support.
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+2. ObjectMapper
+
+The MIT License (MIT)
+Copyright (c) 2014 Hearst
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+HandyJSON is a framework written in Swift which to make converting model objects( **pure classes/structs** ) to and from JSON easy on iOS.
+
+Compared with others, the most significant feature of HandyJSON is that it does not require the objects inherit from NSObject(**not using KVC but reflection**), neither implements a 'mapping' function(**writing value to memory directly to achieve property assignment**).
+
+HandyJSON is totally depend on the memory layout rules infered from Swift runtime code. We are watching it and will follow every bit if it changes.
+* Open the new `HandyJSON` folder, drag the `HandyJSON.xcodeproj` into the `Project Navigator` of your project.
+
+* Select your application project in the `Project Navigator`, open the `General` panel in the right window.
+
+* Click on the `+` button under the `Embedded Binaries` section.
+
+* You will see two different `HandyJSON.xcodeproj` folders each with four different versions of the HandyJSON.framework nested inside a Products folder.
+> It does not matter which Products folder you choose from, but it does matter which HandyJSON.framework you choose.
+
+* Select one of the four `HandyJSON.framework` which matches the platform your Application should run on.
+
+* Congratulations!
+
+# Deserialization
+
+## The Basics
+
+To support deserialization from JSON, a class/struct need to conform to 'HandyJSON' protocol. It's truly protocol, not some class inherited from NSObject.
+
+To conform to 'HandyJSON', a class need to implement an empty initializer.
+if let object = BasicTypes.deserialize(from: jsonString) {
+ // …
+}
+```
+
+But also notice that, if you have a designated initializer to override the default one in the struct, you should explicitly declare an empty one(no `required` modifier need).
+
+## Support Enum Property
+
+To be convertable, An `enum` must conform to `HandyJSONEnum` protocol. Nothing special need to do now.
+'HandyJSON' support classes/structs composed of `optional`, `implicitlyUnwrappedOptional`, `array`, `dictionary`, `objective-c base type`, `nested type` etc. properties.
+
+```swift
+class BasicTypes: HandyJSON {
+ var bool: Bool = true
+ var intOptional: Int?
+ var doubleImplicitlyUnwrapped: Double!
+ var anyObjectOptional: Any?
+
+ var arrayInt: Array<Int> = []
+ var arrayStringOptional: Array<String>?
+ var setInt: Set<Int>?
+ var dictAnyObject: Dictionary<String, Any> = [:]
+if let cats = [Cat].deserialize(from: jsonArrayString) {
+ cats.forEach({ (cat) in
+ // ...
+ })
+}
+```
+
+## Mapping From Dictionary
+
+`HandyJSON` support mapping swift dictionary to model.
+
+```swift
+var dict = [String: Any]()
+dict["doubleOptional"] = 1.1
+dict["stringImplicitlyUnwrapped"] = "hello"
+dict["int"] = 1
+if let object = BasicTypes.deserialize(from: dict) {
+ // ...
+}
+```
+
+## Custom Mapping
+
+`HandyJSON` let you customize the key mapping to JSON fields, or parsing method of any property. All you need to do is implementing an optional `mapping` function, do things in it.
+
+We bring the transformer from [`ObjectMapper`](https://github.com/Hearst-DD/ObjectMapper). If you are familiar with it, it’s almost the same here.
+
+```swift
+class Cat: HandyJSON {
+ var id: Int64!
+ var name: String!
+ var parent: (String, String)?
+ var friendName: String?
+
+ required init() {}
+
+ func mapping(mapper: HelpingMapper) {
+ // specify 'cat_id' field in json map to 'id' property in object
+ mapper <<<
+ self.id <-- "cat_id"
+
+ // specify 'parent' field in json parse as following to 'parent' property in object
+If any non-basic property of a class/struct could not conform to `HandyJSON`/`HandyJSONEnum` or you just do not want to do the deserialization with it, you should exclude it in the mapping function.
+* `Optional<T>/ImplicitUnwrappedOptional<T>` // T is one of the above types
+
+* `Array<T>` // T is one of the above types
+
+* `Dictionary<String, T>` // T is one of the above types
+
+* Nested of aboves
+
+# Serialization
+
+## The Basics
+
+Now, a class/model which need to serialize to JSON should also conform to `HandyJSON` protocol.
+
+```swift
+class BasicTypes: HandyJSON {
+ var int: Int = 2
+ var doubleOptional: Double?
+ var stringImplicitlyUnwrapped: String!
+
+ required init() {}
+}
+
+let object = BasicTypes()
+object.int = 1
+object.doubleOptional = 1.1
+object.stringImplicitlyUnwrapped = “hello"
+
+print(object.toJSON()!) // serialize to dictionary
+print(object.toJSONString()!) // serialize to JSON string
+print(object.toJSONString(prettyPrint: true)!) // serialize to pretty JSON string
+```
+
+## Mapping And Excluding
+
+It’s all like what we do on deserialization. A property which is excluded, it will not take part in neither deserialization nor serialization. And the mapper items define both the deserializing rules and serializing rules. Refer to the usage above.
+
+# FAQ
+
+## Q: Why the mapping function is not working in the inheritance object?
+
+A: For some reason, you should define an empty mapping function in the super class(the root class if more than one layer), and override it in the subclass.
+
+It's the same with `didFinishMapping` function.
+
+## Q: Why my didSet/willSet is not working?
+
+A: Since `HandyJSON` assign properties by writing value to memory directly, it doesn't trigger any observing function. You need to call the `didSet/willSet` logic explicitly after/before the deserialization.
+
+But since version `1.8.0`, `HandyJSON` handle dynamic properties by the `KVC` mechanism which will trigger the `KVO`. That means, if you do really need the `didSet/willSet`, you can define your model like follow:
+
+```swift
+class BasicTypes: NSObject, HandyJSON {
+ dynamic var int: Int = 0 {
+ didSet {
+ print("oldValue: ", oldValue)
+ }
+ willSet {
+ print("newValue: ", newValue)
+ }
+ }
+
+ public override required init() {}
+}
+```
+
+In this situation, `NSObject` and `dynamic` are both needed.
+
+And in versions since `1.8.0`, `HandyJSON` offer a `didFinishMapping` function to allow you to fill some observing logic.
+
+```swift
+class BasicTypes: HandyJSON {
+ var int: Int?
+
+ required init() {}
+
+ func didFinishMapping() {
+ print("you can fill some observing logic here")
+ }
+}
+
+```
+
+It may help.
+
+## Q: How to support Enum property?
+
+It your enum conform to `RawRepresentable` protocol, please look into [Support Enum Property](#support-enum-property). Or use the `EnumTransform`:
+Otherwise, you should implement your custom mapping function.
+
+```swift
+enum EnumType {
+ case type1, type2
+}
+
+class BasicTypes: HandyJSON {
+ var type: EnumType?
+
+ func mapping(mapper: HelpingMapper) {
+ mapper <<<
+ type <-- TransformOf<EnumType, String>(fromJSON: { (rawString) -> EnumType? in
+ if let _str = rawString {
+ switch (_str) {
+ case "type1":
+ return EnumType.type1
+ case "type2":
+ return EnumType.type2
+ default:
+ return nil
+ }
+ }
+ return nil
+ }, toJSON: { (enumType) -> String? in
+ if let _type = enumType {
+ switch (_type) {
+ case EnumType.type1:
+ return "type1"
+ case EnumType.type2:
+ return "type2"
+ }
+ }
+ return nil
+ })
+ }
+
+ required init() {}
+}
+```
+
+# Credit
+
+* [reflection](https://github.com/Zewo/Reflection): After the first version which used the swift mirror mechanism, HandyJSON had imported the reflection library and rewrote some code for class properties inspecting.
+* [ObjectMapper](https://github.com/tristanhimmelman/ObjectMapper): To make HandyJSON more compatible with the general style, the Mapper function support Transform which designed by ObjectMapper. And we import some testcases from ObjectMapper.
+
+# License
+
+HandyJSON is released under the Apache License, Version 2.0. See LICENSE for details.
+*A Chinese version of this document can be found [here](https://github.com/Moya/Moya/blob/master/Readme_CN.md).*
+
+You're a smart developer. You probably use [Alamofire](https://github.com/Alamofire/Alamofire) to abstract away access to
+`URLSession` and all those nasty details you don't really care about. But then,
+like lots of smart developers, you write ad hoc network abstraction layers. They
+are probably called "APIManager" or "NetworkModel", and they always end in tears.
+
+
+
+Ad hoc network layers are common in iOS apps. They're bad for a few reasons:
+
+- Makes it hard to write new apps ("where do I begin?")
+- Makes it hard to maintain existing apps ("oh my god, this mess...")
+- Makes it hard to write unit tests ("how do I do this again?")
+
+So the basic idea of Moya is that we want some network abstraction layer that
+sufficiently encapsulates actually calling Alamofire directly. It should be simple
+enough that common things are easy, but comprehensive enough that complicated things
+are also easy.
+
+> If you use Alamofire to abstract away `URLSession`, why not use something
+to abstract away the nitty gritty of URLs, parameters, etc?
+
+Some awesome features of Moya:
+
+- Compile-time checking for correct API endpoint accesses.
+- Lets you define a clear usage of different endpoints with associated enum values.
+- Treats test stubs as first-class citizens so unit testing is super-easy.
+
+You can check out more about the project direction in the [vision document](https://github.com/Moya/Moya/blob/master/Vision.md).
+
+## Sample Projects
+
+We have provided two sample projects in the repository. To use it download the repo, run `carthage update` to download the required libraries and open [Moya.xcodeproj](https://github.com/Moya/Moya/tree/master/Moya.xcodeproj). You'll see two schemes: `Basic` and `Multi-Target` - select one and then build & run! Source files for these are in the `Examples` directory in project navigator. Have fun!
+
+## Project Status
+
+This project is actively under development, and is being used in [Artsy's
+new auction app](https://github.com/Artsy/eidolon). We consider it
+ready for production use.
+
+## Installation
+
+### Moya version vs Swift version.
+
+Below is a table that shows which version of Moya you should use for
+_Note: If you are using Swift 4.2 in your project, but you are using Xcode 10.2, Moya 13 should work correctly even though we use Swift 5.0._
+
+**Upgrading to a new major version of Moya? Check out our [migration guides](https://github.com/Moya/Moya/blob/master/docs/MigrationGuides).**
+
+### Swift Package Manager
+
+_Note: Instructions below are for using **SwiftPM** without the Xcode UI. It's the easiest to go to your Project Settings -> Swift Packages and add Moya from there._
+
+To integrate using Apple's Swift package manager, without Xcode integration, add the following as a dependency to your `Package.swift`:
+Note: If you are using **ReactiveMoya**, we are using [our own fork of ReactiveSwift](https://github.com/Moya/ReactiveSwift). This fork adds 2 commits to remove testing dependencies on releases (starting 6.1.0). This is to prevent Xcode Previews on Xcode 11/11.1 to build testing dependencies (FB7316430). If you don't want to use our fork, you can just add another dependency to your SPM package list: `git@github.com:ReactiveCocoa/ReactiveSwift.git` and it should fetch the original repository.
+
+Combine note: if you're using **CombineMoya**, make sure that you use Xcode 11.5.0
+or later. With earlier versions of Xcode you will have to manually add Combine as
+a weakly linked framework to your application target.
+
+### Accio
+
+[Accio](https://github.com/JamitLabs/Accio) is a dependency manager based on SwiftPM which can build frameworks for iOS/macOS/tvOS/watchOS. Therefore the integration steps of Moya are exactly the same as described above. Once your `Package.swift` file is configured, run `accio update` instead of `swift package update`.
+
+### CocoaPods
+
+For Moya, use the following entry in your Podfile:
+
+```rb
+pod 'Moya', '~> 15.0'
+
+# or
+
+pod 'Moya/RxSwift', '~> 15.0'
+
+# or
+
+pod 'Moya/ReactiveSwift', '~> 15.0'
+
+#or
+
+pod 'Moya/Combine', '~> 15.0'
+```
+
+Then run `pod install`.
+
+In any file you'd like to use Moya in, don't forget to
+import the framework with `import Moya`.
+
+### Carthage
+
+Carthage users can point to this repository and use whichever
+generated framework they'd like, `Moya`, `RxMoya`, `ReactiveMoya`, or
+`CombineMoya`.
+
+Make the following entry in your Cartfile:
+
+```
+github "Moya/Moya" ~> 15.0
+```
+
+Then run `carthage update --use-xcframeworks`.
+
+If this is your first time using Carthage in the project, you'll need to go through some additional steps as explained [over at Carthage](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application).
+
+> NOTE: At this time, Carthage does not provide a way to build only specific repository submodules. All submodules and their dependencies will be built with the above command. However, you don't need to copy frameworks you aren't using into your project. For instance, if you aren't using `ReactiveSwift`, feel free to delete that framework along with `ReactiveMoya` from the Carthage Build directory after `carthage update` completes. Or if you are using `ReactiveSwift` but not `RxSwift` or `Combine`, then `RxMoya`, `RxTest`, `RxCocoa`, `CombineMoya` etc. can safely be deleted.
+
+### Manually
+
+- Open up Terminal, `cd` into your top-level project directory, and run the following command *if* your project is not initialized as a git repository:
+
+```bash
+$ git init
+```
+
+- Add Alamofire & Moya as a git [submodule](http://git-scm.com/docs/git-submodule) by running the following commands:
+- Open the new `Alamofire` folder, and drag the `Alamofire.xcodeproj` into the Project Navigator of your application's Xcode project. Do the same with the `Moya.xcodeproj` in the `Moya` folder.
+
+> They should appear nested underneath your application's blue project icon. Whether it is above or below all the other Xcode groups does not matter.
+
+- Verify that the deployment targets of the `xcodeproj`s match that of your application target in the Project Navigator.
+- Next, select your application project in the Project Navigator (blue project icon) to navigate to the target configuration window and select the application target under the "Targets" heading in the sidebar.
+- In the tab bar at the top of that window, open the "General" panel.
+- Click on the `+` button under the "Embedded Binaries" section.
+- You will see two different `Alamofire.xcodeproj` folders each with two different versions of the `Alamofire.framework` nested inside a `Products` folder.
+
+> It does not matter which `Products` folder you choose from, but it does matter whether you choose the top or bottom `Alamofire.framework`.
+
+- Select the top `Alamofire.framework` for iOS and the bottom one for macOS.
+
+> You can verify which one you selected by inspecting the build log for your project. The build target for `Alamofire` will be listed as either `Alamofire iOS`, `Alamofire macOS`, `Alamofire tvOS` or `Alamofire watchOS`.
+
+- Click on the `+` button under "Embedded Binaries" again and add the correct build target for `Moya`.
+
+- And that's it!
+
+> The three frameworks are automagically added as a target dependency, linked framework and embedded framework in a copy files build phase which is all you need to build on the simulator and a device.
+
+## Usage
+
+After [some setup](https://github.com/Moya/Moya/blob/master/docs/Examples/Basic.md), using Moya is really simple. You can access an API like this:
+
+```swift
+provider = MoyaProvider<GitHub>()
+provider.request(.zen) { result in
+ switch result {
+ case let .success(moyaResponse):
+ let data = moyaResponse.data
+ let statusCode = moyaResponse.statusCode
+ // do something with the response data or statusCode
+ case let .failure(error):
+ // this means there was a network failure - either the request
+ // wasn't sent (connectivity), or no response was received (server
+ // timed out). If the server responds with a 4xx or 5xx error, that
+ // will be sent as a ".success"-ful response.
+ }
+}
+```
+
+That's a basic example. Many API requests need parameters. Moya encodes these
+into the enum you use to access the endpoint, like this:
+
+```swift
+provider = MoyaProvider<GitHub>()
+provider.request(.userProfile("ashfurrow")) { result in
+ // do something with the result
+}
+```
+
+No more typos in URLs. No more missing parameter values. No more messing with
+parameter encoding.
+
+For more examples, see the [documentation](https://github.com/Moya/Moya/blob/master/docs/Examples).
+
+## Reactive Extensions
+
+Even cooler are the reactive extensions. Moya provides reactive extensions for
+[`ReactiveSwift` extension](https://github.com/Moya/Moya/blob/master/docs/ReactiveSwift.md) provides both `reactive.request(:callbackQueue:)` and
+`reactive.requestWithProgress(:callbackQueue:)` methods that immediately return
+`SignalProducer`s that you can start, bind, map, or whatever you want to do.
+To handle errors, for instance, we could do the following:
+
+```swift
+provider = MoyaProvider<GitHub>()
+provider.reactive.request(.userProfile("ashfurrow")).start { event in
+ switch event {
+ case let .value(response):
+ image = UIImage(data: response.data)
+ case let .failed(error):
+ print(error)
+ default:
+ break
+ }
+}
+```
+
+### RxSwift
+
+[`RxSwift` extension](https://github.com/Moya/Moya/blob/master/docs/RxSwift.md) also provide both `rx.request(:callbackQueue:)` and
+`rx.requestWithProgress(:callbackQueue:)` methods, but return type is
+different for both. In case of a normal `rx.request(:callbackQueue)`, the
+return type is `Single<Response>` which emits either single element or an
+error. In case of a `rx.requestWithProgress(:callbackQueue:)`, the return
+type is `Observable<ProgressResponse>`, since we may get multiple events
+from progress and one last event which is a response.
+
+To handle errors, for instance, we could do the following:
+
+```swift
+provider = MoyaProvider<GitHub>()
+provider.rx.request(.userProfile("ashfurrow")).subscribe { event in
+ switch event {
+ case let .success(response):
+ image = UIImage(data: response.data)
+ case let .error(error):
+ print(error)
+ }
+}
+```
+
+In addition to the option of using signals instead of callback blocks, there are
+also a series of signal operators for RxSwift and ReactiveSwift that will attempt
+to map the data received from the network response into either an image, some JSON,
+or a string, with `mapImage()`, `mapJSON()`, and `mapString()`, respectively. If the mapping is unsuccessful, you'll get an error on the signal. You also get handy methods
+for filtering out certain status codes. This means that you can place your code for
+handling API errors like 400's in the same places as code for handling invalid
+responses.
+
+### Combine
+
+`Combine` extension provides `requestPublisher(:callbackQueue:)` and
+ guard case let .failure(error) = completion else { return }
+
+ print(error)
+ }, receiveValue: { response in
+ image = UIImage(data: response.data)
+ })
+```
+
+## Community Projects
+
+[Moya has a great community around it and some people have created some very helpful extensions](https://github.com/Moya/Moya/blob/master/docs/CommunityProjects.md).
+
+## Contributing
+
+Hey! Do you like Moya? Awesome! We could actually really use your help!
+
+Open source isn't just writing code. Moya could use your help with any of the
+following:
+
+- Finding (and reporting!) bugs.
+- New feature suggestions.
+- Answering questions on issues.
+- Documentation improvements.
+- Reviewing pull requests.
+- Helping to manage issue priorities.
+- Fixing bugs/new features.
+
+If any of that sounds cool to you, send a pull request! After your first
+contribution, we will add you as a member to the repo so you can merge pull
+requests and help steer the ship :ship: You can read more details about that [in our contributor guidelines](https://github.com/Moya/Moya/blob/master/Contributing.md).
+
+Moya's community has a tremendous positive energy, and the maintainers are committed to keeping things awesome. Like [in the CocoaPods community](https://github.com/CocoaPods/CocoaPods/wiki/Communication-&-Design-Rules), always assume positive intent; even if a comment sounds mean-spirited, give the person the benefit of the doubt.
+
+Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by [its terms](https://github.com/Moya/Moya/blob/master/Code%20of%20Conduct.md).
+
+### Adding new source files
+
+If you add or remove a source file from Moya, a corresponding change needs to be made to the `Moya.xcodeproj` project at the root of this repository. This project is used for Carthage. Don't worry, you'll get an automated warning when submitting a pull request if you forget.
+
+### Help us improve Moya documentation
+Whether you’re a core member or a user trying it out for the first time, you can make a valuable contribution to Moya by improving the documentation. Help us by:
+
+- sending us feedback about something you thought was confusing or simply missing
+- suggesting better wording or ways of explaining certain topics
+- sending us a pull request via GitHub
+- improving the [Chinese documentation](https://github.com/Moya/Moya/blob/master/Readme_CN.md)
+
+
+## License
+
+Moya is released under an MIT license. See [License.md](https://github.com/Moya/Moya/blob/master/License.md) for more information.