首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用Swift完成处理程序的结果?

如何使用Swift完成处理程序的结果?
EN

Stack Overflow用户
提问于 2020-11-06 02:08:00
回答 2查看 1.1K关注 0票数 2

我是斯威夫特和SwiftUI的新手。

在我的macOS SwiftUI项目中,我试图验证一个URL是否可以访问,这样我就可以有条件地呈现两个视图中的一个。一个视图加载图像URL,另一个视图在无法访问URL时显示错误图像。

这里是我的URL扩展和完成:

代码语言:javascript
运行
复制
import Foundation

extension URL {
    func isReachable(completion: @escaping (Bool) -> Void) {
        var request = URLRequest(url: self)
        request.httpMethod = "HEAD"
        request.timeoutInterval = 1.0
        
        URLSession.shared.dataTask(with: request) { data, response, error in
            if error != nil {
                DispatchQueue.main.async {
                    completion(false)
                }
                return
            }
            if let httpResp: HTTPURLResponse = response as? HTTPURLResponse {
                DispatchQueue.main.async {
                    completion(httpResp.statusCode == 200)
                }
                return
            } else {
                DispatchQueue.main.async {
                    completion(false)
                }
                return
            }
        }.resume()
    }
}

在其他地方,我试图在模型视图中使用这一点:

代码语言:javascript
运行
复制
var imageURL: URL? {
    if let url = self.book.image_url {
        return URL(string: url)
    } else {
        return nil
    }
}

var imageURLIsReachable: Bool {
    if let url = self.imageURL {
        url.isReachable { result in
            return result  // Error: Cannot convert value of type 'Bool' to closure result type 'Void'
        }
    } else {
        return false
    }
}

尽管Xcode显示了此错误:

Cannot convert value of type 'Bool' to closure result type 'Void'

我做错了什么?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-11-06 05:35:40

在阅读了这里的一些评论并做了更多的研究/实验之后,我才开始工作。我改变的是:

在URL扩展中,我将它保留下来,就像我发现它这样更易读一样。我确实将timeoutInterval推到了一个参数:

代码语言:javascript
运行
复制
// Extensions/URL.swift


import Foundation

extension URL {
    func isReachable(timeoutInterval: Double, completion: @escaping (Bool) -> Void) {
        var request = URLRequest(url: self)
        request.httpMethod = "HEAD"
        request.timeoutInterval = timeoutInterval
        
        URLSession.shared.dataTask(with: request) { data, response, error in
            if error != nil {
                DispatchQueue.main.async {
                    completion(false)
                }
                return
            }
            if let httpResp: HTTPURLResponse = response as? HTTPURLResponse {
                DispatchQueue.main.async {
                    completion(httpResp.statusCode == 200)
                }
                return
            } else {
                DispatchQueue.main.async {
                    completion(false)
                }
                return
            }
        }.resume()
    }
}

我修改了我的BookViewModel,使其中两个属性变为@Published,并在那里使用了URL扩展:

代码语言:javascript
运行
复制
// View Models/BookViewModel.swift

import Foundation

class BookViewModel: ObservableObject {
    @Published var book: Book
    @Published var imageURLIsReachable: Bool
    @Published var imageURL: URL?
    
    init(book: Book) {
        self.book = book
        self.imageURL = nil
        self.imageURLIsReachable = false
        if let url = book.image_url {
            self.imageURL = URL(string: url)
            self.imageURL!.isReachable(timeoutInterval: 1.0) { result in
                self.imageURLIsReachable = result
            }
        }
    }
    
    // Rest of properties...
}

现在,我的BookThumbnailView可以正确地显示条件视图:

代码语言:javascript
运行
复制
// Views/BookThumbnailView.swift

import SwiftUI
import Foundation
import KingfisherSwiftUI

struct BookThumbnailView: View {
    @ObservedObject var viewModel: BookViewModel
        
    private var book: Book {
        viewModel.book
    }
    
    @ViewBuilder
    var body: some View {
        if let imageURL = self.viewModel.imageURL {
            if self.viewModel.imageURLIsReachable {
                KFImage(imageURL)
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .frame(maxWidth: 70)
                        .cornerRadius(8)
            } else {
                ErrorBookThumbnailView()
            }
        } else {
            DefaultBookThumbnailView()
        }
    }
}

哇,这是很好的学习经验。感谢每一个评论和建议,并提供了提示,以寻找!

票数 1
EN

Stack Overflow用户

发布于 2020-11-06 02:19:40

正如Xcode所告诉的那样,这个问题实际上是出现在行return result中的。在创建函数func isReachable(completion: @escaping (Bool) -> Void)时,您要告诉Xcode,您将在(Bool) -> Void类型中输入一些内容,这应该类似于func someFunction(input: Bool) -> Void

但是,当您使用闭包输入完成处理程序时,您将输入一个Bool -> Bool类型的函数。删除return result行,或更改func isReachable(completion:)中的完成类型。

编辑:

实际上,我不建议在计算属性中返回异步结果,这会导致其他问题。

我会把它改为:

代码语言:javascript
运行
复制
func isReachable(completion: @esacping (Bool) -> Void) {
    ...
}

func showResultView() {
    guard let url = imageURL else { 
        // handling if the imageURL is nil
        return
    }
    url.isReachable { result in
        // do something with the result
        if result {
            // show viewController A
        } else {
            // show viewController B
        }
    }
}

// call showResultView anywhere you want, lets say you want to show it whenever the viewController appear
override func viewDidAppear() {
    ...
    showResultView()
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64707897

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档