如何让我的 iOS 应用程序连接到 api?
How can I get my iOS app connected with api?
我是 iOS 开发的初学者。我试图在求职 iOS 应用程序中使用 api URl: https://www.arbeitnow.com/api/job-board-api。但我的应用程序上没有显示任何内容。我在 POSTMAN 中测试了 URL,它 returns json(但在描述部分是 HTML?)。我写的代码:
func getResults(completed: @escaping (Result<[Results], ErrorMessage>) -> Void) {
let urlString = "https://www.arbeitnow.com/api/job-board-api"
guard let url = URL(string: urlString) else {return}
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let _ = error {
completed(.failure(.invalidData))
return
}
guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
completed(.failure(.invalidResponse))
return
}
guard let data = data else {
completed(.failure(.invalidData))
return
}
do {
let deconder = JSONDecoder()
deconder.keyDecodingStrategy = .convertFromSnakeCase
let results = try deconder.decode([Results].self, from: data)
completed(.success(results))
} catch {
completed(.failure(.invalidData))
}
}
task.resume()
}
struct Results: Codable {
let slug, companyName, title, resultsDescription: String
let remote: Bool
let url: String
let tags, jobTypes: [String]
let location: String
let createdAt: Int
enum CodingKeys: String, CodingKey {
case slug
case companyName = "company_name"
case title
case resultsDescription = "description"
case remote, url, tags
case jobTypes = "job_types"
case location
case createdAt = "created_at"
}
}
我使用了 HomeViewController 中的代码:
override func viewDidLoad() {
super.viewDidLoad()
title = "Home"
collectionView.backgroundColor = UIColor(named: "backgroundMain")
collectionView.register(SearchViewCell.self, forCellWithReuseIdentifier: cellId)
setupSearchBar()
Service.shared.getResults() { [weak self] result in
switch result {
case .success(let results):
print(results)
self?.jobResults = results
DispatchQueue.main.async {
self?.collectionView.reloadData()
}
case .failure(let error):
print(error)
}
}
}
888
我不知道我的代码有什么问题。谁能帮忙?谢谢!
您正在丢弃所有有意义的错误信息,这将使诊断变得困难。如果你得到一个 Error
对象,你应该 return 那:
enum WebServiceError: Error {
case httpError(Data, Int)
}
func getResults(completion: @escaping (Result<[Results], Error>) -> Void) {
let urlString = "https://www.arbeitnow.com/api/job-board-api"
guard let url = URL(string: urlString) else {
completion(.failure(URLError(.badURL)))
return
}
let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard
let data = data,
let response = response as? HTTPURLResponse,
error == nil
else {
completion(.failure(error ?? URLError(.badServerResponse)))
return
}
guard 200 ..< 300 ~= response.statusCode else {
completion(.failure(WebServiceError.httpError(data, response.statusCode)))
return
}
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let results = try decoder.decode([Results].self, from: data)
completion(.success(results.data))
} catch {
completion(.failure(error))
}
}
task.resume()
}
所以,那会,
- 如果有
URLSession
错误,请告诉您错误是什么;
- 如果有非 2xx 状态代码,请告诉您代码是什么(以及 return 响应的正文,以防您想查看);和
- 如果有解析错误,告诉你解析错误是什么。
如果没有这样的东西来捕捉显着错误信息,你就是瞎了眼。
在这种情况下,错误是您正在解析 [Results]
,但结构是一个字典,其键为 data
,其值为 [Results]
。您缺少此字典的对象,该对象包含 [Results]
.
struct ResponseObject: Decodable {
let data: [Posting]
let links: Links
let meta: Meta
}
struct Posting: Decodable {
let slug, companyName, title, description: String
let remote: Bool
let url: String
let tags, jobTypes: [String]
let location: String
let createdAt: Int
}
struct Links: Decodable {
let first: URL?
let last: URL?
let prev: URL?
let next: URL?
}
struct Meta: Decodable {
let currentPage: Int
let path: URL
let perPage: Int
let from: Int
let to: Int
let terms: String
let info: String
}
func getResults(completion: @escaping (Result<[Posting], Error>) -> Void) {
let urlString = "https://www.arbeitnow.com/api/job-board-api"
guard let url = URL(string: urlString) else {
completion(.failure(URLError(.badURL)))
return
}
let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard
let data = data,
let response = response as? HTTPURLResponse,
error == nil
else {
completion(.failure(error ?? URLError(.badServerResponse)))
return
}
guard 200 ..< 300 ~= response.statusCode else {
completion(.failure(WebServiceError.httpError(data, response.statusCode)))
return
}
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let results = try decoder.decode(ResponseObject.self, from: data)
completion(.success(results.data))
} catch {
completion(.failure(error))
}
}
task.resume()
}
您的型号与您从您提供的 link 收到的 JSON 不匹配:
使用:
struct Root: Codable{
let data: [WorkData]
let links: Links
let meta: Meta
}
// MARK: - Links
struct Links: Codable {
let first: String
let last, prev: String?
let next: String
}
// MARK: - Meta
struct Meta: Codable {
let currentPage, from: Int
let path: String
let perPage, to: Int
let terms, info: String
enum CodingKeys: String, CodingKey {
case currentPage = "current_page"
case from, path
case perPage = "per_page"
case to, terms, info
}
}
struct WorkData: Codable {
let slug, companyName, title, payloadDescription: String
let remote: Bool
let url: String
let tags, jobTypes: [String]
let location: String
let createdAt: Int
enum CodingKeys: String, CodingKey {
case slug
case companyName = "company_name"
case title
case payloadDescription = "description"
case remote, url, tags
case jobTypes = "job_types"
case location
case createdAt = "created_at"
}
}
应该可以解决问题
用法:
let root = JsonDecoder().decode(Root.self, from: data)
let firstCompany = root.data[0]
编辑评论:
这应该有效!
let results = try decoder.decode([Results].self, from: data)
是你的代码吗?
改为使用:
let root = JsonDecoder().decode(Root.self, from: data)
这里怎么会缺少数据?
之后,您应该将根对象映射到您的 Result
类型,以保持您的 Viewmodel 和完成处理程序保持现在的状态。或者改为更改 Viewmodel 和完成处理程序。
我是 iOS 开发的初学者。我试图在求职 iOS 应用程序中使用 api URl: https://www.arbeitnow.com/api/job-board-api。但我的应用程序上没有显示任何内容。我在 POSTMAN 中测试了 URL,它 returns json(但在描述部分是 HTML?)。我写的代码:
func getResults(completed: @escaping (Result<[Results], ErrorMessage>) -> Void) {
let urlString = "https://www.arbeitnow.com/api/job-board-api"
guard let url = URL(string: urlString) else {return}
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let _ = error {
completed(.failure(.invalidData))
return
}
guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
completed(.failure(.invalidResponse))
return
}
guard let data = data else {
completed(.failure(.invalidData))
return
}
do {
let deconder = JSONDecoder()
deconder.keyDecodingStrategy = .convertFromSnakeCase
let results = try deconder.decode([Results].self, from: data)
completed(.success(results))
} catch {
completed(.failure(.invalidData))
}
}
task.resume()
}
struct Results: Codable {
let slug, companyName, title, resultsDescription: String
let remote: Bool
let url: String
let tags, jobTypes: [String]
let location: String
let createdAt: Int
enum CodingKeys: String, CodingKey {
case slug
case companyName = "company_name"
case title
case resultsDescription = "description"
case remote, url, tags
case jobTypes = "job_types"
case location
case createdAt = "created_at"
}
}
我使用了 HomeViewController 中的代码:
override func viewDidLoad() {
super.viewDidLoad()
title = "Home"
collectionView.backgroundColor = UIColor(named: "backgroundMain")
collectionView.register(SearchViewCell.self, forCellWithReuseIdentifier: cellId)
setupSearchBar()
Service.shared.getResults() { [weak self] result in
switch result {
case .success(let results):
print(results)
self?.jobResults = results
DispatchQueue.main.async {
self?.collectionView.reloadData()
}
case .failure(let error):
print(error)
}
}
}
888
我不知道我的代码有什么问题。谁能帮忙?谢谢!
您正在丢弃所有有意义的错误信息,这将使诊断变得困难。如果你得到一个 Error
对象,你应该 return 那:
enum WebServiceError: Error {
case httpError(Data, Int)
}
func getResults(completion: @escaping (Result<[Results], Error>) -> Void) {
let urlString = "https://www.arbeitnow.com/api/job-board-api"
guard let url = URL(string: urlString) else {
completion(.failure(URLError(.badURL)))
return
}
let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard
let data = data,
let response = response as? HTTPURLResponse,
error == nil
else {
completion(.failure(error ?? URLError(.badServerResponse)))
return
}
guard 200 ..< 300 ~= response.statusCode else {
completion(.failure(WebServiceError.httpError(data, response.statusCode)))
return
}
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let results = try decoder.decode([Results].self, from: data)
completion(.success(results.data))
} catch {
completion(.failure(error))
}
}
task.resume()
}
所以,那会,
- 如果有
URLSession
错误,请告诉您错误是什么; - 如果有非 2xx 状态代码,请告诉您代码是什么(以及 return 响应的正文,以防您想查看);和
- 如果有解析错误,告诉你解析错误是什么。
如果没有这样的东西来捕捉显着错误信息,你就是瞎了眼。
在这种情况下,错误是您正在解析 [Results]
,但结构是一个字典,其键为 data
,其值为 [Results]
。您缺少此字典的对象,该对象包含 [Results]
.
struct ResponseObject: Decodable {
let data: [Posting]
let links: Links
let meta: Meta
}
struct Posting: Decodable {
let slug, companyName, title, description: String
let remote: Bool
let url: String
let tags, jobTypes: [String]
let location: String
let createdAt: Int
}
struct Links: Decodable {
let first: URL?
let last: URL?
let prev: URL?
let next: URL?
}
struct Meta: Decodable {
let currentPage: Int
let path: URL
let perPage: Int
let from: Int
let to: Int
let terms: String
let info: String
}
func getResults(completion: @escaping (Result<[Posting], Error>) -> Void) {
let urlString = "https://www.arbeitnow.com/api/job-board-api"
guard let url = URL(string: urlString) else {
completion(.failure(URLError(.badURL)))
return
}
let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard
let data = data,
let response = response as? HTTPURLResponse,
error == nil
else {
completion(.failure(error ?? URLError(.badServerResponse)))
return
}
guard 200 ..< 300 ~= response.statusCode else {
completion(.failure(WebServiceError.httpError(data, response.statusCode)))
return
}
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let results = try decoder.decode(ResponseObject.self, from: data)
completion(.success(results.data))
} catch {
completion(.failure(error))
}
}
task.resume()
}
您的型号与您从您提供的 link 收到的 JSON 不匹配:
使用:
struct Root: Codable{
let data: [WorkData]
let links: Links
let meta: Meta
}
// MARK: - Links
struct Links: Codable {
let first: String
let last, prev: String?
let next: String
}
// MARK: - Meta
struct Meta: Codable {
let currentPage, from: Int
let path: String
let perPage, to: Int
let terms, info: String
enum CodingKeys: String, CodingKey {
case currentPage = "current_page"
case from, path
case perPage = "per_page"
case to, terms, info
}
}
struct WorkData: Codable {
let slug, companyName, title, payloadDescription: String
let remote: Bool
let url: String
let tags, jobTypes: [String]
let location: String
let createdAt: Int
enum CodingKeys: String, CodingKey {
case slug
case companyName = "company_name"
case title
case payloadDescription = "description"
case remote, url, tags
case jobTypes = "job_types"
case location
case createdAt = "created_at"
}
}
应该可以解决问题
用法:
let root = JsonDecoder().decode(Root.self, from: data)
let firstCompany = root.data[0]
编辑评论: 这应该有效!
let results = try decoder.decode([Results].self, from: data)
是你的代码吗?
改为使用:
let root = JsonDecoder().decode(Root.self, from: data)
这里怎么会缺少数据?
之后,您应该将根对象映射到您的 Result
类型,以保持您的 Viewmodel 和完成处理程序保持现在的状态。或者改为更改 Viewmodel 和完成处理程序。