Empty Return Value from Swift Function Containing Closure

Empty return value from swift function containing closure

You should use Closures in method to return statusUpdates as its Async method.
The empty statusUpdates will be returned immediately in your code but when using closures, you can wait till DataManager.getStatusDataWithSuccess is finished:

typealias RemoteStatusHandler = (status:[StatusModel]) -> Void

func getStatusFromRemoteSource(handler:RemoteStatusHandler){

var statusUpdates = [StatusModel]()
println("statusUpdates after initialization: \(statusUpdates)") // 1

DataManager.getStatusDataWithSuccess { (statusData) -> Void in
let json = JSON(data: statusData)

if let jsonArray = json.array {

for jsonItem in jsonArray {
var statusVersion: String? = jsonItem["version"].string
var statusDescription: String? = jsonItem["message"].string
var statusCode: Int? = jsonItem["code"].string!.toInt()

var update = StatusModel(version: statusVersion, message: statusDescription, code: statusCode)
statusUpdates.append(update)
println("statusUpdates after appending update: \(statusUpdates)") // 3 (after other function call)
}

let item = 0
println("Version \(statusUpdates[item].version) has status \(statusUpdates[item].message)")
// println("Status code: \(statusUpdates[item].code)")
}

handler(status: statusUpdates)
}

}

Then your function can be called like this:

getStatusFromRemoteSource { (status) -> Void in
//use status here, this function is void.
}

Swift. How to return a function from a closure

Closure does not support return statement. Instead use completion block inside main thread to perform the task:

i.e

function AA( completion: @escaping (Result<[Return Type], Error>) -> Void) {
localPlayer.authenticateHandler{
//…
if trigger {
DispatchQueue.main.async {
completion(//Whatever Return Value)
}
}
dosomething()
}
}

Returning a value from a Swift function containing a closure

Add a completion handler (named dataHandler in my example) to your loadData function:

private func loadData(dataHandler: ([Item])->()) throws {
var items = [Item]()
let jsonUrl = "http://api.openweathermap.org/data/2.5/forecast/daily?units=metric&cnt=7&q=coventry,uk"
print(jsonUrl)
let session = NSURLSession.sharedSession()
guard let shotsUrl = NSURL(string: jsonUrl) else {
throw JSONError.InvalidURL(jsonUrl)
}
session.dataTaskWithURL(shotsUrl, completionHandler: {(data, response, error) -> Void in
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: [])
print(json)
guard let days:[AnyObject] = (json["list"] as! [AnyObject]) else {
throw JSONError.InvalidArray
}
for day in days {
guard let timestamp:Double = day["dt"] as? Double else {
throw JSONError.InvalidKey("dt")
}
print(timestamp)
let date = NSDate(timeIntervalSince1970: NSTimeInterval(timestamp))
guard let weather:[AnyObject] = day["weather"] as? [AnyObject] else {
throw JSONError.InvalidArray
}
guard let desc:String = weather[0]["description"] as? String else {
throw JSONError.InvalidKey("description")
}
guard let icon:String = weather[0]["icon"] as? String else {
throw JSONError.InvalidKey("icon")
}
guard let url = NSURL(string: "http://openweathermap.org/img/w/\(icon).png") else {
throw JSONError.InvalidURL("http://openweathermap.org/img/w/\(icon).png")
}
guard let data = NSData(contentsOfURL: url) else {
throw JSONError.InvalidData
}
guard let image = UIImage(data: data) else {
throw JSONError.InvalidImage
}
guard let temp:AnyObject = day["temp"] else {
throw JSONError.InvalidKey("temp")
}
guard let max:Float = temp["max"] as? Float else {
throw JSONError.InvalidKey("max")
}
let newDay = Item(date: date, description: desc, maxTemp: max, icon: image)
print(newDay)
items.append(newDay)
}
dataHandler(items)
} catch {
print("Fetch failed: \((error as NSError).localizedDescription)")
}
}).resume()
}

do {
try loadData { itemsArray in
print(itemsArray)
}
} catch {
print(error)
}

I've tested it in a Playground and it works without errors:

Sample Image

how to call a closure with argument in a function

That is not how closures work in Swift. And the code you wrote doesn't even make sense. Why do you assign n to name then change the value of name just to print it ?

The function with the closure will call the closure with a given value. You can think of closures as lambda functions. Here is an example:

func test(_ closure: @escaping (String) -> Void) {
closure("My string")
}

test { str in
print(str) //prints " My string"
}

For what you are trying to achieve, just use a String parameter in your function:

func test(_ str: String) {
print(str)
}

test("My string") // prints "My string"

Or use a closure that takes Void:

func test(_ closure: @escaping (Void) -> Void) {
closure()
}

