diff --git a/.github/workflows/swiftpm.yml b/.github/workflows/swiftpm.yml index 51d007e8..fc24ccc3 100644 --- a/.github/workflows/swiftpm.yml +++ b/.github/workflows/swiftpm.yml @@ -1,4 +1,4 @@ -name: Swift +name: SwiftPM regression tests on: push: @@ -7,7 +7,7 @@ on: branches: [ master ] jobs: - build: + run_tests: runs-on: macos-latest diff --git a/.jazzy.yaml b/.jazzy.yaml index e5472a90..f5a990a2 100644 --- a/.jazzy.yaml +++ b/.jazzy.yaml @@ -9,9 +9,9 @@ exclude: - "Source/SiestaUI/SiestaUI-ObjC.swift" # ditto - "Source/Siesta/Support/Ω_Deprecations.swift" # ditto -copyright: '© 2018 [Bust Out Solutions](http://bustoutsolutions.com) under [open source license](https://github.com/bustoutsolutions/siesta/blob/master/LICENSE).' +copyright: '© 2020 [Bust Out Solutions](http://bustoutsolutions.com) under [open source license](https://github.com/bustoutsolutions/siesta/blob/master/LICENSE).' -swift_version: 4.2.1 +swift_version: 5.2 theme: fullwidth diff --git a/.swift-version b/.swift-version deleted file mode 100644 index 819e07a2..00000000 --- a/.swift-version +++ /dev/null @@ -1 +0,0 @@ -5.0 diff --git a/Examples/GithubBrowser/GithubBrowser.xcodeproj/project.pbxproj b/Examples/GithubBrowser/GithubBrowser.xcodeproj/project.pbxproj index 24473daa..5bade494 100644 --- a/Examples/GithubBrowser/GithubBrowser.xcodeproj/project.pbxproj +++ b/Examples/GithubBrowser/GithubBrowser.xcodeproj/project.pbxproj @@ -354,7 +354,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; OTHER_SWIFT_FLAGS = "-D DEBUG"; @@ -405,7 +405,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; MTL_ENABLE_DEBUG_INFO = NO; OTHER_SWIFT_FLAGS = "-D DEBUG"; SDKROOT = iphoneos; diff --git a/Examples/GithubBrowser/Podfile b/Examples/GithubBrowser/Podfile index de92fe35..e82ee473 100644 --- a/Examples/GithubBrowser/Podfile +++ b/Examples/GithubBrowser/Podfile @@ -1,4 +1,4 @@ -platform :ios, '9.0' +platform :ios, '10.0' target 'GithubBrowser' do use_frameworks! diff --git a/Examples/GithubBrowser/Podfile.lock b/Examples/GithubBrowser/Podfile.lock index 255e6fbd..3881b4e5 100644 --- a/Examples/GithubBrowser/Podfile.lock +++ b/Examples/GithubBrowser/Podfile.lock @@ -1,6 +1,6 @@ PODS: - - Siesta/Core (1.4.3) - - Siesta/UI (1.4.3): + - Siesta/Core (1.5.0) + - Siesta/UI (1.5.0): - Siesta/Core DEPENDENCIES: @@ -11,8 +11,8 @@ EXTERNAL SOURCES: :path: "../.." SPEC CHECKSUMS: - Siesta: 83795fdf6a43232d1d2909e1a3dfb92ab5916d26 + Siesta: 407b99ae05344d2de33d98e9e239551086daee6a -PODFILE CHECKSUM: ae415ad9ad375272eab63ab45853da2148a7aa21 +PODFILE CHECKSUM: 974001388daa9ecbfa915ea0bc4093a33242099c -COCOAPODS: 1.7.0.beta.3 +COCOAPODS: 1.9.1 diff --git a/Package.swift b/Package.swift index f36ee80b..87cfeadc 100644 --- a/Package.swift +++ b/Package.swift @@ -4,13 +4,14 @@ import PackageDescription let package = Package( name: "Siesta", platforms: [ - .iOS(.v8), + .iOS(.v10), .macOS(.v10_12), .tvOS(.v9), ], products: [ .library(name: "Siesta", targets: ["Siesta"]), .library(name: "SiestaUI", targets: ["SiestaUI"]), + .library(name: "Siesta_Alamofire", targets: ["Siesta_Alamofire"]), ], dependencies: [ // Siesta has no required third-party dependencies for use in downstream projects. diff --git a/README.md b/README.md index b4ed4ba3..1ab925f2 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,9 @@ Drastically simplifies app code by providing a client-side cache of observable models for RESTful resources. -* **OS:** iOS 8+, macOS 10.11+ +* **OS:** iOS 10+, macOS 10.11+, tvOS 9.0+ * **Languages:** Written in Swift, supports apps in both Swift and Objective-C -* **Tool requirements:** Xcode 10, Swift 4 (See `swift-2.x` and `swift-3` branches for legacy support) +* **Tool requirements:** Xcode 11.3+, Swift 5.1+ (See [`swift-*` branches](https://github.com/bustoutsolutions/siesta/branches/all?query=swift-) for legacy support) * **License:** MIT ## Table of Contents @@ -89,7 +89,7 @@ Siesta handles all the transitions and corner cases to deliver these answers wra - It **doesn’t reinvent networking.** Siesta delegates network operations to your library of choice (`URLSession` by default, or [Alamofire](https://github.com/Alamofire/Alamofire), or inject your own [custom adapter](https://bustoutsolutions.github.io/siesta/api/Protocols/NetworkingProvider.html)). - It **doesn’t hide HTTP**. On the contrary, Siesta strives to expose the full richness of HTTP while providing conveniences to simplify common usage patterns. You can devise an abstraction layer to suit your own particular needs, or work directly with Siesta’s nice APIs for requests and response entities. -- It **doesn’t do automatic response ↔ model mapping.** This means that Siesta doesn’t constrain your response models, or force you to have any at all. Add a response transformer to output models of whatever flavor you prefer, or work directly with parsed JSON. +- It **doesn’t do automatic response ↔ model mapping.** This means that Siesta doesn’t constrain your response models, or force you to have any at all. Add a response transformer to output models of whatever flavor your app prefers, or work directly with parsed JSON. ## Origin @@ -120,7 +120,29 @@ _…in that order of priority._ ## Installation -Siesta requires Swift 4 and Xcode 10. (Use the `swift-2.x` and `swift-3` branches if you are still on an older version.) +Siesta requires Swift 5 and Xcode 11. (Use the [`swift-*` branches](https://github.com/bustoutsolutions/siesta/branches/all?query=swift-) branches if you are still on an older version.) + +### Swift Package Manager + +In Xcode: + +* File → Swift Packages → Add Package Dependency… +* Enter `https://github.com/bustoutsolutions/siesta` in the URL field and click Next. +* The defaults for the version settings are good for most projects. Click Next. +* Check the checkbox next to “Siesta.” + - Also check “SiestaUI” if you want to use any of the [UI helpers](https://github.com/bustoutsolutions/siesta/tree/master/Source/SiestaUI). + - Also check “Siesta_Alamofire” if you want to use the Alamofire extension for Siesta. +* Click “Finish.” +* SwiftPM does not yet support resources supplied by dependencies. This means that if: + - you included `SiestaUI` above + - and you plan to use `ResourceStatusOverlay` + - and you are using its default initializer instead of providing your own custom UI layout, + + …then you’ll need to copy [`ResourceStatusOverlay.xib`](https://github.com/bustoutsolutions/siesta/raw/master/Source/SiestaUI/ResourceStatusOverlay.xib) into your own project. + + SwiftPM has support for this coming, but it hasn’t arrived yet as of Swift 5.2. + +Please note that Xcode will show _all_ of Siesta’s optional and test-only dependencies, including Quick, Nimble, and Alamofire. Don’t worry: these won’t actually be bundled into your app (except Alamofire, if you use it). ### CocoaPods @@ -372,7 +394,7 @@ With all that in mind, here is a capabilities comparison¹: | Hides HTTP | | | | ✓ | | | | UI helpers | ✓ | | | | ✓ | | | Primary language | Swift | Swift | Obj-C | Swift | Obj-C | Obj-C | -| Nontrivial lines of code² | 2500 | 3020 | 13291 | 965 | 4025 | ? | +| Nontrivial lines of code² | 2609 | 3980 | 13220 | 1178 | 3936 | ? | | Built on top of | any (injectable)| URLSession | AFNetworking | Alamofire | NSURLSession / NSURLConnection| Apple guts 1. Disclaimer: table compiled by Siesta’s non-omniscient author. Corrections / additions? Please [submit a PR](https://github.com/bustoutsolutions/siesta/edit/master/README%2Emd#L280). diff --git a/Siesta.podspec b/Siesta.podspec index 1832e3dd..0a82c9db 100644 --- a/Siesta.podspec +++ b/Siesta.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "Siesta" - s.version = "1.4.3" + s.version = "1.5.0" s.summary = "Swift REST client library" s.description = <<-DESC @@ -15,18 +15,18 @@ Pod::Spec.new do |s| …then provides notifications whenever the answers to these questions change. - Siesta handles all the transitions and corner cases to deliver these answers wrapped up with a pretty bow on top, letting you focus on your UI. + Siesta handles all the transitions and corner cases to deliver these answers wrapped up with a pretty bow on top, letting you focus on your logic and UI. ## Stats - * **OS:** iOS 8+, OS X / macOS 10.11+, tvOS 9.0+ + * **OS:** iOS 10+, macOS 10.11+, tvOS 9.0+ * **Languages:** Written in Swift, supports apps in both Swift and Objective-C - * **Tool requirements:** Xcode 8, Swift 3.0 + * **Tool requirements:** Xcode 11.3+, Swift 5.1+ * **License:** MIT ## Features - - Decouples view and model lifecycle from network request lifecycle + - Decouples view, model, and controller lifecycle from network request lifecycle - Decouples request initiation from request configuration - Eliminates error-prone state tracking logic - Eliminates redundant network requests @@ -41,13 +41,13 @@ Pod::Spec.new do |s| - …also works great from Objective-C thanks to a compatibility layer. - Lightweight. Won’t achieve sentience and attempt to destroy you. - [Robust regression tests](https://bustoutsolutions.github.io/siesta/specs/) - - [Documentation](https://bustoutsolutions.github.io/siesta/guide/) + - [Documentation](https://bustoutsolutions.github.io/siesta/guide/) and [more documentation](https://bustoutsolutions.github.io/siesta/api/) ## What it doesn’t do - It **doesn’t reinvent networking.** Siesta delegates network operations to your library of choice (`URLSession` by default, or [Alamofire](https://github.com/Alamofire/Alamofire), or inject your own [custom adapter](http://bustoutsolutions.github.io/siesta/api/Protocols/NetworkingProvider.html)). - It **doesn’t hide HTTP**. On the contrary, Siesta strives to expose the full richness of HTTP while providing conveniences to simplify common usage patterns. You can devise an abstraction layer to suit your own particular needs, or work directly with Siesta’s nice APIs for requests and response entities. - - It **doesn’t do response ↔ model mapping.** This means that Siesta doesn’t constrain your response models, or force you to have any at all. Add a response transformer to work with your model library of choice, or work directly with parsed JSON. + - It **doesn’t do automatic response ↔ model mapping.** This means that Siesta doesn’t constrain your response models, or force you to have any at all. Add a response transformer to output models of whatever flavor your app prefers, or work directly with parsed JSON. ## Documentation @@ -66,11 +66,13 @@ Pod::Spec.new do |s| s.documentation_url = "https://bustoutsolutions.github.io/siesta/" - s.ios.deployment_target = "8.0" - s.osx.deployment_target = "10.11" - s.tvos.deployment_target = "9.0" + s.swift_version = "5.0" - s.source = { :git => "https://github.com/bustoutsolutions/siesta.git", :tag => "1.4.3" } + s.ios.deployment_target = "10.0" + s.osx.deployment_target = "10.12" + s.tvos.deployment_target = "10.0" + + s.source = { :git => "https://github.com/bustoutsolutions/siesta.git", :tag => "1.5.0" } s.subspec "Core" do |s| s.source_files = "Source/Siesta/**/*" @@ -87,7 +89,7 @@ Pod::Spec.new do |s| s.subspec "Alamofire" do |s| s.source_files = "Extensions/Alamofire/**/*.{swift,m,h}" s.dependency "Siesta/Core" - s.dependency "Alamofire", "> 4.1" + s.dependency "Alamofire", "> 5.0" end s.default_subspecs = 'Core' diff --git a/Source/Siesta/Pipeline/ResponseTransformer.swift b/Source/Siesta/Pipeline/ResponseTransformer.swift index a247f7ed..9c8b76b1 100644 --- a/Source/Siesta/Pipeline/ResponseTransformer.swift +++ b/Source/Siesta/Pipeline/ResponseTransformer.swift @@ -8,7 +8,7 @@ import Foundation -#if os(OSX) +#if os(macOS) import AppKit /// A cross-platform alias for the output type of Siesta’s image content transformer. diff --git a/Source/Siesta/Support/WeakCache.swift b/Source/Siesta/Support/WeakCache.swift index d263e533..4c5ad381 100644 --- a/Source/Siesta/Support/WeakCache.swift +++ b/Source/Siesta/Support/WeakCache.swift @@ -7,7 +7,7 @@ // import Foundation -#if os(OSX) || os(watchOS) +#if os(macOS) || os(watchOS) internal let memoryWarningNotification = NSNotification.Name("Siesta.memoryWarningNotification") #elseif os(iOS) || os(tvOS) import UIKit diff --git a/Source/SiestaUI/RemoteImageView.swift b/Source/SiestaUI/RemoteImageView.swift index bdab4e8a..dab87865 100644 --- a/Source/SiestaUI/RemoteImageView.swift +++ b/Source/SiestaUI/RemoteImageView.swift @@ -6,7 +6,7 @@ // Copyright © 2016 Bust Out Solutions. All rights reserved. // -#if os(iOS) +#if os(iOS) || os(tvOS) #if !COCOAPODS import Siesta @@ -88,4 +88,4 @@ open class RemoteImageView: UIImageView } } -#endif // OS(iOS) +#endif // OS diff --git a/Source/SiestaUI/ResourceStatusOverlay.swift b/Source/SiestaUI/ResourceStatusOverlay.swift index 6868f92e..61e81a1d 100644 --- a/Source/SiestaUI/ResourceStatusOverlay.swift +++ b/Source/SiestaUI/ResourceStatusOverlay.swift @@ -6,7 +6,7 @@ // Copyright © 2016 Bust Out Solutions. All rights reserved. // -#if os(iOS) +#if os(iOS) || os(tvOS) #if !COCOAPODS import Siesta @@ -110,7 +110,7 @@ open class ResourceStatusOverlay: UIView, ResourceObserver // For explanations of the os() function: // https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html#//apple_ref/doc/uid/TP40014216-CH8-XID_20 - #if os(iOS) + #if os(iOS) || os(tvOS) layer.zPosition = 10000 #endif parentVC?.view.addSubview(self) diff --git a/Source/SiestaUI/SiestaUI-ObjC.swift b/Source/SiestaUI/SiestaUI-ObjC.swift index 15cccdc5..3304903e 100644 --- a/Source/SiestaUI/SiestaUI-ObjC.swift +++ b/Source/SiestaUI/SiestaUI-ObjC.swift @@ -13,7 +13,7 @@ import Foundation import Siesta #endif -#if !os(OSX) +#if !os(macOS) extension ResourceEvent { diff --git a/Source/SiestaUI/Support/Collection+Siesta.swift b/Source/SiestaUI/Support/Collection+Siesta.swift deleted file mode 100644 index 36bab362..00000000 --- a/Source/SiestaUI/Support/Collection+Siesta.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// Collection+Siesta.swift -// Siesta -// -// Created by Paul on 2015/7/19. -// Copyright © 2016 Bust Out Solutions. All rights reserved. -// - -import Foundation - -extension Collection - { - // Just for readability - func any(match predicate: (Iterator.Element) -> Bool) -> Bool - { return contains(where: predicate) } - - func all(match predicate: (Iterator.Element) -> Bool) -> Bool - { return !contains(where: { !predicate($0) }) } - } diff --git a/Source/SiestaUI/Support/Collection+Siesta.swift b/Source/SiestaUI/Support/Collection+Siesta.swift new file mode 120000 index 00000000..607c4beb --- /dev/null +++ b/Source/SiestaUI/Support/Collection+Siesta.swift @@ -0,0 +1 @@ +../../Siesta/Support/Collection+Siesta.swift \ No newline at end of file diff --git "a/Source/SiestaUI/\316\251_UI_Deprecations.swift" "b/Source/SiestaUI/\316\251_UI_Deprecations.swift" index 456f915c..74fbf492 100644 --- "a/Source/SiestaUI/\316\251_UI_Deprecations.swift" +++ "b/Source/SiestaUI/\316\251_UI_Deprecations.swift" @@ -9,7 +9,7 @@ #if !COCOAPODS import Siesta #endif -#if os(iOS) +#if os(iOS) || os(tvOS) import UIKit #endif import Foundation diff --git a/Tests/Functional/NetworkStub.swift b/Tests/Functional/NetworkStub.swift index f1f8e997..a1fe370e 100644 --- a/Tests/Functional/NetworkStub.swift +++ b/Tests/Functional/NetworkStub.swift @@ -308,7 +308,7 @@ private struct Latch func await(target: Int = 0, whileLocked action: () -> Void = {}) { - guard lock.lock(whenCondition: target, before: Date(timeIntervalSinceNow: 1)) else + guard lock.lock(whenCondition: target, before: Date(timeIntervalSinceNow: 10)) else { fatalError("timed out waiting for \(name)") } action() lock.unlock() diff --git a/Tests/Functional/RemoteImageViewSpec.swift b/Tests/Functional/RemoteImageViewSpec.swift index 909e638f..3ad85085 100644 --- a/Tests/Functional/RemoteImageViewSpec.swift +++ b/Tests/Functional/RemoteImageViewSpec.swift @@ -6,7 +6,7 @@ // Copyright © 2018 Bust Out Solutions. All rights reserved. // -#if os(iOS) +#if os(iOS) || os(tvOS) import Foundation diff --git a/Tests/Functional/ResourceStateSpec.swift b/Tests/Functional/ResourceStateSpec.swift index ffc1ba25..083ec017 100644 --- a/Tests/Functional/ResourceStateSpec.swift +++ b/Tests/Functional/ResourceStateSpec.swift @@ -544,10 +544,10 @@ class ResourceStateSpec: ResourceSpecBase it("cancels load after the delay") { - let expectation = QuickSpec.current.expectation(description: "cancelLoadIfUnobserved(afterDelay:") + let expectation = QuickSpec.current.expectation(description: "cancelLoadIfUnobserved(afterDelay:)") resource().cancelLoadIfUnobserved(afterDelay: 0.2) { expectation.fulfill() } - QuickSpec.current.waitForExpectations(timeout: 0.3) + QuickSpec.current.waitForExpectations(timeout: 1.0) _ = reqStub().go() awaitFailure(req(), initialState: .completed) @@ -555,7 +555,7 @@ class ResourceStateSpec: ResourceSpecBase it("does not cancel load before the delay") { - let expectation = QuickSpec.current.expectation(description: "cancelLoadIfUnobserved(afterDelay:") + let expectation = QuickSpec.current.expectation(description: "cancelLoadIfUnobserved(afterDelay:)") expectation.isInverted = true resource().cancelLoadIfUnobserved(afterDelay: 0.3) { expectation.fulfill() } diff --git a/Tests/Functional/SiestaSpec.swift b/Tests/Functional/SiestaSpec.swift index b40873c1..5406a071 100644 --- a/Tests/Functional/SiestaSpec.swift +++ b/Tests/Functional/SiestaSpec.swift @@ -31,8 +31,12 @@ class SiestaSpec: QuickSpec SiestaLog.messageHandler = { _, message in + + let messageWithTimestamp = String(format: "%1.9f %@", ProcessInfo.processInfo.systemUptime, message) + if Self.envFlag("ShowTestOutputImmediately") + { print(messageWithTimestamp) } DispatchQueue.main.async - { currentLogMessages.append(message) } + { currentLogMessages.append(messageWithTimestamp) } } }