malcommac / hydra Goto Github PK
View Code? Open in Web Editor NEW⚡️ Lightweight full-featured Promises, Async & Await Library in Swift
License: MIT License
⚡️ Lightweight full-featured Promises, Async & Await Library in Swift
License: MIT License
.voidPromise()
should be public in order to be used to chain multiple Promises which return different results.
Example:
let op_1: Promise<User> = asyncGetCurrentUserProfile()
let op_2: Promise<UIImage> = asyncGetCurrentUserAvatar()
let op_3: Promise<[User]> = asyncGetCUrrentUserFriends()
all(op_1.void,op_2.void,op_3.void).then { _ in
let userProfile = op_1.result
let avatar = op_2.result
let friends = op_3.result
}.catch { err in
// do something
}
We will also rename voidPromise()
func to void
variable.
Need to rename the Hydra enum to something else because it causing the ambiguity error in those projects in which similar namination is used. For eg. In my project I used a class with name Promise and when I try to tell compiler that use the Promise of Hydra by Hydra.Promise<Int>
then it start complaing that Hydra Enum doesn't contain a case promise. For more Information check issue
I think this will be helpful to have some function analog to the 'zip' function which will accept the list of promises, wait until all of them is finished and returns both failed and resolved in the result.
Is there a reason for not allowing Promise to be subclassed?
I would to implement cancel()
func in Hydra.
These days I'll investigate by looking at other libs implementations.
(@r-plus have you some advices?)
As pointed in #68 Linux compilation does not work correctly.
Hi @malcommac,
as the title, is that wanted?
Xcode 8.3 (8E162)
I'm in the process of evaluating Hydra over PromiseKit, the overall process of converting from one to the other hasn't been too hard, actually cleaned up the code a bit, but I've hit a snag
When trying to work with zip
I keep getting
Error:(695, 24) cannot invoke 'zip' with an argument list of type '(a: Promise<APIAccessRestrictionState>, b: Promise<APIServiceAccessState>)'
I've expanded the code a little in an effort to try and solve the issue (and make it easier to read)
let restrictionStatePromise: Promise<APIAccessRestrictionState> = CioffiAPIManager.shared.getServicesAuthenticatedState()
let accessStatePromise: Promise<APIServiceAccessState> = CioffiAPIManager.shared.getServiceAccessState()
return Promise<Void>.zip(
a: restrictionStatePromise,
b: accessStatePromise)
.then { (restrictionState: APIAccessRestrictionState,
accessState: APIServiceAccessState) -> Promise<Bool> in
self.authorisedState = DefaultAPIAccessRestrictionState(from: state)
self.serviceAccessState = state
self.authenticationChanged()
return Promise<Bool>(resolved: true)
}
I've also tried using...
return Promise.zip(
a: restrictionStatePromise,
b: accessStatePromise)
But neither work.
APIServiceAccessState
is a typealias
of APIAccessRestrictionState
...
public typealias APIServiceAccessState = APIAccessRestrictionState
so I'm wondering if that's the issue and if something like all
might be better
I am currently unable to build Hydra 1.0.0 in Swift 3 for the MacOS target.
In Promise+Recover.swift
, the recover method does not compile correctly because it is unable to resolve which then
method to invoke. The build error is: /Hydra/Promise+Recover.swift:47:11: Ambiguous reference to member 'then(in:_:)'
If you remove the lines:
.cancelled(in: ctx, { _ -> Void in operation.cancel() })
then the swift compiler is able to resolve the appropriate then
helper and the framework compiles.
Hi Malcom! Is there any kind of progress block for things like uploading an avatar for example.
uploadAvatar()
.progress { p in
// Here update progressView for example
}
.then(doSomething)
.onError(showErrorPopup)
.finally(doSomething)
How do you use '[weak self]' in the then portion of the promise? Or do you not need to?
Nice library! This is exactly what I'm looking for. But I got this error message when I tried to integrate it with my project (by Carthage).
Module file's minimum deployment target is ios10.2 v10.2: ./Carthage/Build/iOS/Hydra.framework/Modules/Hydra.swiftmodule/arm64.swiftmodule
I get 3 warnings and 4 errors when compiling on Swift 4 (even though the readme says v0.9.6 and above is swift 4 compatible). The readme also references a swift-4 branch, which doesn't seem to exist.
Hi,
I just run old code in with swift 3 xcode 9 with ios 11 and got below error :
Pods/HydraAsync/Sources/Hydra/DispatchTimerWrapper.swift:46:9: 'schedule(deadline:repeating:leeway:)' is unavailable]
Please suggest what to do?
Thank you.
Hi, I want to use Promise<Void>
in Hydra 2.0.2 and Swift 5.2 (Xcode 11.4).
I tried to use it as following code.
Promise<Void>(in: .main, token: token) { resolve, reject, _ in
resolve()
}
However compiler reports an error Missing argument for parameter #1 in call
.
How do I change the code to use Promise<Void>
?
Ciao 👋
As reported in the release notes, the await keyword will start to emit warnings in Xcode 12.5:
Deprecations
The Swift compiler emits a warning for the use of the await keyword as an unqualified identifier. Wrap await with back-ticks so Swift always treats it as an identifier, or fully qualify declarations named await (for example, by adding self if it is a reference to an instance member named await from within the instance). (SE-0296, 67000350)
Is there any plan to address this in Hydra?
Thanks 🙌
Object will only be released (deinit) after the time interval of timeout setting. For example:
.timeout(50)
.dosomething()
if all the work be done in 1 second, the object will be deinit after 50 seconds.
Would you please help to check it?
return Promise( { [unowned self] (resolve, reject) in
NotificationCenter.default.addObserver(
forName: SOME_NOTIFICATION,
object: nil,
queue: nil,
using: { (notification:Notification) -> Void in
resolve() // never called
})
SOME_ACTION_TRIGGER_NOTIFICATION()
})
We are using Hydra as part of a client API framework. There is a version without Promise
that uses Alamofire
for networking. We then add a Promise
based wrapper for each API call.
The framework exists for both iOS and macOS.
Recently we upgraded to Xcode 11.2, swift 5.1 and Hydra 2.0.2 (from 1.2.1, using SPM).
Now our tests for macOS pass, but the iOS tests crash in Promise.swift, line 71:
public lazy var operation: PromiseStatus = {
return PromiseStatus(token: self.invalidationToken, { [weak self] () -> () in
self?.set(state: .cancelled)
})
}()
I tried to debug but could not figure out what is going on.
Here is a sample project that reproduces the bug.
The project has two targets, one for iOS and one for macOS. Both use the same source and test swift files.
The macOS tests pass but the iOS promise test fails (the standard api test passes, so the api part is ok).
it's in the project description, but not available.
Hey guys, first of all thank you very much for this great library!
I have dismissActivityIndicator
method, which returns a promise:
func dismissActivityIndicator<T>(any: T) -> Promise<T> {
return Promise<T> { resolve, _, _ in
KVNProgress.dismissAnyway {
resolve(any)
}
}
}
My question is how can I inject it into the promise chain, so it is always executed at end? It's fairy simple with always
and a plain non-async method, but how to achieve the same result with the method returning a Promise
?
help wanted
would be an appropiate tag for this question, as this is not an issue :)
Hi everyone!
I'm using Hydra 2.0.6 on iOS on Xcode 13.2.1.
I would like to import Hydra
on this file
import SwiftUI
struct VideocallViewControllerWrapper: UIViewControllerRepresentable {
...
}
but as soon as I import it, Xcode tells me that Type 'VideocallViewControllerWrapper' does not conform to protocol 'UIViewControllerRepresentable'
. I have other files where I have successfully imported both SwiftUI and Hydra. I think the problem is the presence of UIViewControllerRepresentable
.
Thank you
I think it would be helpful if this feature is available.
When trying to build I get the following error in Promise+Recover.swift
:
Cannot convert value of type 'Promise<Void>' to closure result type()'
It works fine on Xcode 11.5.
Version 1.2.1
using swift 3.1 version of spm and its having trouble installing though server side project is in 4.0 (using Perfect Server Side) . too many errors to copy and paste here but It tried different major and minor versions and no success.
the documentation says that the all
function is a static function of the Promise
class.
https://github.com/malcommac/Hydra#all
But I cannot find this function.
The all
function seems to be a global function, that must be declared as public
if is intended to be used from outside the framework.
Hi guys, I have been using this library for a while and I have to say it's very easy to work with it.
I have a concern about cancellable promises, specifically the behaviour of a chain of promises when a promise in the middle has been cancelled.
Let's say we have:
A.then(B).then(C).then(D).then(E)
.then { _ in
print("success")
}.catch { _ in
print("failed")
}.cancelled { in
print("cancelled")
}
If, for example, C gets cancelled while A and B resolve correctly, I'm expecting that cancelled
is printed out, but what I observe is that the sequence gets stuck in pending
state.
This behaviour can be checked with the following test that recalls the ones provided with the library, which fails for timeout:
func test_cancelledPromiseChainable2() {
let exp = expectation(description: "test_cancelledPromiseChainable2")
let invalidator: InvalidationToken = InvalidationToken()
invalidator.isCancelled = true
intPromise().then { _ in
self.test_invalidationToken(token: invalidator)
}.then { total in
print("Operation finished with: \(total)")
XCTFail()
}.catch { _ in
print("Operation failed")
}.cancelled {
print("Operation cancelled")
exp.fulfill()
}
waitForExpectations(timeout: expTimeout, handler: nil)
}
If I'm not misinterpreting the situation, I will open a PR with a suggested fix, otherwise please let me know the reasoning behind this behaviour.
Thanks,
AT
Hi, cool library 👍
I was reading through https://github.com/malcommac/Hydra/blob/master/Sources/Hydra/Await.swift#L109
// Create a semaphore to block the execution of the flow until
// the promise is fulfilled or rejected
let semaphore = DispatchSemaphore(value: 0)
so we're turning async code -> sync code by blocking the current thread?
Also, it would be cooler if there's an example project 😉
What I was wishing for:
all(promiseA,promiseB).then { resultA, resultB in
}
Based on the docs it would have to be
all(promiseA,promiseB).then { result in
let resultA = result[0]
let resultB = result[1]
}
or
Promise<Void>.zip(promiseA, promiseB).then { resultA, resultB in
}
Any thoughts?
I get the following compile error:
/Users/stefan/Documents/Git-Workspace/Modules/Hydra/Sources/Hydra/Promise+Recover.swift:47:11: error: ambiguous reference to member 'then(in:_:)'
return self.then(in: ctx, {
^~~~
/Users/stefan/Documents/Git-Workspace/Modules/Hydra/Sources/Hydra/Promise+Then.swift:48:14: note: found this candidate
public func then<N>(in context: Context? = nil, _ body: @escaping ( (Value) throws -> N) ) -> Promise<N> {
^
/Users/stefan/Documents/Git-Workspace/Modules/Hydra/Sources/Hydra/Promise+Then.swift:76:14: note: found this candidate
public func then<N>(in context: Context? = nil, _ body: @escaping ( (Value) throws -> (Promise<N>) )) -> Promise<N> {
^
/Users/stefan/Documents/Git-Workspace/Modules/Hydra/Sources/Hydra/Promise+Then.swift:118:14: note: found this candidate
public func then(in context: Context? = nil, _ body: @escaping ( (Value) throws -> () ) ) -> Promise<Value> {
^
I'm using Xcode 9.0 (9A235), swift 4 and a deployment target of 10.12.
I'm using Hydra 2.0.6 with Xcode 13, but at compile time I get a message that Hydra requires iOS 12 or higher.
But I didn't have any problems when using Xcode 12 and Hydra 2.0.5.
Did the minimum requirements change? Thank you.
Showing Recent Messages
/Users/hoge/Test/ViewController.swift:11:8: Compiling for iOS 10.0, but module 'Hydra' has a minimum deployment target of iOS 12.0: /Users/hoge/Library/Developer/Xcode/DerivedData/Test-akvdfnkqlvyyxafhnfgahlouszoz/Build/Products/Debug-iphonesimulator/Hydra.framework/Modules/Hydra.swiftmodule/x86_64-apple-ios-simulator.swiftmodule
promise.then {
// test 1
}.then {
// test 2
}.always {
// always 1
}
Are not correctly executed on Xcode 12 and the result is not catched.
I add this line to DemoApp's viewDidLoad method.
Promise<Int>(resolved: 3).catch { _ in }
After launch the DemoApp, invoke memory visualizer in Xcode 8(below screenshot is it) that indicate two Promise
object is still exist and memory leak(Strong reference cycle).
I confirmed this issue on 5692f3e.
https://github.com/malcommac/Hydra/blob/d12500aaf1685b338231f03cdfa49c4aa01858a3/README.md
in README.md, retry
is written twice in line 20.It is good to match because the order is different from Index.
https://github.com/malcommac/Hydra/blob/d12500aaf1685b338231f03cdfa49c4aa01858a3/README.md#all-features
There is no retry
in All Feature
.
Hey, great library! I have been looking for something like this for a while.
I'd like to suggest that zip should receive an array of promises (if all of them shares the same return type) and a return a promise that combines all the inputs. It could also receive a reduce function as argument. What do you think?
I mean something like this:
var promises = [Promise<User>]()
// Some code here.
Promise.zip(promises)
.then { (users: [User]) in
}
Thanks!
I am getting next errors
*** Building scheme "Hydra-macOS" in Hydra.xcodeproj
** CLEAN FAILED **
The following build commands failed:
Check dependencies
(1 failure)
** BUILD FAILED **
The following build commands failed:
Check dependencies
(1 failure)
warning: no umbrella header found for target 'Hydra-macOS', module map will not be generated
warning: no umbrella header found for target 'Hydra-macOS', module map will not be generated
A shell task failed with exit code 65:
** CLEAN FAILED **
The following build commands failed:
Check dependencies
(1 failure)
** BUILD FAILED **
The following build commands failed:
Check dependencies
(1 failure)
how to use "Unit Test"?
Played around with this library a bit and noticed Xcode is reporting quite a few memory leaks using the latest version and with a simple function:
func testPromise() -> Promise<Int> {
return Promise<Int>(in: .utility, { (resolve, reject, _) in
resolve(5)
})
}
testPromise().then { result in
print(result)
}
Hi! First of all, I have to say that I really love this library 🙏
The reason for this issue is cause I'm not sure if I found a bug or if I misunderstood the semantics of retry
with delay.
I was trying to implement polling to a web server leveraging Promises.
Say we have promise: Promise<Value>
which encapsulate the async call to our backend. Then I expressed polling with something like:
promise
.validate { value in /* predicate to decide if continue polling */ }
.retry(10, delay: pollingTime)
Since:
validate
rejects the promise if the predicate is not metretry
allow to execute source chained promise if it ends with a rejection (exactly what I need, to re-issue the web call)delay
is the delay between each attempt (starting when failed the first time)My expectation was to retry the promise at most 10 times, each with a delay of pollingTime
.
AFAIU, the delay is implemented with the defer
which in turn defers only the happy path (then
) but the retryWhen
is actually targeting a rejected promise. This results in the delay being applied in the only attempt that succeeds (if any).
I've also tried to encapsulate the validate inside the promise (rejecting it if the predicate is not met) but it didn't move the problem.
I could achieve what I expected only pushing the validation inside the promise and implementing a deferAll
:
func `deferAll`(in context: Context = .background, _ seconds: TimeInterval) -> Promise<Value> {
guard seconds > 0 else { return self }
let fireTime: DispatchTime = .now() + seconds
return self
.then(in: context) { value in return Promise<Value> { resolve, _, _ in
context.queue.asyncAfter(deadline: fireTime) { resolve(value) }
}}
.recover { error in return Promise<Value> { _, reject, _ in
context.queue.asyncAfter(deadline: fireTime) { reject(error) }
}}
}
}
and leveraging it inside the retryWhen
in place of the defer
.
Am I misunderstanding the semantic of retry
with delay?
Thank you 😄
/home/user/Project/.build/checkouts/Hydra.git-8391472609009747209/Sources/Hydra/Promise+Await.swift:99:20: error: binary operator '!=' cannot be applied to two 'DispatchQueue' operands
guard self.queue != DispatchQueue.main else {
~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~
Swift version 5.0.1 (swift-5.0.1-RELEASE)
Target: x86_64-unknown-linux-gnu
Ubuntu 16.04.6 LTS
Let's say I use the example:
let asyncFunc = async({ _ -> Int in
let loggedUser = try await(loginUser(username,pass))
let followersList = try await(getFollowers(loggedUser))
let countUnfollowed = try await(unfollow(followersList))
return countUnfollowed
}).then({ value in
print("Unfollowed \(value) users")
})
How would I make that cancelable?
I'm trying to use await
using the syntax from the readme.
let city = try await(getCityPromise())
The getCityPromise
function is declared like this:
func getCityPromise() -> Promise<String> { ... }
But the compiler raises an error
cannot invoke 'await' with an argument list of type '(Promise<String>)'
Then I looked at the unit tests, and I saw that a special operator ..
is used instead of calling the await
function.
Using that operator my code doesn't raise any error anymore. Should the documentation be fixed or I'm missing something?
This will not run:
not even the print statement runs.
This however runs:
Does the async
func always need to be used in a chain using methods like .always
? The README examples seem to show this is not needed, but I am confused about its actual usage.
NOTE: the waitUntil
func is from Nimble
Even if there was some sort of problem w/ the waitUntil
func, shouldnt the 1st print
statement at least execute before it timesout?
any()
global function is not visible outside the library.
Hi!
How about using Nested generics
released in Swift 3.1?
I want to make State
and Observer
nested generics.
For example as below.
extension Promise {
/// ....
internal indirect enum State {
case pending
case resolved(_: Value)
case rejected(_: Error)
/// It continues below....
}
/// ....
internal indirect enum Observer {
typealias ResolveObserver = ((Value) -> (Void))
typealias RejectObserver = ((Error) -> (Void))
case onResolve(_: Context, _: ResolveObserver)
case onReject(_: Context, _: RejectObserver)
/// It continues below...
}
}
If there is no problem I think I will give out PR.
Hi Daniele and contributors,
I was wondering if you had thoughts on this situation. I'm wrapping an Alamofire download, which would resolve a temporary url, and then the final destination url. It would be nice to have a couple of Promises. Any perspective would be greatly appreciated.
func streamFile(key: String = "default") -> Promise<URL> {
let source = self.serverURL(forKey: key)
let (localURL, exists) = self.fileURL()
return Promise<URL>({ resolve, reject in
if !exists {
Alamofire.download(source, to: { temp, response in
// Temporary URL
resolve(temp)
return (localURL, [.removePreviousFile, .createIntermediateDirectories])
}).response { response in
if response.error == nil {
// Final URL
resolve(response.destinationURL!)
}
else {
log(error: response.error.debugDescription)
reject(CommonError.networkConnectionError)
}
}
}
else {
resolve(localURL)
}
})
}
Promise.all is throwing a no member all error.
import Hydra
Promise.all(promises).then({
})
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.