简体   繁体   English

API 中下一页的工作按钮调用 SwiftUI

[英]Working button for next page in API call SwiftUI

In my app I'm trying to get this next button to keep getting new pages.在我的应用程序中,我试图获取下一个按钮以继续获取新页面。 When i press next 501 loads and when I press prev 499 loads.当我按下下一个 501 加载时,当我按下上一个 499 加载时。 I'm understanding that it's because comicNumber is set to 500, but having troubles with how I can make it keep going (502,503 etc).我知道这是因为comicNumber 设置为500,但是我无法让它继续运行(502,503 等)。

This is my api call这是我的 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()
    
    }
}

And this is my View这是我的观点

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")")
            }
        }
    }
}

I tried so the comicNumber gets + 1 or - 1 when you press next or prev buttons我试过这样当你按下下一个或上一个按钮时,comicNumber 会得到 + 1 或 - 1

 ApiCall(comicNumber: comicNumber + 1).getNextComic{ 

I also tried with + 1 inside the api but its just the same.我也尝试在 api 中使用 + 1,但它是一样的。

guard let url = URL(string: "https://xkcd.com/\(comicNumber + 1)/info.0.json") else {return}

Does anyone have any guidance on how I could get this to work or what I'm doing wrong?有没有人对我如何让它工作或我做错了什么有任何指导? I'm learning Swift and would really appreciate some help<3我正在学习 Swift,非常感谢您的帮助<3

comicNumber is being stored in too many places. comicNumber存储在太多地方。 In SwiftUI we try to keep a "single source of truth".在 SwiftUI 中,我们尝试保持“单一事实来源”。 Keep an instance of ApiCall() as a member of your view so that comicNumber stays updated: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")")
            }
        }
    }
}

And handle the updating of comicNumber within the view model ( ApiCall ):并在 model ( ApiCall ) 视图中处理comicNumber的更新:

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)
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM