我尝试在我的代码中使用可选绑定但是当我执行和调试时它仍然是nil,所以我想知道我是否使用了错误的方法?
Here is the code which shows me trying to parse my JSON
这是我用来尝试解析我的JSON的代码:
import Foundation
protocol ListingModelProtocol: class {
func itemsDownloaded(items: NSArray)
}
class ListingModel: NSObject, NSURLSessionDataDelegate {
weak var delegate: ListingModelProtocol!
var data : NSMutableData = NSMutableData()
let urlPath: String = "http://booksmart.hol.es/service.php" // this will be changed to the path where service.php lives
func downloadItems() {
let url: NSURL = NSURL(string: urlPath)!
var session: NSURLSession!
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)
let task = session.dataTaskWithURL(url)
task.resume()
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
self.data.appendData(data);
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
if error != nil {
print("Failed to download data")
}else {
print("Data downloaded")
self.parseJSON()
}
}
func parseJSON() {
var jsonResult: NSMutableArray = NSMutableArray()
do{
jsonResult = try NSJSONSerialization.JSONObjectWithData(self.data, options:NSJSONReadingOptions.AllowFragments) as! NSMutableArray
} catch let error as NSError {
print(error)
}
var jsonElement: NSDictionary = NSDictionary()
let properties: NSMutableArray = NSMutableArray()
for(var i = 0; i < jsonResult.count; i+=1)
{
jsonElement = jsonResult[i] as! NSDictionary
let property = PropertyModel()
//the following insures none of the JsonElement values are nil through optional binding
if let propertyType = jsonElement["Property Type"] as? String,
let price = jsonElement["Price"] as? String,
let distance = jsonElement["Distance"] as? String
{
property.propertyType = propertyType
property.price = price
property.distance = distance
}
properties.addObject(property)
}
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.delegate.itemsDownloaded(properties)
})
}
}
这是我用来从我的数据库下载数据的代码:
import Foundation
class PropertyModel: NSObject {
//properties
var propertyType: String?
var price: String?
var distance: String?
//empty constructor
override init()
{
}
//construct with @propertyType, @price and @distance parameters
init(propertyType: String, price: String, distance: String) {
self.propertyType = propertyType
self.price = price
self.distance = distance
}
//prints object's current state
override var description: String {
return "Property Type: \(propertyType), Price: \(price), Distance: \(distance)"
}
}
最后这里是我用来尝试将其转换为swift中的表格单元格的代码:
import UIKit
class First_ResultsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, ListingModelProtocol {
//Properties
var feedItems: NSArray = NSArray()
var selectedProperties : PropertyModel = PropertyModel()
@IBOutlet weak var PropertyListTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
//set delegates and initialize homeModel
self.PropertyListTableView.delegate = self
self.PropertyListTableView.dataSource = self
let listingModel = ListingModel()
listingModel.delegate = self
listingModel.downloadItems()
// Do any additional setup after loading the view.
}
func itemsDownloaded(items: NSArray) {
feedItems = items
self.PropertyListTableView.reloadData()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of feed items
return feedItems.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Retrieve cell
let cellIdentifier: String = "BasicCell"
let myCell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier)!
// Get the location to be shown
let item: PropertyModel = feedItems[indexPath.row] as! PropertyModel
// Get references to labels of cell
myCell.textLabel!.text = item.propertyType
return myCell
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
答案 0 :(得分:0)
您正在使用可选的绑定条件(if let
)来检索那些json值,如果它们不是nil并且类型正确。
但是如果不是这种情况并且一个或多个json密钥丢失或包含错误类型的值会发生什么?它看起来是空的PropertyModel
仍然会添加到您的properties
数组中,但由于propertyType
,price
和distance
从未设置(并且听起来它们是可选的),它们的默认值很可能是零。
您应该将行properties.addObject(property)
向上移动到if let
条件块内(直接位于property.distance = distance
及}
之上)。然后,您不会将任何带有nil值的PropertyModel添加到您的数组中。
答案 1 :(得分:0)
您发布的以下代码和评论不正确。
nil
以上并不能确保这些值不是if
。您的nil
语句正在检查如果所有jsonElement都不是if
,那么它将进入并设置您的属性。
此外,如果上述任何属性不是ur json响应中的String,则不会输入as? Double
语句。您应该使用您返回的类型进行检查。用您的json响应返回的类型替换if let propertyType = jsonElement["Property Type"] as? String,
let price = jsonElement["Price"] as? Double,
let distance = jsonElement["Distance"] as? Double {
property.propertyType = propertyType
property.price = "\(price)"
property.distance = "\(distance)"
}
。
nil
如果要在as String ?? ""
时将其设置为空字符串,则应使用//the following ensure that when the element is nil, we change it to a empty string and update our attributes
let propertyType = jsonElement["Property Type"] as? String ?? ""
let price = jsonElement["Price"] as? String ?? ""
let distance = jsonElement["Distance"] as? String? ??
property.propertyType = propertyType
property.price = price
property.distance = distance
。
if
您不再需要'
声明,因为它不会是零。