使用 AlamofireObjectMapper 映射模型 - swift

Posted

技术标签:

【中文标题】使用 AlamofireObjectMapper 映射模型 - swift【英文标题】:using AlamofireObjectMapper for mapping model - swift 【发布时间】:2017-12-06 18:06:06 【问题描述】:

我正在使用AlamofierObjectMapper 将来自服务器的 json 映射到我的模型。从服务器接收到的json是这样的:

[
  
    "Title": "string",
    "ImageUrl": "string",
    "Url": "string",
    "UrlType": "none"
  
]

我用于映射的类是:

class Banner: Mappable 
    var Title: String?
    var ImageUrl: String?
    var Url: String?
    var UrlType: String?

    required init?(map: Map) 

    

    // Mappable
    func mapping(map: Map) 
        Title <- map["Title"]
        ImageUrl <- map["ImageUrl"]
        Url <- map["Url"]
        UrlType <- map["UrlType"]
    

我的类不是数组,但我的 json 是数组。我怎样才能在没有这样的情况下获取数据:


  "result" : [
  
    "Title": "string",
    "ImageUrl": "string",
    "Url": "string",
    "UrlType": "none"
  
  ]

编辑:

我的要求:

Alamofire.request(url, method: .get)
        .responseObject  (response: DataResponse<Banner>) in

            

【问题讨论】:

【参考方案1】:

很简单,只需要使用方法responseArray:

Alamofire.request(url, method: .get).responseArray  (response: DataResponse<[Banner]>) in

    let bannersArray = response.result.value

    if let bannersArray = bannersArray 
        for banner in bannersArray 
            // Do anything with it         
        
    

【讨论】:

你的意思是我不使用我的请求,而是使用 Alamofire 请求并使用 mapArray 传递 json? 对不起,一开始没有正确理解你,我已经更新了我的答案【参考方案2】:
1) Model Class One--------------
-----------------------------------------
-----------------------------------------

import Foundation
import ObjectMapper

class MainData : NSObject, Mappable 
    var page : Int?
    var per_page : Int?
    var total : Int?
    var total_pages : Int?
    var data : [Data]?
    override init() 

    
    required init?(map: Map) 

    

     func mapping(map: Map) 

        page <- map["page"]
        per_page <- map["per_page"]
        total <- map["total"]
        total_pages <- map["total_pages"]
        data <- map["data"]
    


2) Model Class Two--------------
-----------------------------------------
-----------------------------------------

import Foundation
import ObjectMapper

class Data : NSObject, Mappable 
    var id : Int?
    var name : String?
    var year : Int?
    var color : String?
    var pantone_value : String?
    override init() 

    
    required init?(map: Map) 

    

     func mapping(map: Map) 

        id <- map["id"]
        name <- map["name"]
        year <- map["year"]
        color <- map["color"]
        pantone_value <- map["pantone_value"]
    


3) ViewController--------------
-----------------------------------------
-----------------------------------------


import UIKit

class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate 
       @IBOutlet weak var myTableview: UITableView!

    @IBAction func btnNewFeature(_ sender: UIButton) 
        let vc3 = self.storyboard? .instantiateViewController(withIdentifier: "TheardViewController") as! TheardViewController
        self.navigationController? .pushViewController(vc3, animated: true)


    
    var DictData = MainData()
    var ArrayData = [Data]()

    override func viewDidLoad() 
        super.viewDidLoad()
        self.myTableview.layer.cornerRadius = 10
        getData()

        // Do any additional setup after loading the view, typically from a nib.
    



func getData()

    let dict = [
        "name":"shital",
        "rollno":"1"
    ]
    APIManager.sharedInstance.getListOfFeatures(parms: dict, onsuccess:  (responsedata, anystring) in

        self.DictData = responsedata
        self.ArrayData = self.DictData.data!
        print(self.DictData.page)
        for item in self.ArrayData
        
            print(item.color)
            print(item.id)
            print(item.name)
        
        self.myTableview.reloadData()


    )  (error, error1) in
        print(error,error1)
    

    

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        print(self.ArrayData.count)
        return self.ArrayData.count
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        var cell = myTableview.dequeueReusableCell(withIdentifier: "TableViewCell") as! TableViewCell
       let element = self.ArrayData[indexPath.row]
        let id = "\(element.id!)"
        cell.txtNoofvotes.text = id
        cell.lblFeatureTitle.text = element.name
        cell.lblRequestedName.text = element.name
        cell.txtViewFeatureDesc.text = element.pantone_value
        cell.lblRequestedDate.text = "\(element.year!)"


        if (element.id == 1)
        
            cell.btnVote.setTitle("Voted", for: .normal)
            cell.btnVote.isEnabled = false
        
        else
        
            cell.btnVote.setTitle("Vote", for: .normal)
        
        cell.btnVote.tag = indexPath.row
        cell.btnVote.addTarget(self, action: #selector(voteButtonPressed(sender:)), for: .touchUpInside)
        return cell
    


    @objc func voteButtonPressed(sender:UIButton)
    
        let arrdata = self.ArrayData[sender.tag]
        self.myTableview.reloadData()
        let dict = [
            "commandType":"registervote",
            "requestedId":"10"
        ]
        APIManager.sharedInstance.getListOfFeatures(parms: dict, onsuccess:  (responsedata, anymessage) in
            print(responsedata,anymessage)
        )  (error1, error2) in
            print(error1,error2)
        
    

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
        let vc2 = self.storyboard? .instantiateViewController(withIdentifier: "SecendViewController") as! SecendViewController
        let element = self.ArrayData[indexPath.row]
        vc2.arrpass = [element]
        self.navigationController? .pushViewController(vc2, animated: true)
    

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
        return 300
    

4) SecendViewController--------------
-----------------------------------------
-----------------------------------------

import UIKit

class SecendViewController: UIViewController 
    var arrpass = [Data]()
    @IBOutlet weak var uiMainView: UIView!

    @IBOutlet weak var lblFeatureTitile: UILabel!
    override func viewDidLoad() 
        super.viewDidLoad()
        let item = self.arrpass[0]
        self.lblFeatureTitile.text = item.name
        self.uiMainView.layer.cornerRadius = 10
        // Do any additional setup after loading the view.
    

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


5) TheardViewController--------------
-----------------------------------------
-----------------------------------------


import UIKit

class TheardViewController: UIViewController 


    @IBOutlet weak var lblUseCase: UILabel!
    @IBOutlet weak var txtUsecase: UITextView!
    @IBOutlet weak var txtFeatureDescription: UITextView!
    @IBOutlet weak var txtName: UITextField!

    @IBOutlet weak var txtFeatureTitile: UITextField!
    @IBOutlet weak var txtEmail: UITextField!
    let imgselected = UIImage.init(named: "Selected")

    let imgunselected = UIImage.init(named: "Unselected")

    @IBOutlet weak var btnLow: UIButton!
    @IBOutlet weak var btnMedium: UIButton!
    @IBOutlet weak var btnHigh: UIButton!
    var strresult = ""
    override func viewDidLoad() 
        super.viewDidLoad()

        self.btnMedium.setImage(imgunselected, for: .normal)
        self.btnHigh.setImage(imgunselected, for: .normal)
        self.btnLow.setImage(imgunselected, for: .normal)
        // Do any additional setup after loading the view.
    

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

    @IBAction func btnLowPressed(_ sender: UIButton) 

        self.strresult = "L"
        self.btnLow.setImage(imgselected, for: .normal)
        self.btnHigh.setImage(imgunselected, for: .normal)
        self.btnMedium.setImage(imgunselected, for: .normal)
        self.lblUseCase.text = "Use Case"


    
    @IBAction func btnMediumPressed(_ sender: UIButton) 
        self.strresult = "M"
        self.btnMedium.setImage(imgselected, for: .normal)
        self.btnHigh.setImage(imgunselected, for: .normal)
        self.btnLow.setImage(imgunselected, for: .normal)
        self.lblUseCase.text = "Use Case *"

    

    @IBAction func btnHighPressed(_ sender: UIButton) 
        self.strresult = "H"
        self.btnHigh.setImage(imgselected, for: .normal)
        self.btnLow.setImage(imgunselected, for: .normal)
        self.btnMedium.setImage(imgunselected, for: .normal)
        self.lblUseCase.text = "Use Case *"


    
    @IBAction func btnSendReQuest(_ sender: UIButton) 
        var strname = self.txtName.text!
        var stremail = self.txtEmail.text!
        var strtitile = self.txtFeatureTitile.text!
        var strUsecase = self.txtUsecase.text!

        if strname.count <= 0
        
            let alert = UIAlertController(title: "Warning", message: "Please Enter Name", preferredStyle: UIAlertControllerStyle.alert)
            alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil))
            self.present(alert, animated: true, completion: nil)
        
        else if stremail.count <= 0
        
            let alert = UIAlertController(title: "Warning", message: "Please Enter Email", preferredStyle: UIAlertControllerStyle.alert)
            alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
            self.present(alert, animated: true, completion: nil)
        
        else if strtitile.count <= 0
        
            let alert = UIAlertController(title: "Warning", message: "Please Enter Title", preferredStyle: UIAlertControllerStyle.alert)
            alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
            self.present(alert, animated: true, completion: nil)
        
        else if strresult.count <= 0
        
            let alert = UIAlertController(title: "Warning", message: "Please Set Priority", preferredStyle: UIAlertControllerStyle.alert)
            alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
            self.present(alert, animated: true, completion: nil)
        
        else if (((strresult == "H") && (self.txtUsecase.text.count  <= 0)) || (strresult == "M") && (self.txtUsecase.text.count  <= 0)) 

            let alert = UIAlertController(title: "Warning", message: "Please enter uese case.", preferredStyle: UIAlertControllerStyle.alert)
            alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
            self.present(alert, animated: true, completion: nil)
        
        else
        

            let alert = UIAlertController(title: "Success", message: "All Ok", preferredStyle: UIAlertControllerStyle.alert)
            alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
            self.present(alert, animated: true, completion: nil)


        

    


