如何解析复杂的JSON并在CollectionView的内部和外部显示它

时间:2017-01-09 09:56:14

标签: json swift alamofire

我一直在处理 JSON 一个月,日复一日地变得更好。这是一个复杂的拼图,我一直在盘旋。 JSON 返回我得到的是这样的:

{
"main_content": [
{
  "product_title": "product 3",
  "description": "",
  "regular_price": "320",
  "sale_price": "",
  "product_currency": "$",
  "size": [
    {
      "size_data": "L"
    },
    {
      "size_data": "S"
    }
  ],
  "color": [
    {
      "color_data": "RED"
    },
   {
      "color_data": "WHITE"
    }
  ],
  "gallery": [
    {
      "guid": "http://xxx/wp-content/uploads/2016/11/catagory1.jpg"
    },
    {
      "guid": "http://xxx/wp-content/uploads/2016/11/catagory3.jpg"
    }
      ]
    }
  ]
}

现在, product_title 说明 regular_price sale_price product_currency 你可以看到将在数组之外。对于尺寸& 颜色我需要在 CollectionView 之外获取数组,我不知道如何在 collectionView tableView之外遍历数组,因为我有一个 indexpath 来迭代,但我不知道在 collectionView tableView 之外做什么。最后,我的图片滑块将位于 CollectionView 内,因此图库项目必须位于其中。这是我各自页面的视觉图像。

enter image description here enter image description here

现在,在视图

中使用 Alamofire 进行 POST 调用
import Foundation
import Alamofire
import SwiftyJSON

//Error could happen for these reason
enum ProductDetailsManagerError: Error {
case network(error: Error)
case apiProvidedError(reason: String)
case authCouldNot(reason: String)
case authLost(reason: String)
case objectSerialization(reason: String)
}


 // APIManager Class
 class ProductDetailsManager {

 // THE RIGHT WAY A.K.A. "THE ONE LINE SINGLETON (NOW WITH PROOF!")
static let sharedInstance = ProductDetailsManager()

func printPublicGists(parameter: [String:Any]? , completionHandler: @escaping (Result<[ProductDetailsJSON]>) -> Void) {

    let url: String = "http://xxx/wp-api/products/get_product_informations/"

    Alamofire.request(url, method: .post, parameters: parameter, encoding: URLEncoding.default, headers: nil)
     .responseJSON { (response) in

        guard response.result.error == nil else {
           print(response.result.error!)
           return
        }

        guard let value = response.result.value else {
            print("no string received in response when swapping oauth code for token")
            return
        }

        print(value)

    }

}

func fetchPublicGists(parameter: [String:Any]? , completionHandler: @escaping (Result<[ProductDetailsJSON]>) -> Void) {

    let url: String = "http://xxx/wp-api/products/get_product_informations/"
    Alamofire.request(url, method: .post, parameters: parameter, encoding: URLEncoding.default, headers: nil)
        .responseJSON { response in

            let result = self.gistArrayFromResponse(response: response)
            completionHandler(result)
    }
}


// Download Image from URL
func imageFrom(urlString: String, completionHandler: @escaping (UIImage?, Error?) -> Void) {
    let _ = Alamofire.request(urlString)
        .response { dataResponse in
            // use the generic response serializer that returns Data
            guard let data = dataResponse.data else {
                completionHandler(nil, dataResponse.error)
                return
            }
            let image = UIImage(data: data)
            completionHandler(image, nil)
    }
}

//gistArrayFromResponse function
private func gistArrayFromResponse(response: DataResponse<Any>) -> Result<[ProductDetailsJSON]> {

    // For Network Error
    guard response.result.error == nil else {
        print(response.result.error!)
        return .failure(RueDu8APIManagerError.network(error: response.result.error!))
    }

    // JSON Serialization Error, make sure we got JSON and it's an array
    guard let jsonArray = response.result.value else {
        print("did not get array of homeFeed object as JSON from API")
        return .failure(RueDu8APIManagerError.objectSerialization(reason: "Did not get JSON dictionary in response"))
    }

    //turn JSON into gists
    //let gistss = jsonArray.flatMap { HomeFeedJSON(items: $0) }
    var gists = [ProductDetailsJSON]()
    let jsonR = JSON(jsonArray)
    let main_content = jsonR["main_content"].array
    for item in main_content! {
        gists.append(ProductDetailsJSON(items: item))
    }

    return .success(gists)


   }//gistArrayFromResponse() function ends here

  }

这是我的模型

