Я новичок в Swift и SwiftUI, может ли кто-нибудь помочь мне понять, почему, когда я пытаюсь вызвать определенное c телешоу с помощью функции fecthUserSeries, ничего не появляется?
Вот конечные точки
import UIKit
struct AppData {
static let baseUrl = "https://api.tvmaze.com"
static let search = "/search/shows"
static let show = "/show/"
static let shows = "/shows/"
static let episodes = "/episodes"
static let season = "/seasons"
static let cast = "/cast"
static let crew = "/crew"
static let placeholderUrl = "http://via.placeholder.com/350/ffffff/000000?text=Image+Not+found"
static let dateFormat = "dd MMM yyyy"
static let dateFormatApi = "yyyy-MM-dd"
}
enum AppError : Error {
case invalidFormat
}
Вот все функции:
import SwiftUI
import Combine
enum APIType {
case listSeries
case listseasons
case listEpisodes
case listCast
case listCrew
}
class APIStore: ObservableObject {
@Published var serieses: [Series] = []
@Published var seasons: [Season] = []
@Published var episodes: [Episode] = []
@Published var casts: [CastCrew] = []
@Published var crews: [CastCrew] = []
init() {
serieses = []
seasons = []
episodes = []
casts = []
crews = []
}
func fetchSeries(pageNumber: Int = 1) {
let params = [
("page", String(pageNumber))
]
ApiMapper().callAPI(withPath: AppData.show, params: params, andMappingModel: [Series].self) { [weak self] (result) in
switch(result) {
case .success(let serieses):
DispatchQueue.main.async {
self?.serieses = serieses
}
case .failure(_):
break
}
}
}
func searchSeries(searchString: String) {
let params = [
("q", searchString)
]
ApiMapper().callAPI(withPath: AppData.search, params: params, andMappingModel: [SearchResult].self) { [weak self] (result) in
switch(result) {
case .success(let searchResult):
DispatchQueue.main.async {
self?.serieses = searchResult.compactMap({$0.series})
}
case .failure(_):
break
}
}
}
func fetchSeason(with seriesID: Int) {
let path = "\(AppData.shows)\(seriesID)\(AppData.season)"
ApiMapper().callAPI(withPath: path, params: [], andMappingModel: [Season].self) { [weak self] (result) in
switch(result) {
case .success(let seasons):
DispatchQueue.main.async {
self?.seasons = seasons
}
case .failure(_):
break
}
}
}
func fetchEpisodes(with seriesID: Int) {
let path = "\(AppData.shows)\(seriesID)\(AppData.episodes)"
ApiMapper().callAPI(withPath: path, params: [], andMappingModel: [Episode].self) { [weak self] (result) in
switch(result) {
case .success(let episodes):
DispatchQueue.main.async {
self?.episodes = episodes
}
case .failure(_):
break
}
}
}
func fetchCasts(with seriesID: Int) {
let path = "\(AppData.shows)\(seriesID)\(AppData.cast)"
ApiMapper().callAPI(withPath: path, params: [], andMappingModel: [CastCrew].self) { [weak self] (result) in
switch(result) {
case .success(let casts):
DispatchQueue.main.async {
self?.casts = casts
}
case .failure(_):
break
}
}
}
func fetchCrews(with seriesID: Int) {
let path = "\(AppData.shows)\(seriesID)\(AppData.crew)"
ApiMapper().callAPI(withPath: path, params: [], andMappingModel: [CastCrew].self) { [weak self] (result) in
switch(result) {
case .success(let casts):
DispatchQueue.main.async {
self?.crews = casts
}
case .failure(_):
break
}
}
}
func fetchUserSeries(seriesID: Int) {
let path = "\(AppData.shows)\(seriesID)"
ApiMapper().callAPI(withPath: path, params: [], andMappingModel: [Series].self) { [weak self] (result) in
switch(result) {
case .success(let userSeries):
DispatchQueue.main.async {
self?.serieses = userSeries
}
case .failure(_):
print("Error")
break
}
}
}
}
import UIKit
class ApiMapper {
//MARK: Api Calls
func callAPI<T: Codable>(withPath pathString: String, params : [(String, String)], andMappingModel model: T.Type, callback: @escaping (Result<T, Error>) -> Void ) {
if let url = self.generateURL(withPath: pathString , andParams: params) {
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
do {
let jsonDecoder = JSONDecoder()
let responseModel = try jsonDecoder.decode(model, from: data!)
callback(Result.success(responseModel))
} catch {
callback(Result.failure(error))
}
}
task.resume()
} else {
callback(Result.failure(URLError(.badURL)))
}
}
//MARK: helper methods
private func generateURL(withPath path: String, andParams params: [(String, String)]) -> URL? {
guard var urlComp = URLComponents(string: AppData.baseUrl) else {return nil}
urlComp.queryItems = [URLQueryItem]()
for param in params {
urlComp.queryItems?.append(URLQueryItem(name: param.0, value: param.1))
}
guard var url = urlComp.url else {return nil}
url = url.appendingPathComponent(path)
return url
}
}
Наконец, вот где я вызываю функцию. Как видите, я вызываю шоу с index = 1 (функция fetchSeries - это отдельная функция, которая извлекает все шоу с каждой страницы базы данных)
import SDWebImageSwiftUI
struct HomeView: View {
@ObservedObject var apiStore = APIStore()
@State private var searchString = ""
@State private var pageNumber = 1
@State var selectedSeason: Int
// var seriesID: [Int] = [178, 31, 555, 1855, 263]
var seriesID: Int = 1
init(selectedSeason: Int) {
UITableView.appearance().separatorStyle = .none
_selectedSeason = State(initialValue: selectedSeason)
}
var body: some View {
NavigationView() {
VStack {
TextField("Search", text: $searchString, onEditingChanged: { status in
if !status && self.searchString != "" {
self.apiStore.searchSeries(searchString: self.searchString)
self.pageNumber = 1
} else if !status && self.searchString == "" {
self.apiStore.fetchSeries(pageNumber: self.pageNumber)
}
})
.padding(.all, 10.0)
.textFieldStyle(RoundedBorderTextFieldStyle())
List{
ForEach(self.apiStore.serieses) { series in
SeriesCell(series : self.apiStore.serieses[0], selectedSeason: self.$selectedSeason)
.onAppear {
// ForEach(self.seriesID.) { seriesID in
// if self.seriesID.contains(where: {$0 == series.id}){
// self.apiStore.fetchUserSeries(with: series.id ?? 0)
// }
self.apiStore.fetchUserSeries(with: self.seriesID)
if series.id == self.apiStore.serieses.last?.id {
self.pageNumber += 1
self.apiStore.fetchSeries(pageNumber: self.pageNumber)
}
}
}
}
.navigationBarTitle("Shows", displayMode: .inline)
.onAppear {
self.searchString == "" ? self.apiStore.fetchSeries() : self.apiStore.searchSeries(searchString: self.searchString)
// self.apiStore.fetchUserSeries()
// self.searchString == "" ? self.apiStore.fetchSeries() : self.apiStore.searchSeries(searchString: self.searchString)
}
}
}
}
}
struct SeriesCell: View {
var series: Series
@Binding var selectedSeason: Int
var body: some View {
NavigationLink(destination: DetailsView(series: series, selectedSeason: selectedSeason)) {
ZStack(alignment: .topTrailing) {
VStack(alignment: .center) {
WebImage(url: URL(string: (series.image?.original ?? "")))
.placeholder{Image(systemName: "camera")}
.resizable()
.scaledToFit()
.frame(minWidth: UIScreen.main.bounds.width - 60, minHeight:(UIScreen.main.bounds.width - 60))
HStack {
Text(String(series.name ?? ""))
.bold()
.multilineTextAlignment(.center)
.font(.title)
.padding(10)
Image(systemName: "plus")
.onTapGesture {
}
}
}
ZStack(alignment: .center) {
Image(systemName: "star.fill")
.resizable()
.scaledToFit()
.frame(width: 50, height: 50, alignment: .center)
.foregroundColor(Color.yellow)
.padding()
Text(String.localizedStringWithFormat("%.1f", series.rating?.average ?? 0))
.font(.system(size: 11))
.bold()
}
}
.background(Color.white)
.cornerRadius(6)
.shadow(radius: 5)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
let content = HomeView(selectedSeason: 1)
content.apiStore.serieses = SampleAPIResult.getDummySeries()
return content
// .previewDevice("iPhone 7")
}
}
```