Early Return from a Void-Func in Swift

early return from a void-func in Swift?

It is a tricky thing, Swift doesn't require semi-colons (they are optionally used), this makes Swift compiler automatically deduce whether is the next line should be a new line, or a completion for the old one. print() is a function that returns void. So the word return print("something"), is valid. So

return
print("Something")

could be deduced as return print("Something")

Your solution is to write

return;
print("Something")

Why Cant I return Void directly in a function

Void is a type, so it cannot be returned. Instead you want to return the representation of Void, which is an empty tuple.

Therefore, try this instead, and this will compile:

func test()->Void{
print("Hello")
}

func test1(){//print Hello
return test()
}

func test2()->Void{// throw error
return ()
}

test1()

For more information about why an empty tupple can be returned in a function that expects to return Void type, search for void in the following link: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html

Swift function with Void return type versus no return type

Simply, there is no difference. -> Void is just an explicit way of saying that the function returns no value.

From docs:

Functions without a defined return type return a special value of type Void. This is simply an empty tuple, in effect a tuple with zero elements, which can be written as ().

Thus, these three function declarations below are same:

func someFunc() {}
func someFunc() -> Void {}
func someFunc() -> () {}

Why i am getting Unexpected non-void return value in void function error while returning value in swift?

I think AuthManager.shared.saveAddressAsWorkHome(params) { (response) in this is asynchronous closure and you are try to return a value in it so you getting this error.

You can not return from asynchronous function directly. You have to add a completion handler on your method and return the value from async in completion handler

So you have to change your function

func getLatDestination(completion : @escaping (Double) -> ()){
var params = [String: Any]()
params[ParametersKeys.access_token] = KeyChain.getAccessToken()!
params[ParametersKeys.address] = googlePlaceObject?.results.first?.formattedAddress
params[ParametersKeys.latitude] = googlePlaceObject?.results.first?.geometry.location.lat
params[ParametersKeys.longitude] = googlePlaceObject?.results.first?.geometry.location.lng
params[ParametersKeys.googlePlaceId] = googlePlaceObject?.results.last?.placeId
params[ParametersKeys.login_type] = 1

AuthManager.shared.saveAddressAsWorkHome(params) { (response) in
if response.flag == RESPONSE_FLAGS.flag_143 {
if let addressData = response.response["addresses"] as? [[String: Any]] {
completion(addressData[0]["lat"])

}
}
}

And when you call your function

getLatDestination(completion: {ret in
print(ret)
})

Return void func from func in Swift

returnVoidFunc correctly returns a () ->() function, initFunc is a reference to that function.

The reason you see () printed is because you are evaluating initFunc, and since it returns (), and that's what's printed.

In Swift, by the way, () is basically the same as Void.

Unexpected non-void return value in void function' in swiftui

You are using an asynchronous method (dataTask). You don't know when it will be finished running (network request). It therefore cannot have a return value. When it finishes it executes the closure (URLSession.shared.dataTask (with: request) {// this block}).

You would certainly like to do it this way:

class DogManager {
var imageInfos: String?

func getFavoriteDoggo(breed: String) {
guard let url = URL(string: "https://dog.ceo/api/breed/\(breed)/images/random") else {
print("Trouble parsing url")
return
}

URLSession.shared.dataTask(with: url) { data, response, error in
guard error == nil, (response as? HTTPURLResponse)?.statusCode == 200 else {
return
}
if let data = data {
self.imageInfos = String(data: data, encoding: .utf8)
print(self.imageInfos ?? "no infos")
}
}.resume()
}
}

let manager = DogManager()
manager.getFavoriteDoggo(breed: "retriever/golden")

You can test in a Playground.

Now if you want to use SwiftUI and your View is redrawn when imageInfos changes you have to change your class to ObservableObject:

class DogManager: ObservableObject {
@Published var imageInfos: String?
//....//
}

And use it like this:

struct MainView: View {
@StateObject private var dm = DogManager()

var body: some View {
Text(dm.imageInfos ?? "nothing")
.onAppear {
dm.getFavoriteDoggo(breed: "retriever/golden")
}
}
}

iOS15 :

Note that with the introduction of async / await (iOS15) you can write asynchronous methods that have return values ​​(like you did) :

    @available(iOS 15.0, *)
func getFavoriteDoggo(breed: String) async -> String? {
guard let url = URL(string: "https://dog.ceo/api/breed/\(breed)/images/random"),
let (data, response) = try? await URLSession.shared.data(from: url),
(response as? HTTPURLResponse)?.statusCode == 200 else { return nil }
return String(data: data, encoding: .utf8)
}

You can use it with the new .task modifier :

struct MainView: View {
var dm = DogManager()
@State private var imageInfos: String?
var body: some View {
Text(imageInfos ?? "nothing")
.task {
await imageInfos = dm.getFavoriteDoggo(breed: "retriever/golden")
}
}
}

EDIT :

"Hey thank you for helping me out, but this would only work for only 1
dog breed."

First, let's create a new Dog structure. A Dog has a breed and the information on its image, which initially does not exist (nil).

struct Dog: Identifiable {
let id = UUID()
let breed: String
var imageInfos: String?

init(_ breed: String) {
self.breed = breed
}
}

Our view will show an array of dogs:

@State private var dogs: [Dog] = ["malamute", "chow", "husky", "samoyed"].map(Dog.init)

Now we change our function that fetches the image of a dog: it takes a Dog as a parameter, and returns (when it has finished) a Dog (with imageInfos filled) :

func updateImageOf(dog: Dog) async -> Dog {
var newDog = dog
guard let url = URL(string: "https://dog.ceo/api/breed/\(dog.breed)/images/random"),
let (data, response) = try? await URLSession.shared.data(from: url),
(response as? HTTPURLResponse)?.statusCode == 200 else { return dog }
newDog.imageInfos = String(data: data, encoding: .utf8)
return newDog
}

We create a second function that does the same for several dogs.

func updateImagesOf(favoriteDogs: [Dog]) async -> [Dog] {
var results: [Dog] = []
await withTaskGroup(of: Dog.self) { group in
for dog in favoriteDogs {
group.async {
await self.updateImageOf(dog: dog)
}
}
for await result in group {
results.append(result)
}
}
return results
}

We use this function in our View:

struct MainView: View {
var dm = DogManager()

@State private var dogs: [Dog] = ["malamute", "chow", "husky", "samoyed"].map(Dog.init)

var body: some View {
List(dogs) { dog in
HStack {
Text(dog.breed)
.padding(.trailing, 40)
Text(dog.imageInfos ?? "rien")
}
}
.task {
await dogs = dm.updateImagesOf(favoriteDogs: dogs)
}
}
}

It works (Simulator, Xcode 13 beta2)

Swift - unexpected non-void return value in void function

You are missing return type in your method header.

func calculateDistance(location: CLLocation) -> CLLocationDistance {

Seemingly my answer looks as an inferior duplicate, so some addition.

Functions (including methods, in this case) declared without return types are called as void function, because:

func f() {
//...
}

is equivalent to:

func f() -> Void {
//...
}

Usually, you cannot return any value from such void functions.
But, in Swift, you can return only one value (I'm not sure it can be called as "value"), "void value" represented by ().

func f() {
//...
return () //<- No error here.
}

Now, you can understand the meaning of the error message:

unexpected non-void return value in void function

You need to change the return value or else change the return type Void to some other type.



Related Topics



Leave a reply



Submit