From 67efdfd1877b4260e52d131397073a9d0b2b6d5c Mon Sep 17 00:00:00 2001 From: dougzilla32 Date: Sun, 7 Oct 2018 15:32:04 +0900 Subject: [PATCH 1/2] 'Cancel' for PromiseKit -- provides the ability to cancel promises and promise chains --- .travis.yml | 29 +++++++---- Cartfile | 3 +- Cartfile.resolved | 2 +- PMKUIKit.xcodeproj/project.pbxproj | 26 ++++++---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++ .../xcshareddata/xcschemes/PMKUIKit.xcscheme | 4 +- Sources/UIImagePickerController+Promise.swift | 24 ++++++++++ Sources/UIView+Promise.swift | 48 +++++++++++++++++++ Sources/UIViewPropertyAnimator+Promise.swift | 22 ++++++++- Tests/TestUIViewPropertyAnimator.swift | 46 ++++++++++++++++++ 10 files changed, 187 insertions(+), 25 deletions(-) create mode 100644 PMKUIKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Tests/TestUIViewPropertyAnimator.swift diff --git a/.travis.yml b/.travis.yml index 8413475..6f6a06d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,26 +2,35 @@ os: osx language: objective-c matrix: include: - - {osx_image: xcode8.3, env: 'PLAT=iOS SWFT=3.1 DST="OS=8.4,name=iPhone 4S"'} - - {osx_image: xcode8.3, env: 'PLAT=iOS SWFT=3.1 DST="OS=9.3,name=iPhone 6"'} - {osx_image: xcode8.3, env: 'PLAT=iOS SWFT=3.1 DST="OS=10.3.1,name=iPhone SE"'} - - {osx_image: xcode8.3, env: 'PLAT=tvOS SWFT=3.1 DST="OS=9.2,name=Apple TV 1080p"'} - {osx_image: xcode8.3, env: 'PLAT=tvOS SWFT=3.1 DST="OS=10.2,name=Apple TV 1080p"'} - {osx_image: xcode9.2, env: 'PLAT=iOS SWFT=3.2 DST="OS=11.2,name=iPhone SE"'} - {osx_image: xcode9.2, env: 'PLAT=tvOS SWFT=3.2 DST="OS=11.2,name=Apple TV"'} - - - {osx_image: xcode9.2, env: 'PLAT=iOS SWFT=4.0 DST="OS=8.4,name=iPhone 4s"'} - - {osx_image: xcode9.2, env: 'PLAT=iOS SWFT=4.0 DST="OS=9.3,name=iPhone SE"'} - - {osx_image: xcode9.2, env: 'PLAT=iOS SWFT=4.0 DST="OS=10.3.1,name=iPhone SE"'} + + - {osx_image: xcode9.4, env: 'PLAT=iOS SWFT=3.3 DST="OS=11.4,name=iPhone 5s"'} + - {osx_image: xcode9.4, env: 'PLAT=tvOS SWFT=3.3 DST="OS=11.4,name=Apple TV"'} + + - {osx_image: xcode10, env: 'PLAT=iOS SWFT=3.4 DST="OS=12.0,name=iPhone SE"'} + - {osx_image: xcode10, env: 'PLAT=tvOS SWFT=3.4 DST="OS=12.0,name=Apple TV"'} + - {osx_image: xcode9.2, env: 'PLAT=iOS SWFT=4.0 DST="OS=11.2,name=iPhone SE"'} - - {osx_image: xcode9.2, env: 'PLAT=tvOS SWFT=4.0 DST="OS=9.2,name=Apple TV 1080p"'} - - {osx_image: xcode9.2, env: 'PLAT=tvOS SWFT=4.0 DST="OS=10.2,name=Apple TV 1080p"'} - {osx_image: xcode9.2, env: 'PLAT=tvOS SWFT=4.0 DST="OS=11.2,name=Apple TV"'} + + - {osx_image: xcode9.4, env: 'PLAT=iOS SWFT=4.1 DST="OS=8.4,name=iPhone 4s"'} + - {osx_image: xcode9.4, env: 'PLAT=iOS SWFT=4.1 DST="OS=9.3,name=iPhone 5s"'} + - {osx_image: xcode9.4, env: 'PLAT=iOS SWFT=4.1 DST="OS=10.3.1,name=iPhone SE"'} + - {osx_image: xcode9.4, env: 'PLAT=iOS SWFT=4.1 DST="OS=11.4,name=iPhone 5s"'} + - {osx_image: xcode9.3, env: 'PLAT=tvOS SWFT=4.1 DST="OS=9.2,name=Apple TV 1080p"'} + - {osx_image: xcode9.3, env: 'PLAT=tvOS SWFT=4.1 DST="OS=10.2,name=Apple TV 1080p"'} + - {osx_image: xcode9.4, env: 'PLAT=tvOS SWFT=4.1 DST="OS=11.4,name=Apple TV"'} + + - {osx_image: xcode10, env: 'PLAT=iOS SWFT=4.2 DST="OS=12.0,name=iPhone SE"'} + - {osx_image: xcode10, env: 'PLAT=tvOS SWFT=4.2 DST="OS=12.0,name=Apple TV"'} cache: directories: - Carthage install: - carthage bootstrap --cache-builds --no-use-binaries --platform $PLAT script: - - xcodebuild -scheme PMKUIKit -quiet -destination "$DST" build SWIFT_VERSION="$SWFT" + - xcodebuild -scheme PMKUIKit -target PMKUIKit -quiet -destination "$DST" build SWIFT_VERSION="$SWFT" SWIFT_TREAT_WARNINGS_AS_ERRORS=YES diff --git a/Cartfile b/Cartfile index 2bfea98..c517d21 100644 --- a/Cartfile +++ b/Cartfile @@ -1 +1,2 @@ -github "mxcl/PromiseKit" ~> 6.0 +#github "mxcl/PromiseKit" ~> 6.0 +github "dougzilla32/PromiseKit" "CoreCancel" diff --git a/Cartfile.resolved b/Cartfile.resolved index 7e43117..80a4000 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1 @@ -github "mxcl/PromiseKit" "6.1.0" +github "dougzilla32/PromiseKit" "087b3cf470890ff9ea841212e2f3e285fecf3988" diff --git a/PMKUIKit.xcodeproj/project.pbxproj b/PMKUIKit.xcodeproj/project.pbxproj index c5b16d6..8c228e8 100644 --- a/PMKUIKit.xcodeproj/project.pbxproj +++ b/PMKUIKit.xcodeproj/project.pbxproj @@ -25,6 +25,7 @@ 63C9C4581D5D339B00101ECE /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 630B2DF51D5D0AD400DC10E9 /* Default-568h@2x.png */; }; 63C9C45E1D5D341600101ECE /* PMKUIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63C7FFA71D5BEE09003BAE60 /* PMKUIKit.framework */; }; 63C9C45F1D5D341600101ECE /* PMKUIKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 63C7FFA71D5BEE09003BAE60 /* PMKUIKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 911E6FC620F571F7006F49B9 /* TestUIViewPropertyAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 911E6FC520F571F7006F49B9 /* TestUIViewPropertyAnimator.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -95,6 +96,7 @@ 63C9C4451D5D334700101ECE /* PMKTestsHost.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PMKTestsHost.app; sourceTree = BUILT_PRODUCTS_DIR; }; 63CCF8121D5C0C4E00503216 /* Cartfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartfile; sourceTree = ""; }; 63CCF8171D5C11B500503216 /* Carthage.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Carthage.xcconfig; sourceTree = ""; }; + 911E6FC520F571F7006F49B9 /* TestUIViewPropertyAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestUIViewPropertyAnimator.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -186,6 +188,7 @@ 637E2C8E1D5C2E720043E370 /* TestUIImagePickerController.swift */, 637E2C8F1D5C2E720043E370 /* TestUIViewController.m */, 6332142A1D83CD17009F67CE /* TestUIView.swift */, + 911E6FC520F571F7006F49B9 /* TestUIViewPropertyAnimator.swift */, 637E2C9A1D5C2F600043E370 /* infrastructure.swift */, ); path = Tests; @@ -287,7 +290,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0800; - LastUpgradeCheck = 0900; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Max Howell"; TargetAttributes = { 630B2DFF1D5D0AF500DC10E9 = { @@ -402,6 +405,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 911E6FC620F571F7006F49B9 /* TestUIViewPropertyAnimator.swift in Sources */, 637E2C951D5C2E720043E370 /* TestUIImagePickerController.swift in Sources */, 637E2C961D5C2E720043E370 /* TestUIViewController.m in Sources */, 637E2C9B1D5C2F600043E370 /* infrastructure.swift in Sources */, @@ -455,7 +459,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SUPPRESS_WARNINGS = YES; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; TEST_TARGET_NAME = PMKTestsHost; }; name = Debug; @@ -471,7 +475,7 @@ PRODUCT_BUNDLE_IDENTIFIER = org.promisekit.tests.ui.UIKit; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SUPPRESS_WARNINGS = YES; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; TEST_TARGET_NAME = PMKTestsHost; }; name = Release; @@ -491,6 +495,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -498,6 +503,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -534,6 +540,7 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2,3,4"; TVOS_DEPLOYMENT_TARGET = 9.0; WATCHOS_DEPLOYMENT_TARGET = 2.0; @@ -555,6 +562,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -562,6 +570,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -590,6 +599,7 @@ PRODUCT_BUNDLE_IDENTIFIER = org.promisekit.UIKit; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2,3,4"; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; @@ -611,7 +621,6 @@ PRODUCT_MODULE_NAME = "${TARGET_NAME}"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -628,7 +637,6 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_MODULE_NAME = "${TARGET_NAME}"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; }; name = Release; }; @@ -643,7 +651,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SUPPRESS_WARNINGS = YES; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PMKTestsHost.app/PMKTestsHost"; }; name = Debug; @@ -658,7 +666,7 @@ PRODUCT_BUNDLE_IDENTIFIER = org.promisekit.tests.UIKit; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SUPPRESS_WARNINGS = YES; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PMKTestsHost.app/PMKTestsHost"; }; name = Release; @@ -675,7 +683,7 @@ PRODUCT_BUNDLE_IDENTIFIER = org.promisekit.tests.host.UIKit; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -691,7 +699,7 @@ PRODUCT_BUNDLE_IDENTIFIER = org.promisekit.tests.host.UIKit; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; }; name = Release; }; diff --git a/PMKUIKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/PMKUIKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/PMKUIKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/PMKUIKit.xcodeproj/xcshareddata/xcschemes/PMKUIKit.xcscheme b/PMKUIKit.xcodeproj/xcshareddata/xcschemes/PMKUIKit.xcscheme index bca44ba..db90f8b 100644 --- a/PMKUIKit.xcodeproj/xcshareddata/xcschemes/PMKUIKit.xcscheme +++ b/PMKUIKit.xcodeproj/xcshareddata/xcschemes/PMKUIKit.xcscheme @@ -1,6 +1,6 @@ =4.2) + /// Presents the UIImagePickerController, resolving with the user action. + public func promise(_ vc: UIImagePickerController, animate: PMKAnimationOptions = [.appear, .disappear], completion: (() -> Void)? = nil) -> Promise<[UIImagePickerController.InfoKey: Any]> { + let animated = animate.contains(.appear) + let proxy = UIImagePickerControllerProxy() + vc.delegate = proxy + present(vc, animated: animated, completion: completion) + return proxy.promise.ensure { + vc.presentingViewController?.dismiss(animated: animated, completion: nil) + } + } +#else /// Presents the UIImagePickerController, resolving with the user action. public func promise(_ vc: UIImagePickerController, animate: PMKAnimationOptions = [.appear, .disappear], completion: (() -> Void)? = nil) -> Promise<[String: Any]> { let animated = animate.contains(.appear) @@ -16,10 +28,15 @@ extension UIViewController { vc.presentingViewController?.dismiss(animated: animated, completion: nil) } } +#endif } @objc private class UIImagePickerControllerProxy: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate { +#if swift(>=4.2) + let (promise, seal) = Promise<[UIImagePickerController.InfoKey: Any]>.pending() +#else let (promise, seal) = Promise<[String: Any]>.pending() +#endif var retainCycle: AnyObject? required override init() { @@ -27,10 +44,17 @@ extension UIViewController { retainCycle = self } +#if swift(>=4.2) + func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) { + seal.fulfill(info) + retainCycle = nil + } +#else func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String: Any]) { seal.fulfill(info) retainCycle = nil } +#endif func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { seal.reject(UIImagePickerController.PMKError.cancelled) diff --git a/Sources/UIView+Promise.swift b/Sources/UIView+Promise.swift index 60d87af..1bbb8c6 100644 --- a/Sources/UIView+Promise.swift +++ b/Sources/UIView+Promise.swift @@ -19,6 +19,53 @@ import PromiseKit import PromiseKit */ public extension UIView { +#if swift(>=4.2) +/** + Animate changes to one or more views using the specified duration, delay, + options, and completion handler. + + - Parameter duration: The total duration of the animations, measured in + seconds. If you specify a negative value or 0, the changes are made + without animating them. + + - Parameter delay: The amount of time (measured in seconds) to wait before + beginning the animations. Specify a value of 0 to begin the animations + immediately. + + - Parameter options: A mask of options indicating how you want to perform the + animations. For a list of valid constants, see UIViewAnimationOptions. + + - Parameter animations: A block object containing the changes to commit to the + views. + + - Returns: A promise that fulfills with a boolean NSNumber indicating + whether or not the animations actually finished. + */ + @discardableResult + static func animate(_: PMKNamespacer, duration: TimeInterval, delay: TimeInterval = 0, options: UIView.AnimationOptions = [], animations: @escaping () -> Void) -> Guarantee { + return Guarantee { animate(withDuration: duration, delay: delay, options: options, animations: animations, completion: $0) } + } + + @discardableResult + static func animate(_: PMKNamespacer, duration: TimeInterval, delay: TimeInterval, usingSpringWithDamping damping: CGFloat, initialSpringVelocity: CGFloat, options: UIView.AnimationOptions = [], animations: @escaping () -> Void) -> Guarantee { + return Guarantee { animate(withDuration: duration, delay: delay, usingSpringWithDamping: damping, initialSpringVelocity: initialSpringVelocity, options: options, animations: animations, completion: $0) } + } + + @discardableResult + static func transition(_: PMKNamespacer, with view: UIView, duration: TimeInterval, options: UIView.AnimationOptions = [], animations: (() -> Void)?) -> Guarantee { + return Guarantee { transition(with: view, duration: duration, options: options, animations: animations, completion: $0) } + } + + @discardableResult + static func transition(_: PMKNamespacer, from: UIView, to: UIView, duration: TimeInterval, options: UIView.AnimationOptions = []) -> Guarantee { + return Guarantee { transition(from: from, to: to, duration: duration, options: options, completion: $0) } + } + + @discardableResult + static func perform(_: PMKNamespacer, animation: UIView.SystemAnimation, on views: [UIView], options: UIView.AnimationOptions = [], animations: (() -> Void)?) -> Guarantee { + return Guarantee { perform(animation, on: views, options: options, animations: animations, completion: $0) } + } +#else /** Animate changes to one or more views using the specified duration, delay, options, and completion handler. @@ -64,4 +111,5 @@ public extension UIView { static func perform(_: PMKNamespacer, animation: UISystemAnimation, on views: [UIView], options: UIViewAnimationOptions = [], animations: (() -> Void)?) -> Guarantee { return Guarantee { perform(animation, on: views, options: options, animations: animations, completion: $0) } } +#endif } diff --git a/Sources/UIViewPropertyAnimator+Promise.swift b/Sources/UIViewPropertyAnimator+Promise.swift index 34ee140..f95d230 100644 --- a/Sources/UIViewPropertyAnimator+Promise.swift +++ b/Sources/UIViewPropertyAnimator+Promise.swift @@ -6,9 +6,29 @@ import UIKit @available(iOS 10, tvOS 10, *) public extension UIViewPropertyAnimator { func startAnimation(_: PMKNamespacer) -> Guarantee { - return Guarantee { + return Guarantee(cancellableTask: self) { addCompletion($0) startAnimation() } } } + +@available(iOS 10, tvOS 10, *) +extension UIViewPropertyAnimator: CancellableTask { + public func cancel() { + stopAnimation(true) + } + + public var isCancelled: Bool { + return (state == .inactive) && (fractionComplete < 1.0) + } +} + +//////////////////////////////////////////////////////////// Cancellable wrapper + +@available(iOS 10, tvOS 10, *) +extension UIViewPropertyAnimator { + public func cancellableStartAnimation(_: PMKNamespacer) -> CancellablePromise { + return cancellable(startAnimation(.promise)) + } +} diff --git a/Tests/TestUIViewPropertyAnimator.swift b/Tests/TestUIViewPropertyAnimator.swift new file mode 100644 index 0000000..98f3789 --- /dev/null +++ b/Tests/TestUIViewPropertyAnimator.swift @@ -0,0 +1,46 @@ +import PromiseKit +import PMKUIKit +import XCTest +import UIKit + +@available(iOS 10, tvOS 10, *) +class UIViewPropertyAnimatorTests: XCTestCase { + func test() { + let ex1 = expectation(description: "") + let ex2 = expectation(description: "") + + let animator = UIViewPropertyAnimator(duration: 0.1, curve: .easeIn, animations: { [weak self] in + ex1.fulfill() + }) + animator.startAnimation(.promise).done { _ in + ex2.fulfill() + } + + waitForExpectations(timeout: 1) + } +} + +//////////////////////////////////////////////////////////// Cancellation + +@available(iOS 10, tvOS 10, *) +extension UIViewPropertyAnimatorTests { + func testCancel() { + let ex1 = expectation(description: "") + let ex2 = expectation(description: "") + + let animator = UIViewPropertyAnimator(duration: 0.1, curve: .easeIn, animations: { [weak self] in + ex1.fulfill() + }) + let p = animator.cancellableStartAnimation(.promise).done { _ in + XCTFail() + }.catch(policy: .allErrors) { error in + error.isCancelled ? ex2.fulfill() : XCTFail("Error: \(error)") + } + p.cancel() + + XCTAssert(animator.isCancelled) + XCTAssert(p.isCancelled) + + waitForExpectations(timeout: 1) + } +} From 6f00c3eeb863f441f350cc9c00af81f1e7227de5 Mon Sep 17 00:00:00 2001 From: dougzilla32 Date: Tue, 16 Oct 2018 11:53:03 +0900 Subject: [PATCH 2/2] 'Cancel' for PromiseKit -- remove cancellable wrappers (they are unnecessary) --- Sources/UIViewPropertyAnimator+Promise.swift | 11 ++--------- Tests/TestUIViewPropertyAnimator.swift | 2 +- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/Sources/UIViewPropertyAnimator+Promise.swift b/Sources/UIViewPropertyAnimator+Promise.swift index f95d230..b86e76a 100644 --- a/Sources/UIViewPropertyAnimator+Promise.swift +++ b/Sources/UIViewPropertyAnimator+Promise.swift @@ -5,6 +5,8 @@ import UIKit @available(iOS 10, tvOS 10, *) public extension UIViewPropertyAnimator { + /// - Note: cancelling this promise will cancel the underlying task + /// - SeeAlso: [Cancellation](http://promisekit.org/docs/) func startAnimation(_: PMKNamespacer) -> Guarantee { return Guarantee(cancellableTask: self) { addCompletion($0) @@ -23,12 +25,3 @@ extension UIViewPropertyAnimator: CancellableTask { return (state == .inactive) && (fractionComplete < 1.0) } } - -//////////////////////////////////////////////////////////// Cancellable wrapper - -@available(iOS 10, tvOS 10, *) -extension UIViewPropertyAnimator { - public func cancellableStartAnimation(_: PMKNamespacer) -> CancellablePromise { - return cancellable(startAnimation(.promise)) - } -} diff --git a/Tests/TestUIViewPropertyAnimator.swift b/Tests/TestUIViewPropertyAnimator.swift index 98f3789..0902d86 100644 --- a/Tests/TestUIViewPropertyAnimator.swift +++ b/Tests/TestUIViewPropertyAnimator.swift @@ -31,7 +31,7 @@ extension UIViewPropertyAnimatorTests { let animator = UIViewPropertyAnimator(duration: 0.1, curve: .easeIn, animations: { [weak self] in ex1.fulfill() }) - let p = animator.cancellableStartAnimation(.promise).done { _ in + let p = cancellable(animator.startAnimation(.promise)).done { _ in XCTFail() }.catch(policy: .allErrors) { error in error.isCancelled ? ex2.fulfill() : XCTFail("Error: \(error)")