import Foundation
import SwiftyJSON

class ProductDetailsJSON {

var _product_title: String?
var _description: String?
var _regular_price: String?
var _sale_price: String?
var _product_currency: String?
var _size: String?
var _color: String?
var _image: URL?


init(items: JSON){

    self._product_title = items["product_title"].stringValue
    self._description = items["description"].stringValue
    self._regular_price = items["regular_price"].stringValue
    self._sale_price = items["sale_price"].stringValue
    self._product_currency = items["product_currency"].stringValue

    let sizeData = items["size"].arrayValue
    for itemsIMG in sizeData {
        self._size = itemsIMG["size_data"].stringValue
    }

    let colorData = items["color"].arrayValue
    for itemsColor in colorData {
        self._size = itemsColor["color_data"].stringValue
    }

    let galleryImg = items["gallery"].arrayValue
    for image in galleryImg {
       self._image = image["guid"].URL
    }



}

var product_title: String {
    if _product_title == nil {
        _product_title = ""
    }
    return _product_title!
}

var description: String {
    if _description == nil {
        _description = ""
    }
    return _description!
}

var regular_price: String {
    if _regular_price == nil {
        _regular_price = ""
    }
    return _regular_price!
}

var sale_price: String {
    if _sale_price == nil {
        _sale_price = ""
    }
    return _sale_price!
}

var product_currency: String {
    if _product_currency == nil {
        _product_currency = ""
    }
    return _product_currency!
}


var product_color: String {
    if _color == nil {
        _color = ""
    }
    return _size!
}

var product_image: URL {
    if _image == nil {
        let myURL = "http://www.clker.com/cliparts/d/L/P/X/z/i/no-image-icon-hi.png"
        let noImage: URL = URL(string: myURL)!
        _image = noImage
    }
    return _image!
    }


 }

这是我的控制器类,我正在努力展示尺寸颜色图库项目来自 JSON

import UIKit
import DropDown
import Alamofire
import SwiftyJSON

class ShopItemVC: UIViewController , UICollectionViewDataSource,     UICollectionViewDelegate {


@IBOutlet weak var collectionView: UICollectionView!

@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var contentView: UIView!
@IBOutlet weak var selectedProductImg: UIImageView!
@IBOutlet weak var backgroundCardView1: UIView!
@IBOutlet weak var backgroundCardView2: UIView!
@IBOutlet weak var backgroundCardView3: UIView!

@IBOutlet weak var sizeBtn: NiceButton!
@IBOutlet weak var colorBtn: NiceButton!
@IBOutlet weak var productPrice: UILabel!
@IBOutlet weak var productTitle: UILabel!

// var Title = [ProductDetailsJSON]()

var product_id:Int? //got value from SpecificCatagoryVC
var product_detail = [ProductDetailsJSON]()
var reloadData = 0

let sizeDropDown = DropDown()
let colorDropDown = DropDown()
lazy var dropDowns: [DropDown] = {
     return [
         self.sizeDropDown,
         self.colorDropDown
      ]
   }()


 let CatagoryPic =  ["catagory1","catagory2","catagory3","catagory4","catagory5","catagory6","c atagory7"]
 // let CatagoryPicture = [ProductDetailsJSON]()




 override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.

    sizeBtn.layer.borderWidth = 1.2
    sizeBtn.layer.borderColor = UIColor.black.cgColor

    colorBtn.layer.borderWidth = 1.2
    colorBtn.layer.borderColor = UIColor.black.cgColor

    backgroundCardView1.backgroundColor = UIColor.white
    backgroundCardView1.layer.cornerRadius = 5.0
    backgroundCardView1.layer.masksToBounds = false
    backgroundCardView1.layer.shadowColor = UIColor.black.withAlphaComponent(0.2).cgColor
    backgroundCardView1.layer.shadowOffset = CGSize(width: 0, height: 0)
    backgroundCardView1.layer.shadowOpacity = 0.8

    backgroundCardView2.backgroundColor = UIColor.white
    backgroundCardView2.layer.cornerRadius = 5.0
    backgroundCardView2.layer.masksToBounds = false
    backgroundCardView2.layer.shadowColor = UIColor.black.withAlphaComponent(0.2).cgColor
    backgroundCardView2.layer.shadowOffset = CGSize(width: 0, height: 0)
    backgroundCardView2.layer.shadowOpacity = 0.8

    backgroundCardView3.backgroundColor = UIColor.white
    backgroundCardView3.layer.cornerRadius = 5.0
    backgroundCardView3.layer.masksToBounds = false
    backgroundCardView3.layer.shadowColor = UIColor.black.withAlphaComponent(0.2).cgColor
    backgroundCardView3.layer.shadowOffset = CGSize(width: 0, height: 0)
    backgroundCardView3.layer.shadowOpacity = 0.8

    setupDropDowns()





}

override func viewDidAppear(_ animated: Bool) {
    self.scrollView.contentSize = CGSize(width: self.view.frame.width, height: self.view.frame.height + 40)

    loadGists(parameter: ["product_id":product_id ?? 0])

}

func setupDropDowns() {
   setupSizeDropDown()
   setupColorDropDown()
}

func setupSizeDropDown() {

    sizeDropDown.anchorView = sizeBtn
    sizeDropDown.bottomOffset = CGPoint(x: 0, y: sizeBtn.bounds.height)
    // You can also use localizationKeysDataSource instead. Check the docs.
    sizeDropDown.dataSource = [
        "XXL",
        "XL",
        "L",
        "M",
        "S"
    ]

    // Action triggered on selection
    sizeDropDown.selectionAction = { [unowned self] (index, item) in
        self.sizeBtn.setTitle(item, for: .normal)
        print(item)
    }

}
func setupColorDropDown() {

    colorDropDown.anchorView = colorBtn
    colorDropDown.bottomOffset = CGPoint(x: 0, y: colorBtn.bounds.height)
    // You can also use localizationKeysDataSource instead. Check the docs.
    colorDropDown.dataSource = [
        "Red",
        "Blue",
        "White",
        "Purple",
        "Pink"
    ]

    // Action triggered on selection
    colorDropDown.selectionAction = { [unowned self] (index, item) in
        self.colorBtn.setTitle(item, for: .normal)
        print(item)
    }

}



override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func loadGists(parameter: [String:Any]?) {

    ProductDetailsManager.sharedInstance.fetchPublicGists(parameter: parameter) {
        (result) in

        guard result.error == nil else {
            self.handleLoadGistsError(result.error!)
            return
        }

        if let fetchedGists = result.value {
            self.product_detail = fetchedGists
        }

        self.reloadData = 1
        self.collectionView?.reloadData()
    }
}


func handleLoadGistsError(_ error: Error) { }

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return CatagoryPic.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    let  cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ShopItemCell", for: indexPath) as! ShopItemCell

          if reloadData == 1 {


              let myProduct = self.product_detail[indexPath.row]
              self.productTitle.text = myProduct.product_title

          }

    cell.shopItemPic.image = UIImage(named: CatagoryPic[(indexPath as NSIndexPath).row])


    return cell
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    // here you know which item is selected by accessing indexPath.item property, for example:
    let selectedImage = UIImage(named: CatagoryPic[(indexPath as NSIndexPath).item])
    selectedProductImg.image = selectedImage
}


@IBAction func sizeBtnPressed(_ sender: Any) {
    sizeDropDown.show()
    //print("size btn pressed")
}
@IBAction func colorBtnPressed(_ sender: Any) {
    colorDropDown.show()
}

@IBAction func backBtn(_ sender: AnyObject) {
    self.dismiss(animated: true, completion: nil)
}

}

还有一些我面临同样问题的课程。希望如果我得到这个解决方案,我将能够解决这些问题。提前谢谢。

1 个答案:

答案 0 :(得分:0)

首先要注意的是,您要返回product_color变量中的大小值而不是颜色。

此外,当您在JSON中循环遍历数组时,您将变量设置为仅为最终值。例如:

let sizeData = items["size"].arrayValue
for itemsIMG in sizeData {
    self._size = itemsIMG["size_data"].stringValue
}

JSON是

"size": [
  {
  "size_data": "L"
  },
  {
  "size_data": "S"
  }
]

因此_size将设置为"S",永远不会分配"L"。我建议将_size_color_image更改为

var _sizes: [String] = []
var _colors: [String] = []
var _images: [String] = []

然后循环遍历JSON数组时:

let sizeData = items["size"].arrayValue
for itemsIMG in sizeData {
    let size = itemsIMG["size_data"].stringValue
    _sizes.append(size)
}

如果我理解正确,那么当您获得有关要点的回复时,您希望更新下拉数据。

sizeDropDown.dataSource = product_detail.product_sizes

然后对于其他下降也一样。

在类似sale_priceregular_price的模型中创建product_sizes,product_colors和product_images变量。