Use function in closure - swift

I am trying to use a function within a closure but I am receiving an error 'cannot convert value of type () to closure result type Bool'. The following code demonstrates the error. How can I make this work?
func test1(){
test2(){ success in
self.test1()
}
}
func test2(completionHandler: (Bool) -> Bool){
completionHandler(true)
}

You specify that the test2 closure returns a Bool, so return one:
func test1(){
test2 { (success) -> Bool in
test1()
return success
}
}
Have test2's closure return void if you don't want to return a value from it:
func test1(){
test2 { (success) in
test1()
}
}
func test2(completionHandler: (Bool) -> Void){
completionHandler(true)
}

Related

Invalid conversion from throwing function of type XXXX to non-throwing function type XXXX

I am stuck with this situation where I have a custom JSONDecoder struct which contains a private function to decode data, and another function which is exposed, and should return a specific, Decodable type. I would like these functions to throw successively so I only have to write my do/catch block inside the calling component, but I'm stuck with this error on the exposedFunc() function:
Invalid conversion from throwing function of type '(Completion) throws -> ()' (aka '(Result<Data, any Error>) throws -> ()') to non-throwing function type '(Completion) -> ()' (aka '(Result<Data, any Error>) -> ()')
Here is the code:
import Foundation
import UIKit
typealias Completion = Result<Data, Error>
let apiProvider = ApiProvider()
struct DecodableTest: Decodable {
}
struct CustomJSONDecoder {
private static func decodingFunc<T: Decodable>(
_ response: Completion,
_ completion: #escaping (T) -> Void
) throws {
switch response {
case .success(let success):
try completion(
JSONDecoder().decode(
T.self,
from: success
)
)
case .failure(let error):
throw error
}
}
static func exposedFunc(
value: String,
_ completion: #escaping (DecodableTest) -> Void
) throws {
apiProvider.request {
try decodingFunc($0, completion)
}
}
}
class CustomViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
do {
try CustomJSONDecoder.exposedFunc(value: "test_value") { result in
// Do something with result
}
} catch {
print(error)
}
}
}
class ApiProvider: NSObject {
func request(_ completion: #escaping (Completion) -> ()) {
}
}
Thank you for your help
This defines method that takes a non-throwing function:
class ApiProvider: NSObject {
func request(_ completion: #escaping (Completion) -> ()) {
}
}
So in all cases, this function must take a Completion and return Void without throwing. However, you pass the following:
apiProvider.request {
try decodingFunc($0, completion)
}
This method does throw (note the uncaught try), so that's not allowed. You need to do something if this fails:
apiProvider.request {
do {
try decodingFunc($0, completion)
} catch {
// Here you must deal with the error without throwing.
}
}
}
Not using concurrency features is making your code hard to understand. Switch!
final class CustomViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
Task {
let result = DecodableTest()
// Do something with result
}
}
}
extension DecodableTest {
init() async throws {
self = try JSONDecoder().decode(Self.self, from: await APIProvider.data)
}
}
enum APIProvider {
static var data: Data {
get async throws { .init() }
}
}

Swift: Convert a Sync function to Async

If you have a sync function, how would you convert it to an async function?
func syncFunc() -> Int {
//Do something
}
Would this work?
func asyncFunc(_ syncFunc:()->Int, _ completion:(Int)->()) -> Int {
DispatchQueue.background.async{
completion( syncFunc() )
}
}
No, functions containing an asynchronous task cannot return any value from the closure body and both closures must be marked as #escaping
func asyncFunc(_ syncFunc: #escaping ()->Int, completion: #escaping (Int)->()) {
DispatchQueue.global().async {
completion( syncFunc() )
}
}

Optional closure with Bool return type

I have a method with an optional closure argument like this:
func when(_ name:String, state:State = .normal, closure:(() -> Bool)? = nil)
{
...
}
I call them like this:
when("I do something")
{
if !self.doSomething() { return false }
if !self.doSomethingElse() { return false }
return true
}
This gives me a compile-time error:
Error: cannot convert value of type '()' to expected argument type
'Bool'
What is going on here? Why does Swift sees a type () where Bool is expected?
Your function self.doSomething() and self.doSomethingElse() do not return a bool value
Instead of
func doSomething() {
return true
}
It should be like this
func doSomething() -> Bool {
return true
}

ReactiveCocoa ignore nil in Swift

I'm using ReactiveCocoa in many places around my app. I've build a check to skip nil values as followed:
func subscribeNextAs<T>(nextClosure:(T) -> ()) -> RACDisposable {
return self.subscribeNext {
(next: AnyObject!) -> () in
self.errorLogCastNext(next, withClosure: nextClosure)
}
}
private func errorLogCastNext<T>(next:AnyObject!, withClosure nextClosure:(T) -> ()){
if let nextAsT = next as? T {
nextClosure(nextAsT)
} else {
DDLogError("ERROR: Could not cast! \(next)", level: logLevel, asynchronous: false)
}
}
This helps to log failed castings, but will also fail for nil values.
In Objective-C you would simply call ignore as followed:
[[RACObserve(self, maybeNilProperty) ignore:nil] subscribeNext:^(id x) {
// x can't be nil
}];
But in Swift the ignore property can't be nil. Any idea to use ignore in Swift?
Finally, with help from powerj1984 I created this method for now:
extension RACSignal {
func ignoreNil() -> RACSignal {
return self.filter({ (innerValue) -> Bool in
return innerValue != nil
})
}
}

How to use #autoclosure parameter in async block in Swift?

I would like to call an #autoclosure parameter inside dispatch_async block.
func myFunc(#autoclosure condition: () -> Bool) {
dispatch_async(dispatch_get_main_queue()) {
if condition() {
println("Condition is true")
}
}
}
I get the following error.
Closure use of #noescape parameter may allow it to escape.
Is it possible to call #autoclosure parameter asynchronously?
Tested in Xcode 6.4 (6E23).
Yes, so long as you declare them #autoclosure(escaping):
Declarations with the autoclosure attribute imply noescape as well, except when passed the optional attribute escaping.
So this should do it:
func myFunc(#autoclosure(escaping) condition: () -> Bool) {
dispatch_async(dispatch_get_main_queue()) {
if condition() {
println("Condition is true")
}
}
}
Updating the answer from Airspeed Velocity, you can pass weak self directly into escaping autoclosure.
var boolValue: Bool = true
func myFunc(condition: #autoclosure #escaping () -> Bool?) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
if let condition = condition() {
print("Condition is \(condition ? "true" : "false")")
}
}
}
func main() {
weak var weakSelf = self
myFunc(condition: weakSelf?.boolValue)
}