6) APIManager--------------
-----------------------------------------
-----------------------------------------


import UIKit
import ObjectMapper
import Alamofire
class APIManager: NSObject 

    static let sharedInstance = APIManager()


    func getListOfFeatures(parms:[String:Any], onsuccess:@escaping(MainData,String) -> Void, onfailure:@escaping(String,String) ->Void)
    
        let url = URL.init(string: "https://reqres.in/api/unknown")
        let headres: HTTPHeaders = ["content-type":"application/json"]

        Alamofire.request(url!, method: .get, parameters: parms, encoding: JSONEncoding.default, headers: headres).responseJSON
            
                response in
                switch response.result
                case .success:
                    let string = NSString(data: response.data!, encoding: String.Encoding.utf8.rawValue)
                    print("string:\(String(describing: string))")
                    do
                        let jsonResponse = try JSONSerialization.jsonObject(with: response.data!, options: []) as! [String:AnyObject]
                        let userDetails = Mapper<MainData>() .map(JSON: jsonResponse)

                        if jsonResponse != nil
                        
                            onsuccess(userDetails!,"success")
                        
                        else
                        
                            onfailure((response.error?.localizedDescription)!,"fail")
                        
                    
                    catch let parsingError
                    
                        print("error",parsingError)
                        onfailure((response.error?.localizedDescription)!,"fail")
                    
                    break
                case .failure(let error):
                    print(error)
                    onfailure((response.error?.localizedDescription)!,"fail")
                    
        
    

【讨论】:

【参考方案3】:
1) Model Class One--------------
-----------------------------------------
-----------------------------------------

import Foundation
import ObjectMapper

class MainData : NSObject, Mappable 
    var page : Int?
    var per_page : Int?
    var total : Int?
    var total_pages : Int?
    var data : [Data]?
    override init() 

    
    required init?(map: Map) 

    

     func mapping(map: Map) 

        page <- map["page"]
        per_page <- map["per_page"]
        total <- map["total"]
        total_pages <- map["total_pages"]
        data <- map["data"]
    


2) Model Class Two--------------
-----------------------------------------
-----------------------------------------

import Foundation
import ObjectMapper

class Data : NSObject, Mappable 
    var id : Int?
    var name : String?
    var year : Int?
    var color : String?
    var pantone_value : String?
    override init() 

    
    required init?(map: Map) 

    

     func mapping(map: Map) 

        id <- map["id"]
        name <- map["name"]
        year <- map["year"]
        color <- map["color"]
        pantone_value <- map["pantone_value"]
    


3) ViewController--------------
-----------------------------------------
-----------------------------------------


import UIKit

class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate 
       @IBOutlet weak var myTableview: UITableView!

    @IBAction func btnNewFeature(_ sender: UIButton) 
        let vc3 = self.storyboard? .instantiateViewController(withIdentifier: "TheardViewController") as! TheardViewController
        self.navigationController? .pushViewController(vc3, animated: true)


    
    var DictData = MainData()
    var ArrayData = [Data]()

    override func viewDidLoad() 
        super.viewDidLoad()
        self.myTableview.layer.cornerRadius = 10
        getData()

        // Do any additional setup after loading the view, typically from a nib.
    



