我正在嘗試從其 ISBN 中獲取一本書的詳細資訊。這是迄今為止我所擁有的一個可重復的示例。我希望在按下按鈕時獲取資料,但是我所擁有的不起作用。我還將為下面的請求包含一個資料模型。此外,我想在它獲取資料時覆寫某種加載影片。
struct ContentView: View {
@State var name: String = ""
@State var author: String = ""
@State var total: String = ""
@State var code = "ISBN"
private func fetchBook(id identifier: String) async throws -> GoogleBook {
let url = URL(string: "https://www.googleapis.com/books/v1/volumes?q={\(identifier)}")
let (data, _) = try await URLSession.shared.data(from: url!)
return try! JSONDecoder().decode(GoogleBook.self, from: data)
}
var body: some View {
VStack {
Text("Name: \(name)")
Text("Author: \(author)")
Text("total: \(total)")
Button(action: {
code = "9780141375632"
Task {
do {
let fetchedBooks = try await fetchBook(id: code)
let book = fetchedBooks.items[0].volumeInfo
name = book.title
author = book.authors[0]
total = String(book.pageCount!)
} catch {
print(error.localizedDescription)
}
}
}, label: {
Rectangle()
.frame(width: 200, height: 100)
.foregroundColor(.blue)
})
}
}
}
import Foundation
// MARK: - GoogleBook
struct GoogleBook: Decodable {
let kind: String
let totalItems: Int
let items: [Item]
}
// MARK: - Item
struct Item: Decodable {
let kind: Kind
let id, etag: String
let selfLink: String
let volumeInfo: VolumeInfo
let saleInfo: SaleInfo
let accessInfo: AccessInfo
let searchInfo: SearchInfo
}
// MARK: - AccessInfo
struct AccessInfo: Decodable {
let country: Country
let viewability: Viewability
let embeddable, publicDomain: Bool
let textToSpeechPermission: TextToSpeechPermission
let epub, pdf: Epub
let webReaderLink: String
let accessViewStatus: AccessViewStatus
let quoteSharingAllowed: Bool
}
enum AccessViewStatus: String, Decodable {
case none = "NONE"
case sample = "SAMPLE"
}
enum Country: String, Decodable {
case countryIN = "IN"
}
// MARK: - Epub
struct Epub: Decodable {
let isAvailable: Bool
let acsTokenLink: String?
}
enum TextToSpeechPermission: String, Decodable {
case allowed = "ALLOWED"
case allowedForAccessibility = "ALLOWED_FOR_ACCESSIBILITY"
}
enum Viewability: String, Decodable {
case noPages = "NO_PAGES"
case partial = "PARTIAL"
}
enum Kind: String, Decodable {
case booksVolume = "books#volume"
}
// MARK: - SaleInfo
struct SaleInfo: Decodable {
let country: Country
let saleability: Saleability
let isEbook: Bool
let listPrice, retailPrice: SaleInfoListPrice?
let buyLink: String?
let offers: [Offer]?
}
// MARK: - SaleInfoListPrice
struct SaleInfoListPrice: Decodable {
let amount: Double
let currencyCode: CurrencyCode
}
enum CurrencyCode: String, Decodable {
case inr = "INR"
}
// MARK: - Offer
struct Offer: Decodable {
let finskyOfferType: Int
let listPrice, retailPrice: OfferListPrice
}
// MARK: - OfferListPrice
struct OfferListPrice: Decodable {
let amountInMicros: Int
let currencyCode: CurrencyCode
}
enum Saleability: String, Decodable {
case forSale = "FOR_SALE"
case notForSale = "NOT_FOR_SALE"
}
// MARK: - SearchInfo
struct SearchInfo: Decodable {
let textSnippet: String
}
// MARK: - VolumeInfo
struct VolumeInfo: Decodable {
let title: String
let authors: [String]
let publisher, publishedDate, volumeInfoDescription: String
let industryIdentifiers: [IndustryIdentifier]
let readingModes: ReadingModes
let pageCount: Int?
let printType: PrintType
let categories: [String]?
let averageRating: Double?
let ratingsCount: Int?
let maturityRating: MaturityRating
let allowAnonLogging: Bool
let contentVersion: String
let panelizationSummary: PanelizationSummary?
let imageLinks: ImageLinks
let language: Language
let previewLink: String
let infoLink: String
let canonicalVolumeLink: String
let subtitle: String?
let comicsContent: Bool?
let seriesInfo: SeriesInfo?
enum CodingKeys: String, CodingKey {
case title, authors, publisher, publishedDate
case volumeInfoDescription = "description"
case industryIdentifiers, readingModes, pageCount, printType, categories, averageRating, ratingsCount, maturityRating, allowAnonLogging, contentVersion, panelizationSummary, imageLinks, language, previewLink, infoLink, canonicalVolumeLink, subtitle, comicsContent, seriesInfo
}
}
// MARK: - ImageLinks
struct ImageLinks: Decodable {
let smallThumbnail, thumbnail: String
}
// MARK: - IndustryIdentifier
struct IndustryIdentifier: Decodable {
let type: TypeEnum
let identifier: String
}
enum TypeEnum: String, Decodable {
case isbn10 = "ISBN_10"
case isbn13 = "ISBN_13"
}
enum Language: String, Decodable {
case en = "en"
}
enum MaturityRating: String, Decodable {
case notMature = "NOT_MATURE"
}
// MARK: - PanelizationSummary
struct PanelizationSummary: Decodable {
let containsEpubBubbles, containsImageBubbles: Bool
let imageBubbleVersion: String?
}
enum PrintType: String, Decodable {
case book = "BOOK"
}
// MARK: - ReadingModes
struct ReadingModes: Decodable {
let text, image: Bool
}
// MARK: - SeriesInfo
struct SeriesInfo: Decodable {
let kind, shortSeriesBookTitle, bookDisplayNumber: String
let volumeSeries: [VolumeSery]
}
// MARK: - VolumeSery
struct VolumeSery: Decodable {
let seriesID, seriesBookType: String
let orderNumber: Int
let issue: [Issue]
enum CodingKeys: String, CodingKey {
case seriesID = "seriesId"
case seriesBookType, orderNumber, issue
}
}
// MARK: - Issue
struct Issue: Decodable {
let issueDisplayNumber: String
}
uj5u.com熱心網友回復:
有幾個問題。
- 永遠不要
try!在一個方法中throws,交出錯誤。 - 永遠不要
error.localizedDescription在解碼背景關系中列印,總是只列印error實體。 - 永遠不要強制解包由字串插值組成的 URL,失敗時拋出錯誤。
主要問題是您必須通過添加百分比編碼來對 URL 進行編碼
private func fetchBook(id identifier: String) async throws -> GoogleBook {
guard let encodedString = "https://www.googleapis.com/books/v1/volumes?q={\(identifier)}"
.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
let url = URL(string: encodedString) else { throw URLError(.badURL)}
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode(GoogleBook.self, from: data)
}
如果您遇到任何 DecodingError,錯誤訊息將準確告訴您發生的原因和位置
要顯示進度視圖,請添加一個具有@Published表示狀態的屬性的視圖模型,一個具有關聯值的列舉,例如這個通用列舉
enum LoadingState<Value> {
case loading(Double)
case loaded(Value)
}
關聯的Double值可以傳遞進度百分比。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/409131.html
標籤:
