在 SwiftUI 中推送空查询后,如何使警报而不是永恒的 ProgressView 出现?
How to make alert instead of eternal ProgressView appear after pushing an empty query in SwiftUI?
我正在尝试制作一个应用程序,允许您通过提供用户的登录名来查看用户的回购列表,但我遇到了一个相当大的错误,我不知道如何摆脱它。
如何让bug出现?
- 通过在 TextField 中键入正确的用户登录名(例如 jacobtoye)从初始视图前进到 ListView
- 删除 ListView 中 TextField 的内容,然后按“查看 repos”
- 至少我当时没有收到错误警报,而是一个永恒的 ProgressView()
如何使从 ListView 推送的空查询显示“无效用户名错误”警报而不是 Eternal ProgressView()?
代码:
CONTENTVIEW 文件:
import SwiftUI
struct ContentView: View {
@StateObject var viewModel = ContentViewModel()
var body: some View {
if viewModel.repos.isEmpty {
//Initial View code here
NavigationView{
VStack(alignment: .leading){
HStack{
TextField("Enter GitHub username", text: $viewModel.userName)
Button("View repos") {
viewModel.fetchRepos()
}
.alert("This user doesn't own any repositories", isPresented: $viewModel.showingSecondAlert){
Button("Try again", action: viewModel.flushRepos)
}
.padding()
}
.alert("Invalid GitHub username", isPresented: $viewModel.showingMainAlert){
Button("Try again", action: viewModel.flushRepos)
}
.navigationTitle("GH Repo Language")
Spacer()
}
}
}
else if viewModel.reposAreLoading {
ProgressView()
} else {
//ListView code here
NavigationView{
VStack{
HStack{
TextField("Enter GitHub username", text: $viewModel.userName)
Button("View repos") {
viewModel.fetchRepos()
}
.alert("This user doesn't own any repositories", isPresented: $viewModel.showingSecondAlert){
Button("Try again", action: viewModel.flushRepos)
}
.padding()
}
.alert("Invalid GitHub username", isPresented: $viewModel.showingMainAlert){
Button("Try again", action: viewModel.flushRepos)
}
List {
ForEach(viewModel.repos) { repo in
VStack {
Text("\(repo.fullName)")
}
}
}
}
}
.navigationTitle("\(viewModel.repos.first?.owner.login ?? "no name")'s repos")
}
}
}
CONTENTVIEW 模型:
import Foundation
final class ContentViewModel: ObservableObject {
@Published var repos = [Repository]()
@Published var reposAreLoading = false
@Published var userName = ""
@Published var showingMainAlert = false
@Published var showingSecondAlert = false
func fetchRepos() {
reposAreLoading = true
guard let url = URL(string: "https://api.github.com/users/\(userName)/repos") else { return }
URLSession.shared.dataTask(with: url) {(data, _, _) in
guard let data = data else { return }
DispatchQueue.main.async {
do {
self.repos = try JSONDecoder().decode([Repository].self, from: data)
self.reposAreLoading = false
if self.repos.isEmpty {
self.showingSecondAlert = true
}
} catch {
self.showingMainAlert = true
}
}
}.resume()
}
func flushRepos() {
self.repos = [Repository]()
}
}
JSON 结构:
import Foundation
struct Repository: Decodable, Identifiable {
let id: Int
let name: String
let fullName: String
let owner: Owner
enum CodingKeys: String, CodingKey {
case id, owner
case name
case fullName = "full_name"
}
}
struct Owner : Decodable, Identifiable {
let id: Int
let login: String
let reposUrl : String
enum CodingKeys: String, CodingKey, CaseIterable {
case id
case login
case reposUrl = "repos_url"
}
}
对我来说,似乎 Xcode 在从 ListView 推送一个空查询后无法实现 fetchRepos() 函数,但我不知道如何找出要解决的问题。请帮忙。
现在,您不测试 URL 响应中的错误代码。无效的用户名 returns 和 404
,因此您需要检查一下(请注意,您还可以在尝试之前检查 空 用户名获取结果)。
URLSession.shared.dataTask(with: url) {(data, response, error) in
DispatchQueue.main.async {
self.reposAreLoading = false
// may want to check `error` here, too
if let response = response as? HTTPURLResponse, response.statusCode == 404 {
self.showingMainAlert = true
return
}
//consider handling other error codes?
guard let data = data else { return }
do {
self.repos = try JSONDecoder().decode([Repository].self, from: data)
if self.repos.isEmpty {
self.showingSecondAlert = true
}
} catch {
self.showingMainAlert = true
}
}
}.resume()
查看内联评论以了解其他一些注释
还可能值得注意的是,您可以使用 async/await
对其进行现代化改造,这将简化您的代码。参见 https://www.hackingwithswift.com/books/ios-swiftui/sending-and-receiving-codable-data-with-urlsession-and-swiftui
我正在尝试制作一个应用程序,允许您通过提供用户的登录名来查看用户的回购列表,但我遇到了一个相当大的错误,我不知道如何摆脱它。
如何让bug出现?
- 通过在 TextField 中键入正确的用户登录名(例如 jacobtoye)从初始视图前进到 ListView
- 删除 ListView 中 TextField 的内容,然后按“查看 repos”
- 至少我当时没有收到错误警报,而是一个永恒的 ProgressView()
如何使从 ListView 推送的空查询显示“无效用户名错误”警报而不是 Eternal ProgressView()?
代码:
CONTENTVIEW 文件:
import SwiftUI
struct ContentView: View {
@StateObject var viewModel = ContentViewModel()
var body: some View {
if viewModel.repos.isEmpty {
//Initial View code here
NavigationView{
VStack(alignment: .leading){
HStack{
TextField("Enter GitHub username", text: $viewModel.userName)
Button("View repos") {
viewModel.fetchRepos()
}
.alert("This user doesn't own any repositories", isPresented: $viewModel.showingSecondAlert){
Button("Try again", action: viewModel.flushRepos)
}
.padding()
}
.alert("Invalid GitHub username", isPresented: $viewModel.showingMainAlert){
Button("Try again", action: viewModel.flushRepos)
}
.navigationTitle("GH Repo Language")
Spacer()
}
}
}
else if viewModel.reposAreLoading {
ProgressView()
} else {
//ListView code here
NavigationView{
VStack{
HStack{
TextField("Enter GitHub username", text: $viewModel.userName)
Button("View repos") {
viewModel.fetchRepos()
}
.alert("This user doesn't own any repositories", isPresented: $viewModel.showingSecondAlert){
Button("Try again", action: viewModel.flushRepos)
}
.padding()
}
.alert("Invalid GitHub username", isPresented: $viewModel.showingMainAlert){
Button("Try again", action: viewModel.flushRepos)
}
List {
ForEach(viewModel.repos) { repo in
VStack {
Text("\(repo.fullName)")
}
}
}
}
}
.navigationTitle("\(viewModel.repos.first?.owner.login ?? "no name")'s repos")
}
}
}
CONTENTVIEW 模型:
import Foundation
final class ContentViewModel: ObservableObject {
@Published var repos = [Repository]()
@Published var reposAreLoading = false
@Published var userName = ""
@Published var showingMainAlert = false
@Published var showingSecondAlert = false
func fetchRepos() {
reposAreLoading = true
guard let url = URL(string: "https://api.github.com/users/\(userName)/repos") else { return }
URLSession.shared.dataTask(with: url) {(data, _, _) in
guard let data = data else { return }
DispatchQueue.main.async {
do {
self.repos = try JSONDecoder().decode([Repository].self, from: data)
self.reposAreLoading = false
if self.repos.isEmpty {
self.showingSecondAlert = true
}
} catch {
self.showingMainAlert = true
}
}
}.resume()
}
func flushRepos() {
self.repos = [Repository]()
}
}
JSON 结构:
import Foundation
struct Repository: Decodable, Identifiable {
let id: Int
let name: String
let fullName: String
let owner: Owner
enum CodingKeys: String, CodingKey {
case id, owner
case name
case fullName = "full_name"
}
}
struct Owner : Decodable, Identifiable {
let id: Int
let login: String
let reposUrl : String
enum CodingKeys: String, CodingKey, CaseIterable {
case id
case login
case reposUrl = "repos_url"
}
}
对我来说,似乎 Xcode 在从 ListView 推送一个空查询后无法实现 fetchRepos() 函数,但我不知道如何找出要解决的问题。请帮忙。
现在,您不测试 URL 响应中的错误代码。无效的用户名 returns 和 404
,因此您需要检查一下(请注意,您还可以在尝试之前检查 空 用户名获取结果)。
URLSession.shared.dataTask(with: url) {(data, response, error) in
DispatchQueue.main.async {
self.reposAreLoading = false
// may want to check `error` here, too
if let response = response as? HTTPURLResponse, response.statusCode == 404 {
self.showingMainAlert = true
return
}
//consider handling other error codes?
guard let data = data else { return }
do {
self.repos = try JSONDecoder().decode([Repository].self, from: data)
if self.repos.isEmpty {
self.showingSecondAlert = true
}
} catch {
self.showingMainAlert = true
}
}
}.resume()
查看内联评论以了解其他一些注释
还可能值得注意的是,您可以使用 async/await
对其进行现代化改造,这将简化您的代码。参见 https://www.hackingwithswift.com/books/ios-swiftui/sending-and-receiving-codable-data-with-urlsession-and-swiftui