func getData()

    let dict = [
        "name":"shital",
        "rollno":"1"
    ]
    APIManager.sharedInstance.getListOfFeatures(parms: dict, onsuccess:  (responsedata, anystring) in

        self.DictData = responsedata
        self.ArrayData = self.DictData.data!
        print(self.DictData.page)
        for item in self.ArrayData
        
            print(item.color)
            print(item.id)
            print(item.name)
        
        self.myTableview.reloadData()


    )  (error, error1) in
        print(error,error1)
    

    

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        print(self.ArrayData.count)
        return self.ArrayData.count
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        var cell = myTableview.dequeueReusableCell(withIdentifier: "TableViewCell") as! TableViewCell
       let element = self.ArrayData[indexPath.row]
        let id = "\(element.id!)"
        cell.txtNoofvotes.text = id
        cell.lblFeatureTitle.text = element.name
        cell.lblRequestedName.text = element.name
        cell.txtViewFeatureDesc.text = element.pantone_value
        cell.lblRequestedDate.text = "\(element.year!)"


        if (element.id == 1)
        
            cell.btnVote.setTitle("Voted", for: .normal)
            cell.btnVote.isEnabled = false
        
        else
        
            cell.btnVote.setTitle("Vote", for: .normal)
        
        cell.btnVote.tag = indexPath.row
        cell.btnVote.addTarget(self, action: #selector(voteButtonPressed(sender:)), for: .touchUpInside)
        return cell
    


    @objc func voteButtonPressed(sender:UIButton)
    
        let arrdata = self.ArrayData[sender.tag]
        self.myTableview.reloadData()
        let dict = [
            "commandType":"registervote",
            "requestedId":"10"
        ]
        APIManager.sharedInstance.getListOfFeatures(parms: dict, onsuccess:  (responsedata, anymessage) in
            print(responsedata,anymessage)
        )  (error1, error2) in
            print(error1,error2)
        
    

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
        let vc2 = self.storyboard? .instantiateViewController(withIdentifier: "SecendViewController") as! SecendViewController
        let element = self.ArrayData[indexPath.row]
        vc2.arrpass = [element]
        self.navigationController? .pushViewController(vc2, animated: true)
    

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
        return 300
    

4) SecendViewController--------------
-----------------------------------------
-----------------------------------------

import UIKit

class SecendViewController: UIViewController 
    var arrpass = [Data]()
    @IBOutlet weak var uiMainView: UIView!

    @IBOutlet weak var lblFeatureTitile: UILabel!
    override func viewDidLoad() 
        super.viewDidLoad()
        let item = self.arrpass[0]
        self.lblFeatureTitile.text = item.name
        self.uiMainView.layer.cornerRadius = 10
        // Do any additional setup after loading the view.
    

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


5) TheardViewController--------------
-----------------------------------------
-----------------------------------------


import UIKit

