Ios Swift-在单独的文件中使用函数中的多线程
我试图在Swift中使用多线程来检索和显示视图控制器中的图像。但是,我用于检索图像的函数位于单独的模型中。我可以将该函数复制并粘贴到视图控制器中,但我将多次重用该函数,并希望将其与特定的视图控制器分开 我目前拥有的函数(同样,在我命名为WikimediaAPI的单独文件中)如下所示:Ios Swift-在单独的文件中使用函数中的多线程,ios,swift,multithreading,Ios,Swift,Multithreading,我试图在Swift中使用多线程来检索和显示视图控制器中的图像。但是,我用于检索图像的函数位于单独的模型中。我可以将该函数复制并粘贴到视图控制器中,但我将多次重用该函数,并希望将其与特定的视图控制器分开 我目前拥有的函数(同样,在我命名为WikimediaAPI的单独文件中)如下所示: public func getThumbnailImage(forPage page: String) -> UIImage? { if let data = try? Data(conten
public func getThumbnailImage(forPage page: String) -> UIImage? {
if let data = try? Data(contentsOf: URL(string: "https://en.wikipedia.org/w/api.php?action=query&titles=" + page + "&prop=pageimages&format=json&pithumbsize=1000")!) {
let json = JSON(data: data)
if let pageId = json["query"]["pages"].dictionary?.first?.key {
if let imageUrl = json["query"]["pages"][pageId]["thumbnail"]["source"].string {
if let url = URL(string: imageUrl) {
if let imageData = try? Data(contentsOf: url) {
if let image = UIImage(data: imageData) {
return image
}
}
}
}
}
}
return nil
}
上面的方法可以工作,但不是多线程的,当我从表视图控制器切换到视图控制器时,需要的时间太长。我尝试在这些方面实现多线程,但不允许在异步块中返回任何内容
public func getThumbnailImage(forPage page: String) -> UIImage? {
DispatchQueue.global().async {
if let data = try? Data(contentsOf: URL(string: "https://en.wikipedia.org/w/api.php?action=query&titles=" + page + "&prop=pageimages&format=json&pithumbsize=1000")!) {
DispatchQueue.main.async {
let json = JSON(data: data)
if let pageId = json["query"]["pages"].dictionary?.first?.key {
if let imageUrl = json["query"]["pages"][pageId]["thumbnail"]["source"].string {
if let url = URL(string: imageUrl) {
DispatchQueue.global().async {
if let imageData = try? Data(contentsOf: url) {
DispatchQueue.main.async {
if let image = UIImage(data: imageData) {
return image //error: "Unexpected non-void return value in void function"
}
}
}
}
}
}
}
}
}
}
return nil
}
我曾经认为,可以使用异步代码块而不是UIImage返回闭包,但不确定如何实现这一点。如果我这样做了,我仍然需要在视图控制器中设置图像,我不知道该怎么做
以下是对视图控制器中函数的调用:
let wikiQuery = WikimediaAPI() // the class from above
fileprivate func setImage() {
if let pageTitle = wikimediaPageTitleDict[(allergy.0).lowercased()] {
if let image = wikiQuery.getThumbnailImage(forPage: pageTitle) {
wikipediaImage.image = image
wikipediaImage.contentMode = .scaleAspectFit
}
}
}
我正在使用plist中的一个字典(wikimediaPageTitleDict)将一个字符串与右边的wikipedia页面相关联(allergy.0就是这个字符串)
谢谢你的帮助。谢谢大家! 如果使用异步代码,则无法从函数返回结果。异步不是这样工作的。异步函数调用将结果排队等待稍后获取。然后,该函数在结果可用之前返回 使用异步函数通常要传入一个完成块,当结果可用时调用该块。例如,您可以传入一个闭包,将新下载的映像安装到视图控制器中相应的映像视图中 请看我在这条线上的答案
我给出了一个使用完成处理程序的异步函数的工作示例。在分派异步闭包中不能返回任何内容。 但是,您可以将UIImageView变量传递给
getThumbnailImage
当您收到图像时,
你可以马上设置
public func getThumbnailImage(forPage page: String, imageView : UIImageView)
{
...
...
if let imageData = try? Data(contentsOf: url) {
DispatchQueue.main.async {
if let image = UIImage(data: imageData) {
imageView.image = image
}
}
}
}
和都为您执行此操作,它们扩展了UIImageView,因此您只需在图像视图上调用一个方法,当图像下载(或从缓存中检索)时,图像视图就会更新。我建议你用图书馆来做这个。但如果你想自己动手(注意守卫们要消灭厄运金字塔):
另外,上面的JSON引用了SwiftyJSON(),只是一个提示,如果让你的
进入相同的条件,你可以将你的链接到相同的条件中,以避免死亡金字塔。好的一点,我忘记了Alamofire内置了异步映像加载。这是迄今为止最简单、最好的答案,您已经在使用AlamoFireTanks了!我最终使用了Alamofire,但演示代码确实有助于我理解正常情况下应该如何操作。另外,我还欣赏防护结构,没有意识到我可以做到这一点,但看起来更干净
typealias ImageCallback = (UIImage?) -> Void
func getThumbnailImage(forPage page: String, completion: @escaping ImageCallback) -> void {
DispatchQueue.global().async {
var imageToReturn: UIImage? = nil
defer {
completion(imageToReturn)
}
guard let data = try? Data(contentsOf: URL(string: "https://en.wikipedia.org/w/api.php?action=query&titles=" + page + "&prop=pageimages&format=json&pithumbsize=1000")!) else {
return
}
let json = JSON(data: data)
guard let pageId = json["query"]["pages"].dictionary?.first?.key,
let imageUrl = json["query"]["pages"][pageId]["thumbnail"]["source"].string,
let url = URL(string: imageUrl) else {
return
}
guard let imageData = try? Data(contentsOf: url),
let image = UIImage(data: imageData) else {
return
}
imageToReturn = image
}
}
getThumbnailImage(forPage: "Escherichia_coli") { image in
DispatchQueue.main.async {
imageView.image = image
}
}