【问题标题】:How to fetch JSONData in DetailViewController? Swift如何在 DetailViewController 中获取 JSONData?迅速
【发布时间】:2019-07-04 08:28:59
【问题描述】:

我有 2 个控制器:CollectionViewControllerDetailViewController。在CollectionViewController 中,我获取了数据并获得了coctails。现在我想获取coctails?.drinks?[indexPath.row] 并传入DetailViewController,我需要再次获取请求,但需要使用另一个API 和新的url。但是在加载DetailViewController时,networkDataService.fetchDrink(drinkName: drinkName)方法不起作用。 我做错了什么?

struct Coctail: Codable {
   let drinks: [Drink]?
}

struct Drink: Codable {
   let strDrink : String?
   let strDrinkThumb : URL?
}

class NetworkDataService {

let networkManager = NetworkManager.shared

func fetchCoctails(completion: @escaping (Coctail?) -> Void) {
    let url = "https://www.thecocktaildb.com/api/json/v1/1/filter.php?c=Cocktail"
    networkManager.fetchData(url: url, completion: completion)
}

func fetchDrink(drinkName: String, completion: @escaping (Coctail?) -> Void) {
    let url = "https://www.thecocktaildb.com/api/json/v1/1/search.php?s=\(drinkName)"
    networkManager.fetchData(url: url, completion: completion)
   }
}

class CollectionViewController: UICollectionViewController {

var coctails: Coctail?
let networkDataService = NetworkDataService()

override func viewDidLoad() {
    super.viewDidLoad()

    networkDataService.fetchCoctails() { (coctails) in
        self.coctails = coctails

        DispatchQueue.main.async {
            self.collectionView.reloadData()
        }
    }

}

// MARK: UICollectionViewDataSource

override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return coctails?.drinks?.count ?? 0
}

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell

    let drink = coctails?.drinks?[indexPath.row]

    cell.config(drink: drink)

    return cell
}

// MARK: - Navigation

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

    guard let indexPath = collectionView.indexPathsForSelectedItems?.first else { return }
    let drink = coctails?.drinks?[indexPath.row]

    let destination = segue.destination as! DetailViewController
    destination.drinkName = drink?.strDrink ?? ""
   }
}

class DetailViewController: UIViewController {

var drinkName = ""
var coctail: Coctail?
let networkDataService = NetworkDataService()

override func viewDidLoad() {
    super.viewDidLoad()

    networkDataService.fetchDrink(drinkName: drinkName) { (coctail) in
        self.coctail = coctail
    }
}

【问题讨论】:

  • DetailViewController中drinkName不为空吧?可以传数据吗?
  • @Vicaren 对! drinkName 不为空
  • @MikhailTseitlin 我认为 viewDidLoad 函数在您设置drinkName 之前运行。那么当你调用fetchDrink时,drinkName 为空

标签: json swift api


【解决方案1】:

如果您使用strDrink 中的饮料名称,那么问题是您发送的内容如下:

'57 雪佛兰白车牌

这意味着 URL 将类似于:

https://www.thecocktaildb.com/api/json/v1/1/search.php?s='57 雪佛兰 白车牌

并且不会自动转换为 URL 编码的 URL。

这种方法的问题是您需要在将名称发送到 API 之前对名称进行 url 编码。比如:

networkDataService.fetchDrink(drinkName: drinkName.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)) { (coctail) in
    self.coctail = coctail
}

这样您将获得类似以下内容的 URL:

https://www.thecocktaildb.com/api/json/v1/1/search.php?s=%2757%20Chevy%20with%20a%20White%20License%20Plate

引用此 URL 编码字符串: Swift - encode URL

另一方面,您的 API 返回饮料的 id,idDrink,它应该用于获取详细信息,而不是运行搜索,然后根据特定名称提取第一个。稍后可能发生的情况是,您可能有两个 Jack Daniel's,具有不同的值,您将始终显示第一个。

【讨论】:

  • 查看最新评论以及将来对您的应用进行校对:)
  • 现在我使用饮料的 id,一切正常!)再次感谢!)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-30
  • 1970-01-01
  • 1970-01-01
  • 2016-09-03
  • 1970-01-01
  • 2015-11-13
相关资源
最近更新 更多