I want to execute code with dispatchqueue. But only if a certain condition is true. I'm doing this so far, but there has to be a less ugly way.
if !sync {
return self.tasksInQueue[userID]
}
return SYNC_QUEUE.sync {
return self.tasksInQueue[userID]
}
I'm not sure its any cleaner.. but you could define a variable to define the common job to do...
let task = { self.tasksInQueue[userID] }
if sync {
return SYNC_QUEUE.sync { task() }
} else {
return task()
}
If this type of if happens in a bunch of places, you could in theory create some generic function to do the check for you..
func optionalSync <T> (_ sync: Bool, task: () -> T) {
if sync {
return SYNC_QUEUE.sync { task() }
} else {
return task()
}
}
Then whenever you need to do an op...
optionalSync(sync) { self.tasksInQueue[userID] }
Related
I have a Promise<T> that I would like to transform into a Guarantee<Bool> where true means the promise fulfilled and false if it got rejected.
I managed to reach this using
return getPromise()
.map { _ in true }
.recover { _ in Guarantee.value(false) }
I'm wondering if there is a neater way to do this.
Expanding on the original code and the answers here, I would make the extension explicitly for Void Promises, and keep the naming more inline with PromiseKit:
extension Promise where T == Void {
func asGuarantee() -> Guarantee<Bool> {
self.map { true }.recover { _ in .value(false) }
}
}
You can extend promise as below for easy usage mentioned under Usage
extension Promise {
func guarantee() -> Guarantee<Bool> {
return Guarantee<Bool>(resolver: { [weak self] (body) in
self?.done({ (result) in
body(true)
}).catch({ (error) in
body(false)
})
})
}
}
Usage:
// If you want to execute a single promise and care about success only.
getPromise().guarantee().done { response in
// Promise success handling here.
}
// For chaining multiple promises
getPromise().guarantee().then { bool -> Promise<Int> in
return .value(20)
}.then { integer -> Promise<String> in
return .value("Kamran")
}.done { name in
print(name)
}.catch { e in
print(e)
}
PromiseKit 6
I have a function that fetches a list of alerts from a db, I then need to use the contentId property on each to fetch the content and attach to the appropriate alert item.
Maybe there's a better way, but for now, what I came up with is to collect the promises into a list and call when(resolved:). I chose that because if any promise fails, I want to be able to return all those that can pass.
Inside my then handler in the function attachContents, the handler gets passed this type [Result] but the only field I can access when I map the list is isFulfilled
I checked what type Result was and found this:
public enum Result<T> {
case fulfilled(T)
case rejected(Error)
}
public extension PromiseKit.Result {
var isFulfilled: Bool {
switch self {
case .fulfilled:
return true
case .rejected:
return false
}
}
}
It led me to the first one, in Resolver.swift so I'm not sure why I can't get the data by calling fulfilled
private func getContent(for alert: Model) -> Promise<ViewModel> {
return firstly { () -> Promise<Any> in
if let contentType = AlertContentType(rawValue: alert.type) {
switch contentType {
case .news:
return newsService.get(contentId: contentId, superareaId: superareaId).compactMap { $0 as Any }
case .insight:
return insightService.get(contentId: contentId, superareaId: superareaId).compactMap { $0 as Any }
}
} else { throw DataError.Missing(error: "Could not retrieve type!") }
}.compactMap { content in
var viewModel = alert.toViewModel()
viewModel.content = content
return viewModel
}
}
private func attachContents(to alerts: [Model]) -> Promise<[ViewModel]> {
return firstly { () -> Guarantee<[Result<ViewModel>]> in
let contentPromises: [Promise<AlertViewModel>] = alerts.map {
return self.getContent(for: $0)
}
return when(resolved: contentPromises)
}.then { (vModels: [Result<ViewModel>]) -> Promise<[OIAlertViewModel]> in
vModels.map { (vm: Result<OIAlertViewModel>) in
// vm.isFulfilled is the only accessible property here
// can't call
}
}
}
Result is an enum of .fulfilled or .rejected
vModels.map { (vm: Result<OIAlertViewModel>) in
switch vm {
case .fulfilled(let alert):
print(alert)
case .rejected(let error):
print(error)
}
}
I would like to use this method from PromiseKit but dont know how to write propper synthax :x
public func firstly<U: Thenable>(execute body: () throws -> U) -> Promise<U.T> {
do {
let rp = Promise<U.T>(.pending)
try body().pipe(to: rp.box.seal)
return rp
} catch {
return Promise(error: error)
}
}
firstly {
return someMethodWhichReturnsPromise()
}.then{
}
...
How can I invoke this?
Code is from: https://github.com/mxcl/PromiseKit/blob/master/Sources/firstly.swift
A basic example of PromiseKit "firstly" usage:
func someMethodWhichReturnsPromise() -> Promise<Int> {
// return promise
}
firstly {
someMethodWhichReturnsPromise()
}.then {
// Execute more logic here after 'firstly' block completes
}.catch {
// handle error if you need to
handle(error: $0)
}
I am not so convinced with RxSwift yet, and it's really hard to cleat understanding. After reviewing different materials, I cant' still work and manipulate sequences.
On the whole I have problem with type converting:
Cannot convert return expression of type 'Observable<Bool>' to return type 'Observable<Void>' (aka 'Observable<()>')
I have CocoaAction processing, and should return Observable<Void>
func stopProject() -> CocoaAction {
return CocoaAction { _ in
let stopProject = stop(project: self.projectId)
return stopProject.asObservable() //wrong converting
}
}
The stop function return Observable<Bool>
Finish view:
return stop(project: self.projectId).flatMap { _ in
Observable<Void>.empty()
}
let voidObservable = boolObservable.map { Void() }
let voidObservable = boolObservable.map { _ in Void() }
And in the case that you only want to emit a value if the boolean value is true:
let voidObservable = boolObservable.filter { $0 }.map { _ in Void() }
Adding this extension:
public extension ObservableType {
func mapToVoid() -> Observable<Void> {
return map { _ in }
}
}
so you could do
myObservable.mapToVoid()
I am rookie with Swift. I need to change the following method to a boolean function which will return true if connection is ok else false if something is wrong. Thanks
func test() {
var configuration = SessionConfiguration()
configuration.host = "ftp://ftp.mozilla.org:21"
configuration.username = "optimus"
configuration.password = "rollout"
configuration.encoding = NSUTF8StringEncoding
_session = Session(configuration: configuration)
_session.list("/") {
(resources, error) -> Void in
println("List directory with result:\n\(resources), error: \(error)\n\n")
}
}
Since the _session.list("/") have a callback, which is asynchronous, what you can do is this:
func test(_ completion: (Bool) -> Void) {
// ...
_session.list("/") { (resources, error) -> Void in
println("List directory with result:\n\(resources), error: \(error)\n\n")
guard error == nil else {
completion(false) // failed
return
}
completion(true) // succeed
}
}
And so you can call it this way:
test() { (hasSucceeded: Bool) -> Void in
if hasSucceeded {
// Do what you want
} else {
// Failed
}
}
Lots of people have told you what to do, but nobody's clearly explained why.
The function _session.list() is an async function. When you call it it returns immediately, before it has even begun executing. The code runs on a separate thread, and the closure you pass in gets called once the function is complete.
Thus, you can't have your function return a simple bool. Async programming doesn't work that way.
Instead, you need to refactor your test function to take a closure with a bool parameter, as outlined by several other answers. (#KevinHirsch's answer for example.) Then when you invoke your test function you put the code that checks to see if the test passed or failed into the closure that you pass to the test function.
Since, session.list is an async process, add a completion handler and call your function as shown:
typealias theBool = (Bool) -> ()
func test(completion: theBool) {
//your code
_session.list("/") { (resources, error) in
guard error == nil else {
completion(false)
return
}
//your code
completion(true)
}
}
And call it like so:
test { someVar in
if someVar {
//do stuff when it is true
}
else{
//do stuff if it is false
}
}
When sync code:
func test() -> Bool {
return true
}
// Use case below:
let succes = test()
Turn to async use closure:
func test(didTest didTest: (Bool)->Void) {
...
_session.list("/") { (resources, error) -> Void in
if error != nil {
didTest(false)
} else {
didTest(true)
}
}
}
// Use case below:
test(didTest: { result in
let succes = result
})
Wish this may help.
Simply do
func test() -> Bool {
...
_session.list("/") { (resources, error) -> Void in
println("List directory with result:\n\(resources), error: \(error)\n\n")
if error != nil {
return true
} else {
return false
}
}
}
Updated:
I guess you should use closure for this because session.list is an async process. as #Duncan C said in his answer _session.list() When you call it it returns immediately, before it has even begun executing. The code runs on a separate thread, and the closure you pass in gets called once the function is complete.
public typealias SuccessClosure = (data: String) -> (Void)
public typealias FailureClosure = (error: NSError?, data: NSData? = nil, statusCode: Int? = nil) -> (Void)
func test(success: SuccessClosure, failure: FailureClosure) {
...
_session.list("/") { (resources, error) -> Void in
println("List directory with result:\n\(resources), error: \(error)\n\n")
if error != nil {
success("success")
} else {
failure(error)
}
}
}