API 调用 SwiftUI 中下一页的工作按钮
Working button for next page in API call SwiftUI
在我的应用程序中,我正在尝试获取此下一个按钮以继续获取新页面。当我按下下一个 501 负载时,当我按下前一个 499 负载时。我知道这是因为 comicNumber 设置为 500,但我无法让它继续运行(502,503 等)。
这是我的api电话
struct Comic: Codable {
var month: String
var num: Int
var link: String
var year: String
var news: String
var safe_title: String
var transcript: String
var alt: String
var img: String
var title: String
var day: String
}
enum ApiError: Error {
case dataIsNil
}
class ApiCall {
var comicNumber: Int
init(comicNumber: Int) {
self.comicNumber = comicNumber
}
func getComic(completion: @escaping (Result<Comic, Error>) -> ()) {
guard let url = URL(string: "https://xkcd.com/\(comicNumber)/info.0.json") else {return}
URLSession.shared.dataTask(with: url) { data, _, error in
if let error = error {
print(error)
completion(.failure(error))
return
}
guard let data = data else {
print("data is nil")
completion(.failure(ApiError.dataIsNil))
return
}
do {
let comic = try JSONDecoder().decode(Comic.self, from: data)
// print(comic)
DispatchQueue.main.async {
completion(.success(comic))
}
} catch {
print(error)
completion(.failure(error))
}
}
.resume()
}
func getNextComic(completion: @escaping (Result<Comic, Error>) -> ()) {
guard let url = URL(string: "https://xkcd.com/\(comicNumber)/info.0.json") else {return}
URLSession.shared.dataTask(with: url) { data, _, error in
if let error = error {
print(error)
completion(.failure(error))
return
}
guard let data = data else {
print("data is nil")
completion(.failure(ApiError.dataIsNil))
return
}
do {
let comic = try JSONDecoder().decode(Comic.self, from: data)
DispatchQueue.main.async {
completion(.success(comic))
}
} catch {
print(error)
completion(.failure(error))
}
}
.resume()
}
func getPrevComic(completion: @escaping (Result<Comic, Error>) -> ()) {
guard let url = URL(string: "https://xkcd.com/\(comicNumber)/info.0.json") else {return}
URLSession.shared.dataTask(with: url) { data, _, error in
if let error = error {
print(error)
completion(.failure(error))
return
}
guard let data = data else {
print("data is nil")
completion(.failure(ApiError.dataIsNil))
return
}
do {
let comic = try JSONDecoder().decode(Comic.self, from: data)
DispatchQueue.main.async {
completion(.success(comic))
}
} catch {
print(error)
completion(.failure(error))
}
}
.resume()
}
}
这是我的观点
struct ComicContainer: View {
@State var comic: Comic?
@State var comicNumber = 500
var body: some View {
ZStack {
VStack {
NavigationLink(destination: ComicDetailView(), label: {
AsyncImage(url: URL(string: comic?.img ?? "Hello")) { image in
image
.resizable()
.scaledToFit()
} placeholder: {
Color.purple.opacity(0.1)
}
.padding()
})
.onAppear {
ApiCall(comicNumber: comicNumber).getComic{ result in
switch result {
case .success(let comic):
self.comic = comic
case .failure(let error):
print(error)
}
}
}
.toolbar {
ToolbarItemGroup(placement: .bottomBar) {
CustomButton {
ApiCall(comicNumber: comicNumber - 1).getPrevComic{ result in
switch result {
case .success(let comic):
self.comic = comic
print(comic.num)
case .failure(let error):
print(error)
}
}
} content: {
Text("Prev")
}
Spacer()
Text("Comic num: \(comic?.num ?? 0)")
.padding()
Spacer()
CustomButton {
ApiCall(comicNumber: comicNumber + 1).getNextComic{ result in
switch result {
case .success(let comic):
self.comic = comic
print(comic.num)
case .failure(let error):
print(error)
}
}
} content: {
Text("Next")
}
}
}
.navigationBarTitle("\(comic?.title ?? "title")")
}
}
}
}
我试过当你按下一个或一个按钮时 comicNumber 得到 + 1 或 - 1
ApiCall(comicNumber: comicNumber + 1).getNextComic{
我也试过在 api 中加上 + 1 但还是一样。
guard let url = URL(string: "https://xkcd.com/\(comicNumber + 1)/info.0.json") else {return}
有没有人对我如何让它工作或我做错了什么有任何指导?我正在学习 Swift,非常感谢您的帮助<3
comicNumber
存储在太多地方。在 SwiftUI 中,我们试图保持“单一的事实来源”。将 ApiCall() 的实例保留为您的视图的成员,以便 comicNumber 保持更新:
struct ComicContainer: View {
@State var comic: Comic?
var api = ApiCall(comicNumber: 500)
var body: some View {
ZStack {
VStack {
NavigationLink(destination: ComicDetailView(), label: {
AsyncImage(url: URL(string: comic?.img ?? "Hello")) { image in
image
.resizable()
.scaledToFit()
} placeholder: {
Color.purple.opacity(0.1)
}
.padding()
})
.onAppear {
apiCall.getComic{ result in
switch result {
case .success(let comic):
self.comic = comic
case .failure(let error):
print(error)
}
}
}
.toolbar {
ToolbarItemGroup(placement: .bottomBar) {
CustomButton {
apiCall.getPrevComic{ result in
switch result {
case .success(let comic):
self.comic = comic
print(comic.num)
case .failure(let error):
print(error)
}
}
} content: {
Text("Prev")
}
Spacer()
Text("Comic num: \(comic?.num ?? 0)")
.padding()
Spacer()
CustomButton {
apiCall.getNextComic{ result in
switch result {
case .success(let comic):
self.comic = comic
print(comic.num)
case .failure(let error):
print(error)
}
}
} content: {
Text("Next")
}
}
}
.navigationBarTitle("\(comic?.title ?? "title")")
}
}
}
}
并在视图模型中处理 comicNumber 的更新 (ApiCall
):
class ApiCall {
var comicNumber: Int
init(comicNumber: Int) {
self.comicNumber = comicNumber
}
func getComic(completion: @escaping (Result<Comic, Error>) -> ()) {
guard let url = URL(string: "https://xkcd.com/\(comicNumber)/info.0.json") else {return}
URLSession.shared.dataTask(with: url) { data, _, error in
if let error = error {
print(error)
completion(.failure(error))
return
}
guard let data = data else {
print("data is nil")
completion(.failure(ApiError.dataIsNil))
return
}
do {
let comic = try JSONDecoder().decode(Comic.self, from: data)
// print(comic)
DispatchQueue.main.async {
completion(.success(comic))
}
} catch {
print(error)
completion(.failure(error))
}
}
.resume()
}
func getNextComic(completion: @escaping (Result<Comic, Error>) -> ()) {
// this
comicNumber += 1
getComic(completion: completion)
}
func getPrevComic(completion: @escaping (Result<Comic, Error>) -> ()) {
// this
comicNumber -= 1
getComic(completion: completion)
}
}
在我的应用程序中,我正在尝试获取此下一个按钮以继续获取新页面。当我按下下一个 501 负载时,当我按下前一个 499 负载时。我知道这是因为 comicNumber 设置为 500,但我无法让它继续运行(502,503 等)。
这是我的api电话
struct Comic: Codable {
var month: String
var num: Int
var link: String
var year: String
var news: String
var safe_title: String
var transcript: String
var alt: String
var img: String
var title: String
var day: String
}
enum ApiError: Error {
case dataIsNil
}
class ApiCall {
var comicNumber: Int
init(comicNumber: Int) {
self.comicNumber = comicNumber
}
func getComic(completion: @escaping (Result<Comic, Error>) -> ()) {
guard let url = URL(string: "https://xkcd.com/\(comicNumber)/info.0.json") else {return}
URLSession.shared.dataTask(with: url) { data, _, error in
if let error = error {
print(error)
completion(.failure(error))
return
}
guard let data = data else {
print("data is nil")
completion(.failure(ApiError.dataIsNil))
return
}
do {
let comic = try JSONDecoder().decode(Comic.self, from: data)
// print(comic)
DispatchQueue.main.async {
completion(.success(comic))
}
} catch {
print(error)
completion(.failure(error))
}
}
.resume()
}
func getNextComic(completion: @escaping (Result<Comic, Error>) -> ()) {
guard let url = URL(string: "https://xkcd.com/\(comicNumber)/info.0.json") else {return}
URLSession.shared.dataTask(with: url) { data, _, error in
if let error = error {
print(error)
completion(.failure(error))
return
}
guard let data = data else {
print("data is nil")
completion(.failure(ApiError.dataIsNil))
return
}
do {
let comic = try JSONDecoder().decode(Comic.self, from: data)
DispatchQueue.main.async {
completion(.success(comic))
}
} catch {
print(error)
completion(.failure(error))
}
}
.resume()
}
func getPrevComic(completion: @escaping (Result<Comic, Error>) -> ()) {
guard let url = URL(string: "https://xkcd.com/\(comicNumber)/info.0.json") else {return}
URLSession.shared.dataTask(with: url) { data, _, error in
if let error = error {
print(error)
completion(.failure(error))
return
}
guard let data = data else {
print("data is nil")
completion(.failure(ApiError.dataIsNil))
return
}
do {
let comic = try JSONDecoder().decode(Comic.self, from: data)
DispatchQueue.main.async {
completion(.success(comic))
}
} catch {
print(error)
completion(.failure(error))
}
}
.resume()
}
}
这是我的观点
struct ComicContainer: View {
@State var comic: Comic?
@State var comicNumber = 500
var body: some View {
ZStack {
VStack {
NavigationLink(destination: ComicDetailView(), label: {
AsyncImage(url: URL(string: comic?.img ?? "Hello")) { image in
image
.resizable()
.scaledToFit()
} placeholder: {
Color.purple.opacity(0.1)
}
.padding()
})
.onAppear {
ApiCall(comicNumber: comicNumber).getComic{ result in
switch result {
case .success(let comic):
self.comic = comic
case .failure(let error):
print(error)
}
}
}
.toolbar {
ToolbarItemGroup(placement: .bottomBar) {
CustomButton {
ApiCall(comicNumber: comicNumber - 1).getPrevComic{ result in
switch result {
case .success(let comic):
self.comic = comic
print(comic.num)
case .failure(let error):
print(error)
}
}
} content: {
Text("Prev")
}
Spacer()
Text("Comic num: \(comic?.num ?? 0)")
.padding()
Spacer()
CustomButton {
ApiCall(comicNumber: comicNumber + 1).getNextComic{ result in
switch result {
case .success(let comic):
self.comic = comic
print(comic.num)
case .failure(let error):
print(error)
}
}
} content: {
Text("Next")
}
}
}
.navigationBarTitle("\(comic?.title ?? "title")")
}
}
}
}
我试过当你按下一个或一个按钮时 comicNumber 得到 + 1 或 - 1
ApiCall(comicNumber: comicNumber + 1).getNextComic{
我也试过在 api 中加上 + 1 但还是一样。
guard let url = URL(string: "https://xkcd.com/\(comicNumber + 1)/info.0.json") else {return}
有没有人对我如何让它工作或我做错了什么有任何指导?我正在学习 Swift,非常感谢您的帮助<3
comicNumber
存储在太多地方。在 SwiftUI 中,我们试图保持“单一的事实来源”。将 ApiCall() 的实例保留为您的视图的成员,以便 comicNumber 保持更新:
struct ComicContainer: View {
@State var comic: Comic?
var api = ApiCall(comicNumber: 500)
var body: some View {
ZStack {
VStack {
NavigationLink(destination: ComicDetailView(), label: {
AsyncImage(url: URL(string: comic?.img ?? "Hello")) { image in
image
.resizable()
.scaledToFit()
} placeholder: {
Color.purple.opacity(0.1)
}
.padding()
})
.onAppear {
apiCall.getComic{ result in
switch result {
case .success(let comic):
self.comic = comic
case .failure(let error):
print(error)
}
}
}
.toolbar {
ToolbarItemGroup(placement: .bottomBar) {
CustomButton {
apiCall.getPrevComic{ result in
switch result {
case .success(let comic):
self.comic = comic
print(comic.num)
case .failure(let error):
print(error)
}
}
} content: {
Text("Prev")
}
Spacer()
Text("Comic num: \(comic?.num ?? 0)")
.padding()
Spacer()
CustomButton {
apiCall.getNextComic{ result in
switch result {
case .success(let comic):
self.comic = comic
print(comic.num)
case .failure(let error):
print(error)
}
}
} content: {
Text("Next")
}
}
}
.navigationBarTitle("\(comic?.title ?? "title")")
}
}
}
}
并在视图模型中处理 comicNumber 的更新 (ApiCall
):
class ApiCall {
var comicNumber: Int
init(comicNumber: Int) {
self.comicNumber = comicNumber
}
func getComic(completion: @escaping (Result<Comic, Error>) -> ()) {
guard let url = URL(string: "https://xkcd.com/\(comicNumber)/info.0.json") else {return}
URLSession.shared.dataTask(with: url) { data, _, error in
if let error = error {
print(error)
completion(.failure(error))
return
}
guard let data = data else {
print("data is nil")
completion(.failure(ApiError.dataIsNil))
return
}
do {
let comic = try JSONDecoder().decode(Comic.self, from: data)
// print(comic)
DispatchQueue.main.async {
completion(.success(comic))
}
} catch {
print(error)
completion(.failure(error))
}
}
.resume()
}
func getNextComic(completion: @escaping (Result<Comic, Error>) -> ()) {
// this
comicNumber += 1
getComic(completion: completion)
}
func getPrevComic(completion: @escaping (Result<Comic, Error>) -> ()) {
// this
comicNumber -= 1
getComic(completion: completion)
}
}