为什么我的 Swift 网络请求不起作用? [英] Why aren't my Swift network requests working?

查看:56
本文介绍了为什么我的 Swift 网络请求不起作用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是第一次尝试 Swift/SwiftUI,所以我决定制作一个小型的 Hacker News 客户端.我似乎能够很好地恢复头条新闻的 id 列表,但是一旦 dispatchGroup 参与进来,什么都不起作用.我做错了什么?

I've been trying out Swift/SwiftUI for the first time, so I decided to make a small Hacker News client. I seem to be able to get the list of ids of the top stories back fine, but once the dispatchGroup gets involved, nothing works. What am I doing wrong?

Data.swift

import SwiftUI

struct HNStory: Codable, Identifiable {
    var id: UInt
    var title: String
    var score: UInt
}

class Fetch {
    func getStory(id: Int, completion: @escaping (HNStory) -> ()) {
        let url = URL(string: "https://hacker-news.firebaseio.com/v0/item/\(id).json")
        
        URLSession.shared.dataTask(with: url!) { (data, _, _) in
            let story = try!JSONDecoder().decode(HNStory.self, from: data!)
            print(id, story)
            
            DispatchQueue.main.async {
                completion(story)
            }
        }
    }
    
    func getStories(completion: @escaping ([HNStory]) -> ()) {
        let url = URL(string: "https://hacker-news.firebaseio.com/v0/topstories.json")
        var stories: [HNStory] = []
        print("here")
        
        URLSession.shared.dataTask(with: url!) { (data, _, _) in
            var ids = try!JSONDecoder().decode([Int].self, from: data!)
            
            ids = Array(ids[0...10])
            print(ids)
            
            let dispatchGroup = DispatchGroup()
            
            for id in ids {
                dispatchGroup.enter()
                self.getStory(id: id) { (story) in
                    stories.append(story)
                    dispatchGroup.leave()
                }
            }
            
            dispatchGroup.notify(queue: .main) {
                print("Completed work")
                DispatchQueue.main.async {
                    completion(stories)
                }
            }
        }.resume()
    }
}

ContentView.swift(可能无关紧要,但以防万一)

ContentView.swift (probably doesn't matter, but just in case)

import SwiftUI

struct ContentView: View {
    @State private var stories: [HNStory] = []

    var body: some View {
        Text("Hacker News").font(.headline)
        List(stories) { story in
            VStack {
                Text(story.title)
                Text(story.score.description)
            }
        }.onAppear{
            Fetch().getStories { (stories) in
                self.stories = stories
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

推荐答案

通过调用 Fetch().getStories,Fetch 类会立即超出范围并且不会保留.

By calling Fetch().getStories, the Fetch class goes out of scope immediately and isn't retained.

我建议将 Fetch 设为 ObservableObject 并将其设置为您视图上的属性:

I'd recommend making Fetch an ObservableObject and setting it as a property on your view:

@StateObject var fetcher = Fetch()

然后,调用:

fetcher.getStories {
  self.stories = stories
}

如果您想使用它获得更多 SwiftUI 风格,您可能需要查看 ObservableObject 上的 @Published 属性以及如何让您的视图做出响应自动给他们.通过这样做,您可以完全避免在您的视图中使用 @State 变量,不必有回调函​​数,而只需将故事加载到 @PublishedObservableObject 上的属性.当 @Published 属性更改时,您的视图将重新呈现.更多阅读:https://www.hackingwithswift.com/quick-start/swiftui/observable-objects-environment-objects-and-published

If you wanted to get even more SwiftUI-ish with it, you may want to look into @Published properties on ObservableObjects and how you can make your view respond to them automatically. By doing this, you could avoid having a @State variable on your view at all, not have to have a callback function, and instead just load the stories into a @Published property on the ObservableObject. Your view will be re-rendered when the @Published property changes. More reading: https://www.hackingwithswift.com/quick-start/swiftui/observable-objects-environment-objects-and-published

这篇关于为什么我的 Swift 网络请求不起作用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