test {
print("My string") // prints "My string"
}

Return value for function in nested function (Swift 3 | Xcode)

There is no way to return from the outer function from within the inner one. The only way I can think of is by using a completion handler, that you can then call from within the nested function like so:

func checkIfUserExists(userID : String, completion: @escaping (_ userExists: Bool) -> Void)

How to return value from a closure in a Struct in Swift?

You're seeing this error because the closure captures an immutable self.

Just like primitive types (e.g. Int), structs are value-types, and Swift is built with the notion of immutability of value-types.

In other words, if you had let questionManager = QuestionManager(), you'd expect questionManager not to change. Even if it was a var, it can only mutate via direct action by the caller, e.g. questionManager.doMutatingFunc().

But, if a closure was allowed to capture self, it could modify itself at some later point. This is not allowed.

This simplest (only?) way to fix this is to turn QuestionManager into a class:

class QuestionManager {
// ...
}

How many ways there to write a closure in swift?


Closure Rules:


  1. If the closure block solely returns value after the 'in' keyword (or
    the closure block just returns a value) then using 'return' keyword is
    optional.

  2. Defining closure argument type is optional if the closure type is
    explicitly defined.

  3. Defining closure return type is optional, if closure arguments are
    defined with it's type and there is no other statement in the return
    block or the closure type is explicitly defined.

  4. Defining closure arguments, return type and 'in' keyword is optional
    if closure is explicitly defined, in this case if the closure has any
    argument, it is compulsory to use them and refer them using indexes,
    eg: $0 represents first argument, $1 represents second argument and so
    on.

  5. Defining closure type, arguments, return type and 'in' keyword is
    optional if closure have no arguments and there is no other statement
    in the return block.

  6. Defining closure type explicitly is optional if closure arguments(if
    any) are defined with it's type and either there is no other statement
    in the return block or return type is also defined.

  7. If type is defined explicitly then it should be defined completely.


Closure rules in action:

// Rule#1: If the closure block solely returns value after the 'in' keyword (or the closure block just returns a value) then using 'return' keyword is optional.
var rule_1:(String)->String = { (txt:String)->String in
"Rule_1: 'return' keyword is not defined because there is no other statement in the return block, Text = \(txt)"
}
print(rule_1("xyz"))
print("")

// Rule#2: Defining closure argument type is optional if the closure type is explicitly defined.
var rule_2:(String)->String = { (txt)->String in
print("", terminator:"")
return "Rule_2: Closure argument type is not defined because closure type is explicitly defined, Text = \(txt)"
}
print(rule_2("xyz"))
print("")

// Rule#3: Defining closure return type is optional, if closure arguments are defined with it's type and there is no other statement in the return block or the closure type is explicitly defined.
var rule_3_1:(String)->String = { (txt:String) in
print("", terminator:"")
return "Rule_3_1: Return type is not defined because closure type is explicitly defined, Text = \(txt)"
}
var rule_3_2 = { (txt:String) in
return "Rule_3_2: Return type not defined because arguments are defined with it's type and there is no other statement in the return block, Text = \(txt)"
}
print(rule_3_1("xyz"))
print(rule_3_2("xyz"))
print("")

// Rule#4: Defining closure arguments, return type and 'in' keyword is optional if closure is explicitly defined, in this case if the closure has any argument, it is compulsory to use them and refer them using indexes, eg: $0 represents first argument, $1 represents second argument and so on.
var rule_4:(String)->String = {
print("", terminator:"")
return "Rule_4: Closure arguments, return type and 'in' keyword is not defined because closure is explicitly defined, Text = \($0)"
}
print(rule_4("xyz"))
print("")

// Rule#5: Defining closure type(explicitly), arguments, return type and 'in' keyword is optional if closure have no arguments and there is no other statement in the return block.
var rule_5 = {
return "Rule_5: Closure type, closure arguments, return type and 'in' keyword not defined because closure have no arguments and there is no other statement in the return block, Text = \"\""
}
print(rule_5())
print("")

// Rule#6: Defining closure type explicitly is optional if closure arguments(if any) are defined with it's type and either there is no other statement in the return block or return type is also defined.
var rule_6_1 = { (txt:String)->String in
print("", terminator:"")
return "Rule_6_1: Closure not explicitly defined because closure arguments are defined with it's type and return type, Text = \(txt)"
}
var rule_6_2 = { (txt:String) in
return "Rule_6_2: Closure not explicitly defined because closure arguments are defined with it's type and there is no other statement in the return block, Text = \(txt)"
}
print(rule_6_1("xyz"))
print(rule_6_2("xyz"))

Output:

Closure rules output



Related Topics



Leave a reply



Submit