所以我有一个UICollectionView,一旦用户在搜索栏中输入一些文本,它就会显示图像。第一次效果很好,但是一旦您尝试再次搜索,您就会得到:
Failed to decode: dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.})))
我检查了从请求发送的路径,它与应有的路径完全相同。看起来和第一个完全一样。我不明白这是怎么回事。...
模型类
import Foundation
struct Image{
let name: String?
let imageUrl: String?
init(name: String? = nil, imageUrl: String? = nil) {
self.name = name
self.imageUrl = imageUrl
}
}
struct ImageObject: Codable {
let value: [Value]?
let queryExpansions: [QueryExpansions]?
let pivotSuggestions: [PivotSuggestions]?
let similarTerms: [SimilarTerms]?
let relatedSearches: [RelatedSearches]?
}
struct Value: Codable {
let name: String?
let contentUrl: String?
let imageId: String?
let thumbnailUrl: String?
}
struct QueryExpansions: Codable {
let text: String?
let thumbnail: ThumbnailWithUrl?
}
struct PivotSuggestions: Codable {
let suggestions: [Suggestions]?
}
struct Suggestions: Codable {
let text: String?
let thumbnail: ThumbnailWithUrl?
}
struct SimilarTerms: Codable {
let text: String?
let thumbnail: Thumbnail?
}
struct RelatedSearches: Codable {
let text: String?
let thumbnail: ThumbnailWithUrl?
}
struct Thumbnail: Codable {
let url: String?
}
struct ThumbnailWithUrl: Codable {
let thumbnailUrl: String?
}
API_Service类
class API_Service{
static let sharedAPIService = API_Service()
func fetchImagesFromSearch(request: String ,completionHandler:@escaping(ImageObject?) ->()){
var path = "https://api.cognitive.microsoft.com/bing/v7.0/images/search"
let searchRequest = "q=" + request
let array = [
// Request parameters
searchRequest,
//"count=10",
//"offset=0",
"mkt=en-us",
"safeSearch=Moderate",
]
let string = array.joined(separator: "&")
path = path + "?" + string
guard let url = URL(string: path) else { return }
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "GET"
urlRequest.setValue("KeyGoesHere", forHTTPHeaderField: "Ocp-Apim-Subscription-Key")
urlRequest.httpBody = path.data(using: .utf8)
URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
if(error != nil){
print("Error: \(error!)")
completionHandler(nil)
}
guard let data = data else { return }
do{
let results = try JSONDecoder().decode(ImageObject.self, from: data)
completionHandler(results)
} catch let decodeError {
// Decode error, what should we show to the user?
print("Failed to decode: ", decodeError)
completionHandler(nil)
}
}.resume()
}
}
ViewController类
import UIKit
class mainViewController: UIViewController, UICollectionViewDelegate,
UICollectionViewDataSource, UISearchBarDelegate {
@IBOutlet weak var mainCollectionView: UICollectionView!
var images = [Image]()
let mainCollectionViewCellReusableIdentifier = "mainCollectionViewCell"
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
setupLayout()
setupSearchController()
title = "Search something!"
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
navigationItem.hidesSearchBarWhenScrolling = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func fetchImagesOf(searchText: String){
API_Service.sharedAPIService.fetchImagesFromSearch(request: searchText) { (data) in
if let results = data{
if let values = results.value{
self.collectImagesFromValue(using: values)
}
if let queryExpansions = results.queryExpansions{
self.collectImagesFromQueryExpansions(using: queryExpansions)
}
if let pivotSuggestions = results.pivotSuggestions{
self.collectImagesFromPivotSuggestions(using: pivotSuggestions)
}
if let similarTerms = results.similarTerms{
self.collectImagesFromSimilarTerms(using: similarTerms)
}
if let relatedSearches = results.relatedSearches{
self.collectImagesFromRelatedSearches(using: relatedSearches)
}
DispatchQueue.main.async {
self.mainCollectionView.reloadData()
}
}
}
}
func collectImagesFromValue(using results: [Value]){
for image in results{
if let url = image.thumbnailUrl{
let name = image.name ?? ""
let image = Image(name: name, imageUrl: url)
self.images.append(image)
}else{ continue }
}
}
func collectImagesFromQueryExpansions(using results: [QueryExpansions]){
for image in results{
if let thumbnail = image.thumbnail{
if let thumbnailUrl = thumbnail.thumbnailUrl{
let name = image.text ?? ""
let image = Image(name: name, imageUrl: thumbnailUrl)
self.images.append(image)
}else { continue }
}else{ continue }
}
}
func collectImagesFromPivotSuggestions(using results: [PivotSuggestions]){
for image in results{
if let suggestions = image.suggestions{
for suggestion in suggestions{
let name = suggestion.text ?? ""
if let thumbnail = suggestion.thumbnail{
if let thumbnailUrl = thumbnail.thumbnailUrl{
let image = Image(name: name, imageUrl: thumbnailUrl)
self.images.append(image)
}
}else { continue }
}
}else{ continue }
}
}
func collectImagesFromSimilarTerms(using results: [SimilarTerms]){
for image in results{
if let thumbnail = image.thumbnail{
if let thumbnailUrl = thumbnail.url{
let name = image.text ?? ""
let image = Image(name: name, imageUrl: thumbnailUrl)
self.images.append(image)
}else { continue }
}else{ continue }
}
}
func collectImagesFromRelatedSearches(using results: [RelatedSearches]){
for image in results{
if let thumbnail = image.thumbnail{
if let thumbnailUrl = thumbnail.thumbnailUrl{
let name = image.text ?? ""
let image = Image(name: name, imageUrl: thumbnailUrl)
self.images.append(image)
}else { continue }
}else{ continue }
}
}
func setupLayout(){
let layout = UICollectionViewFlowLayout()
let cellHeight = view.frame.size.width / 3
let cellWidth = cellHeight
let cellSize = CGSize(width: cellWidth, height: cellHeight)
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
layout.itemSize = cellSize
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
mainCollectionView.collectionViewLayout = layout
}
func setupSearchController(){
searchController.searchBar.delegate = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search for images"
navigationItem.searchController = searchController
definesPresentationContext = true
navigationItem.hidesSearchBarWhenScrolling = false
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
fetchImagesOf(searchText: searchBar.text!)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images.count > 0 ? images.count : 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: mainCollectionViewCellReusableIdentifier, for: indexPath) as! MainCollectionViewControllerCell
if images.count > 0{
cell.image = images[indexPath.row]
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let imageViewController = storyBoard.instantiateViewController(withIdentifier: "imageViewController") as! ImageViewController
imageViewController.image = images[indexPath.item]
navigationController?.pushViewController(imageViewController, animated: true)
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
JSON
{
"_type": "Images",
"instrumentation": {
"_type": "ResponseInstrumentation"
},
"readLink": "https://api.cognitive.microsoft.com/api/v7/images/search?
q=cats",
"webSearchUrl": "https://www.bing.com/images/search?q=cats&FORM=OIIARP",
"totalEstimatedMatches": 955,
"nextOffset": 5,
"value": [
{
"webSearchUrl": "https://www.bing.com/images/search? view=detailv2&FORM=OIIRPO&q=cats&id=6B6E51236064B16189141D1916C6F188AB1D8FD1&simid=608039789623643813",
"name": "Cute Cats #5 - Pets Cute and Docile",
"thumbnailUrl": "https://tse2.mm.bing.net/th?id=OIP.U5GJh9jyKpFuhBIt_EEZvAHaE9&pid=Api",
"datePublished": "2018-06-19T21:32:00.0000000Z",
"contentUrl": "http://4.bp.blogspot.com/-o5XBs5uRifo/UIUQeuyqoMI/AAAAAAAAHm0/h-XH1IR3l6Y/s1600/cats_animals_cat_desktop_3872x2592_hd-wallpaper-863122.jpeg",
"hostPageUrl": "http://dark-horse-adaptations.blogspot.com/2012/10/cute-cats-5.html",
"contentSize": "127935 B",
"encodingFormat": "jpeg",
"hostPageDisplayUrl": "dark-horse-adaptations.blogspot.com/2012/10/cute-cats-5.html",
"width": 1600,
"height": 1071,
"thumbnail": {
"width": 474,
"height": 317
},
"imageInsightsToken": "ccid_U5GJh9jy*mid_6B6E51236064B16189141D1916C6F188AB1D8FD1*simid_608039789623643813*thid_OIP.U5GJh9jyKpFuhBIt!_EEZvAHaE9",
"insightsMetadata": {
"recipeSourcesCount": 0,
"bestRepresentativeQuery": {
"text": "Crazy Cats Kittens Wallpaper",
"displayText": "Crazy Cats Kittens Wallpaper",
"webSearchUrl": "https://www.bing.com/images/search?q=Crazy+Cats+Kittens+Wallpaper&id=6B6E51236064B16189141D1916C6F188AB1D8FD1&FORM=IDBQDM"
},
"pagesIncludingCount": 32,
"availableSizesCount": 16
},
"imageId": "6B6E51236064B16189141D1916C6F188AB1D8FD1",
"accentColor": "666666"
},
{
"webSearchUrl": "https://www.bing.com/images/search?view=detailv2&FORM=OIIRPO&q=cats&id=F42DAAA598B5E0E1383CED35C292387266EB9A9F&simid=608030899010537949",
"name": "A Cat’s Tale: Meowing for the right kind of food - Zee ...",
"thumbnailUrl": "https://tse4.mm.bing.net/th?id=OIP.qtkOFD3PTouGYLHxi3xypwHaFj&pid=Api",
"datePublished": "2017-06-12T03:21:00.0000000Z",
"contentUrl": "http://zeelifestylecebu.com/wp-content/uploads/2015/03/cat3.jpg",
"hostPageUrl": "http://zeelifestylecebu.com/a-cats-tale-meowing-for-the-right-kind-of-food/",
"contentSize": "414235 B",
"encodingFormat": "jpeg",
"hostPageDisplayUrl": "zeelifestylecebu.com/a-cats-tale-meowing-for-the-right-kind-of-food",
"width": 1600,
"height": 1200,
"thumbnail": {
"width": 474,
"height": 355
},
"imageInsightsToken": "ccid_qtkOFD3P*mid_F42DAAA598B5E0E1383CED35C292387266EB9A9F*simid_608030899010537949*thid_OIP.qtkOFD3PTouGYLHxi3xypwHaFj",
"insightsMetadata": {
"recipeSourcesCount": 0,
"bestRepresentativeQuery": {
"text": "Cat Kitten",
"displayText": "Cat Kitten",
"webSearchUrl": "https://www.bing.com/images/search?q=Cat+Kitten&id=F42DAAA598B5E0E1383CED35C292387266EB9A9F&FORM=IDBQDM"
},
"pagesIncludingCount": 46,
"availableSizesCount": 20
},
"imageId": "F42DAAA598B5E0E1383CED35C292387266EB9A9F",
"accentColor": "8E553D"
},
{
"webSearchUrl": "https://www.bing.com/images/search?view=detailv2&FORM=OIIRPO&q=cats&id=A0401CF1F0E6DF84114EFA731FAF1CB360B3ED56&simid=607997879302688190",
"name": "cat | installect",
"thumbnailUrl": "https://tse3.mm.bing.net/th?id=OIP.WpkNnHDGdlljW4b1G_cl-QHaF7&pid=Api",
"datePublished": "2017-10-11T15:24:00.0000000Z",
"contentUrl": "https://installect.files.wordpress.com/2013/03/catsincup.jpg",
"hostPageUrl": "https://installect.wordpress.com/tag/cat/",
"contentSize": "274870 B",
"encodingFormat": "jpeg",
"hostPageDisplayUrl": "https://installect.wordpress.com/tag/cat",
"width": 1280,
"height": 1024,
"thumbnail": {
"width": 474,
"height": 379
},
"imageInsightsToken": "ccid_WpkNnHDG*mid_A0401CF1F0E6DF84114EFA731FAF1CB360B3ED56*simid_607997879302688190*thid_OIP.WpkNnHDGdlljW4b1G!_cl-QHaF7",
"insightsMetadata": {
"recipeSourcesCount": 0,
"bestRepresentativeQuery": {
"text": "Cute Good Morning Kitten",
"displayText": "Cute Good Morning Kitten",
"webSearchUrl": "https://www.bing.com/images/search?q=Cute+Good+Morning+Kitten&id=A0401CF1F0E6DF84114EFA731FAF1CB360B3ED56&FORM=IDBQDM"
},
"pagesIncludingCount": 420,
"availableSizesCount": 116
},
"imageId": "A0401CF1F0E6DF84114EFA731FAF1CB360B3ED56",
"accentColor": "72441C"
},
{
"webSearchUrl": "https://www.bing.com/images/search?view=detailv2&FORM=OIIRPO&q=cats&id=8CC6B40382B19534E56CEE711488ED9FDAF52B93&simid=607994756864674280",
"name": "Somali Cats – Jeanne Foguth's Blog",
"thumbnailUrl": "https://tse3.mm.bing.net/th?id=OIP.Csfth4IIGILGI31QVA54HgHaHg&pid=Api",
"datePublished": "2018-01-17T08:20:00.0000000Z",
"contentUrl": "https://foguth.files.wordpress.com/2014/11/19068-chocolate-somali-cat-white-background.jpg",
"hostPageUrl": "https://foguth.wordpress.com/tag/somali-cats/",
"contentSize": "260846 B",
"encodingFormat": "jpeg",
"hostPageDisplayUrl": "https://foguth.wordpress.com/tag/somali-cats",
"width": 1089,
"height": 1104,
"thumbnail": {
"width": 474,
"height": 480
},
"imageInsightsToken": "ccid_Csfth4II*mid_8CC6B40382B19534E56CEE711488ED9FDAF52B93*simid_607994756864674280*thid_OIP.Csfth4IIGILGI31QVA54HgHaHg",
"insightsMetadata": {
"recipeSourcesCount": 0,
"bestRepresentativeQuery": {
"text": "Chocolate Somali Cat",
"displayText": "Chocolate Somali Cat",
"webSearchUrl": "https://www.bing.com/images/search?q=Chocolate+Somali+Cat&id=8CC6B40382B19534E56CEE711488ED9FDAF52B93&FORM=IDBQDM"
},
"pagesIncludingCount": 12,
"availableSizesCount": 4
},
"imageId": "8CC6B40382B19534E56CEE711488ED9FDAF52B93",
"accentColor": "AF501C"
},
{
"webSearchUrl": "https://www.bing.com/images/search?view=detailv2&FORM=OIIRPO&q=cats&id=3FC937888C49B0641BC0A590AAF50FED74AEB93E&simid=608021153747308294",
"name": "Cat Pictures - Photos of Cats | Interesting Stuff",
"thumbnailUrl": "https://tse3.mm.bing.net/th?id=OIP.QjKAHyYfB4sQ9y_kbxEheAHaFA&pid=Api",
"datePublished": "2011-10-29T23:41:00.0000000Z",
"contentUrl": "http://www.cat-world.com.au/images/levi-sma2-big.jpg",
"hostPageUrl": "http://www.cat-world.com.au/cat-photos",
"contentSize": "800317 B",
"encodingFormat": "jpeg",
"hostPageDisplayUrl": "www.cat-world.com.au/cat-photos",
"width": 1590,
"height": 1075,
"thumbnail": {
"width": 474,
"height": 320
},
"imageInsightsToken": "ccid_QjKAHyYf*mid_3FC937888C49B0641BC0A590AAF50FED74AEB93E*simid_608021153747308294*thid_OIP.QjKAHyYfB4sQ9y!_kbxEheAHaFA",
"insightsMetadata": {
"recipeSourcesCount": 0,
"bestRepresentativeQuery": {
"text": "Singapura Cat Breed",
"displayText": "Singapura Cat Breed",
"webSearchUrl": "https://www.bing.com/images/search?q=Singapura+Cat+Breed&id=3FC937888C49B0641BC0A590AAF50FED74AEB93E&FORM=IDBQDM"
},
"pagesIncludingCount": 24,
"availableSizesCount": 12
},
"imageId": "3FC937888C49B0641BC0A590AAF50FED74AEB93E",
"accentColor": "614B3D"
}
],
答案 0 :(得分:0)
这是您遇到问题的代码段。
urlRequest.httpMethod = "GET"
urlRequest.setValue("KeyGoesHere", forHTTPHeaderField: "Ocp-Apim-Subscription-Key")
urlRequest.httpBody = path.data(using: .utf8)
您的httpMethod
值为GET
。
但是,在下面的两行中您分配了一个httpBody
值。
在执行GET
请求时不使用该字段。通常用于在POST
请求期间向API服务器发送诸如表单数据之类的信息。
删除设置正文的行,请求应该可以正常工作。