'Unexpected non-void return value in void function' 在 swiftui 中
'Unexpected non-void return value in void function' in swiftui
基本上,我在 API 调用中 return 以字符串形式输入 url 时遇到问题。
我正在尝试通过一个采用 'breed' 参数调用其端点的大函数来实现抽象。这样我就避免了多次编写完全相同的函数。函数 getMamalute()、getGolden() 等都传入此参数以获取 URL,以便我可以将其作为图像显示在我的视图中——您可能已经知道了。但是我在 'getFavoriteDoggo' 函数的 return 行收到以下错误 'Unexpected non-void return value in void function'。我需要使用完成处理程序吗?如果是这样,那会是什么样子?
@Published var mamaluteImg = ""
@Published var goldenImg = ""
@Published var samoyedImg = ""
@Published var chowImg = ""
@Published var huskyImg = ""
func getMamalute() -> String{
return getFavoriteDoggo(breed: "malamute")
}
func getChowChow() -> String{
return getFavoriteDoggo(breed: "chow")
}
func getHusky() -> String{
return getFavoriteDoggo(breed: "husky")
}
func getSamoyed() -> String{
return getFavoriteDoggo(breed: "samoyed")
}
func getGoldenRetriever() -> String{
return getFavoriteDoggo(breed: "retriever/golden")
}
func getFavoriteDoggo(breed: String) -> String{
guard let url = URL(string: "https://dog.ceo/api/breed/\(breed)/images/random") else {
print("Trouble parsing url")
return ""
}
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request){ data, response, error in
if error != nil {
print((error?.localizedDescription)!)
return
}
if let data = data {
let response = try! JSON(data: data)
// let randoIndex = Int.random(in: 0...(response.count - 1))
let img = response["message"]
// print(img)
// DispatchQueue.main.async {
// self.mamaluteImg = img.string!
// }
return img.string
}
}.resume()
}
希望我清楚地解释了我的问题,如果不是我的道歉,我的大脑 运行 电池电量真的很低,所以我很乐意在下面帮助澄清:)
再次感谢!
您正在使用异步方法 (dataTask
)。你不知道什么时候完成运行(网络请求)。因此它不能有 return 值。完成后执行闭包 (URLSession.shared.dataTask (with: request) {// this block}
).
你肯定会喜欢这样:
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")
您可以在 Playground 中进行测试。
现在,如果您想使用 SwiftUI
并且在 imageInfos
更改时重绘您的视图,您必须将 class 更改为 ObservableObject
:
class DogManager: ObservableObject {
@Published var imageInfos: String?
//....//
}
并像这样使用它:
struct MainView: View {
@StateObject private var dm = DogManager()
var body: some View {
Text(dm.imageInfos ?? "nothing")
.onAppear {
dm.getFavoriteDoggo(breed: "retriever/golden")
}
}
}
iOS15 :
请注意,随着 async
/ await
(iOS15) 的引入,您可以编写具有 return 值的异步方法(就像您所做的那样):
@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)
}
您可以将它与新的 .task
修饰符一起使用:
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")
}
}
}
编辑:
"Hey thank you for helping me out, but this would only work for only 1
dog breed."
首先,让我们创建一个新的 Dog
结构。 A Dog
有一个品种及其图像上的信息,最初不存在 (nil)。
struct Dog: Identifiable {
let id = UUID()
let breed: String
var imageInfos: String?
init(_ breed: String) {
self.breed = breed
}
}
我们的视图将显示一组狗:
@State private var dogs: [Dog] = ["malamute", "chow", "husky", "samoyed"].map(Dog.init)
现在我们更改获取狗图像的函数:它接受一个 Dog
作为参数,并且 returns(当它完成时)一个 Dog
( imageInfos
填充):
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
}
我们创建了第二个函数,它对几只狗执行相同的操作。
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
}
我们在 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)
}
}
}
有效(模拟器,Xcode 13 beta2)
基本上,我在 API 调用中 return 以字符串形式输入 url 时遇到问题。
我正在尝试通过一个采用 'breed' 参数调用其端点的大函数来实现抽象。这样我就避免了多次编写完全相同的函数。函数 getMamalute()、getGolden() 等都传入此参数以获取 URL,以便我可以将其作为图像显示在我的视图中——您可能已经知道了。但是我在 'getFavoriteDoggo' 函数的 return 行收到以下错误 'Unexpected non-void return value in void function'。我需要使用完成处理程序吗?如果是这样,那会是什么样子?
@Published var mamaluteImg = ""
@Published var goldenImg = ""
@Published var samoyedImg = ""
@Published var chowImg = ""
@Published var huskyImg = ""
func getMamalute() -> String{
return getFavoriteDoggo(breed: "malamute")
}
func getChowChow() -> String{
return getFavoriteDoggo(breed: "chow")
}
func getHusky() -> String{
return getFavoriteDoggo(breed: "husky")
}
func getSamoyed() -> String{
return getFavoriteDoggo(breed: "samoyed")
}
func getGoldenRetriever() -> String{
return getFavoriteDoggo(breed: "retriever/golden")
}
func getFavoriteDoggo(breed: String) -> String{
guard let url = URL(string: "https://dog.ceo/api/breed/\(breed)/images/random") else {
print("Trouble parsing url")
return ""
}
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request){ data, response, error in
if error != nil {
print((error?.localizedDescription)!)
return
}
if let data = data {
let response = try! JSON(data: data)
// let randoIndex = Int.random(in: 0...(response.count - 1))
let img = response["message"]
// print(img)
// DispatchQueue.main.async {
// self.mamaluteImg = img.string!
// }
return img.string
}
}.resume()
}
希望我清楚地解释了我的问题,如果不是我的道歉,我的大脑 运行 电池电量真的很低,所以我很乐意在下面帮助澄清:)
再次感谢!
您正在使用异步方法 (dataTask
)。你不知道什么时候完成运行(网络请求)。因此它不能有 return 值。完成后执行闭包 (URLSession.shared.dataTask (with: request) {// this block}
).
你肯定会喜欢这样:
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")
您可以在 Playground 中进行测试。
现在,如果您想使用 SwiftUI
并且在 imageInfos
更改时重绘您的视图,您必须将 class 更改为 ObservableObject
:
class DogManager: ObservableObject {
@Published var imageInfos: String?
//....//
}
并像这样使用它:
struct MainView: View {
@StateObject private var dm = DogManager()
var body: some View {
Text(dm.imageInfos ?? "nothing")
.onAppear {
dm.getFavoriteDoggo(breed: "retriever/golden")
}
}
}
iOS15 :
请注意,随着 async
/ await
(iOS15) 的引入,您可以编写具有 return 值的异步方法(就像您所做的那样):
@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)
}
您可以将它与新的 .task
修饰符一起使用:
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")
}
}
}
编辑:
"Hey thank you for helping me out, but this would only work for only 1 dog breed."
首先,让我们创建一个新的 Dog
结构。 A Dog
有一个品种及其图像上的信息,最初不存在 (nil)。
struct Dog: Identifiable {
let id = UUID()
let breed: String
var imageInfos: String?
init(_ breed: String) {
self.breed = breed
}
}
我们的视图将显示一组狗:
@State private var dogs: [Dog] = ["malamute", "chow", "husky", "samoyed"].map(Dog.init)
现在我们更改获取狗图像的函数:它接受一个 Dog
作为参数,并且 returns(当它完成时)一个 Dog
( imageInfos
填充):
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
}
我们创建了第二个函数,它对几只狗执行相同的操作。
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
}
我们在 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)
}
}
}
有效(模拟器,Xcode 13 beta2)