class TheardViewController: UIViewController 


    @IBOutlet weak var lblUseCase: UILabel!
    @IBOutlet weak var txtUsecase: UITextView!
    @IBOutlet weak var txtFeatureDescription: UITextView!
    @IBOutlet weak var txtName: UITextField!

    @IBOutlet weak var txtFeatureTitile: UITextField!
    @IBOutlet weak var txtEmail: UITextField!
    let imgselected = UIImage.init(named: "Selected")

    let imgunselected = UIImage.init(named: "Unselected")

    @IBOutlet weak var btnLow: UIButton!
    @IBOutlet weak var btnMedium: UIButton!
    @IBOutlet weak var btnHigh: UIButton!
    var strresult = ""
    override func viewDidLoad() 
        super.viewDidLoad()

        self.btnMedium.setImage(imgunselected, for: .normal)
        self.btnHigh.setImage(imgunselected, for: .normal)
        self.btnLow.setImage(imgunselected, for: .normal)
        // Do any additional setup after loading the view.
    

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

    @IBAction func btnLowPressed(_ sender: UIButton) 

        self.strresult = "L"
        self.btnLow.setImage(imgselected, for: .normal)
        self.btnHigh.setImage(imgunselected, for: .normal)
        self.btnMedium.setImage(imgunselected, for: .normal)
        self.lblUseCase.text = "Use Case"


    
    @IBAction func btnMediumPressed(_ sender: UIButton) 
        self.strresult = "M"
        self.btnMedium.setImage(imgselected, for: .normal)
        self.btnHigh.setImage(imgunselected, for: .normal)
        self.btnLow.setImage(imgunselected, for: .normal)
        self.lblUseCase.text = "Use Case *"

    

    @IBAction func btnHighPressed(_ sender: UIButton) 
        self.strresult = "H"
        self.btnHigh.setImage(imgselected, for: .normal)
        self.btnLow.setImage(imgunselected, for: .normal)
        self.btnMedium.setImage(imgunselected, for: .normal)
        self.lblUseCase.text = "Use Case *"


    
    @IBAction func btnSendReQuest(_ sender: UIButton) 
        var strname = self.txtName.text!
        var stremail = self.txtEmail.text!
        var strtitile = self.txtFeatureTitile.text!
        var strUsecase = self.txtUsecase.text!

        if strname.count <= 0
        
            let alert = UIAlertController(title: "Warning", message: "Please Enter Name", preferredStyle: UIAlertControllerStyle.alert)
            alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil))
            self.present(alert, animated: true, completion: nil)
        
        else if stremail.count <= 0
        
            let alert = UIAlertController(title: "Warning", message: "Please Enter Email", preferredStyle: UIAlertControllerStyle.alert)
            alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
            self.present(alert, animated: true, completion: nil)
        
        else if strtitile.count <= 0
        
            let alert = UIAlertController(title: "Warning", message: "Please Enter Title", preferredStyle: UIAlertControllerStyle.alert)
            alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
            self.present(alert, animated: true, completion: nil)
        
        else if strresult.count <= 0
        
            let alert = UIAlertController(title: "Warning", message: "Please Set Priority", preferredStyle: UIAlertControllerStyle.alert)
            alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
            self.present(alert, animated: true, completion: nil)
        
        else if (((strresult == "H") && (self.txtUsecase.text.count  <= 0)) || (strresult == "M") && (self.txtUsecase.text.count  <= 0)) 

            let alert = UIAlertController(title: "Warning", message: "Please enter uese case.", preferredStyle: UIAlertControllerStyle.alert)
            alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
            self.present(alert, animated: true, completion: nil)
        
        else
        

            let alert = UIAlertController(title: "Success", message: "All Ok", preferredStyle: UIAlertControllerStyle.alert)
            alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
            self.present(alert, animated: true, completion: nil)


        

    


6) APIManager--------------
-----------------------------------------
-----------------------------------------


import UIKit
import ObjectMapper
import Alamofire
class APIManager: NSObject 

    static let sharedInstance = APIManager()


    func getListOfFeatures(parms:[String:Any], onsuccess:@escaping(MainData,String) -> Void, onfailure:@escaping(String,String) ->Void)
    
        let url = URL.init(string: "https://reqres.in/api/unknown")
        let headres: HTTPHeaders = ["content-type":"application/json"]

        Alamofire.request(url!, method: .get, parameters: parms, encoding: JSONEncoding.default, headers: headres).responseJSON
            
                response in
                switch response.result
                case .success:
                    let string = NSString(data: response.data!, encoding: String.Encoding.utf8.rawValue)
                    print("string:\(String(describing: string))")
                    do
                        let jsonResponse = try JSONSerialization.jsonObject(with: response.data!, options: []) as! [String:AnyObject]
                        let userDetails = Mapper<MainData>() .map(JSON: jsonResponse)

                        if jsonResponse != nil
                        
                            onsuccess(userDetails!,"success")
                        
                        else
                        
                            onfailure((response.error?.localizedDescription)!,"fail")
                        
                    
                    catch let parsingError
                    
                        print("error",parsingError)
                        onfailure((response.error?.localizedDescription)!,"fail")
                    
                    break
                case .failure(let error):
                    print(error)
                    onfailure((response.error?.localizedDescription)!,"fail")
                    
        
    

【讨论】:

以上是关于使用 AlamofireObjectMapper 映射模型 - swift的主要内容,如果未能解决你的问题,请参考以下文章

使用 AlamofireObjectMapper 映射模型 - swift

AlamofireObjectMapper,嵌套的 JSON 结构在序列化时总是 nil

在 AlamofireObjectMapper 响应中映射 allHeaderFields

AlamofireObjectmapper 编码模型属性

如何实例化映射类? (迅速 - alamofireObjectMapper)

AlamofireObjectMapper / ObjectMapper 是不是支持结构类型映射