2016-03-06 3 views
1

При получении данных из api я могу получить ответ либо на массив продуктов, либо на словарь с ошибкой, например.Как разобрать неизвестный тип данных json в swift 2

Если все прошло правильно апи посылает множество продуктов, как:

[ 
"Product1": 
{ 
name = "someting", 
price = 100, 
discount = 10%, 
images = [image1,image2] 
}, 
"Product2": 
{ 
name = "someting", 
price = 100, 
discount = 10%, 
images = [image1,image2] 
} 
] 

Но если какая-то ошибка происходит он посылает словарь с сообщением об ошибке и код, как:

{ 
error_message = "message" 
error_code = 202 
} 

Я использую этот код для преобразования данных JSON в массив:

do { 
    let jsonDict = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSArray{ 
       //Some code.... 
    } catch let error as NSError { 
    print("JSON Error: \(error.localizedDescription)")  
} 

, но если я получу ошибку, как словарь, это приведет к сбою.

Проблемы: 1. Как узнать, являются ли полученные данные массивом или словарем? 2. Какое-то время даже ключ или значение может отсутствовать, так проверка значения становится очень длинным код, как:

if let productsArray = jsonObject as? NSArray{ 
    if let product1 = productsArray[0] as? NSDictionary{ 
     if let imagesArray = product1["image"] as? NSArray{ 
      if let imageUrl = imagesArray[0] as? String{ 
       //Code .... 
      } 
     } 
    } 
} 

Я читал о охраннику ключевое слово, чтобы уменьшить, если условие, но у меня нет четкого представления, как использовать здесь.

+0

Как вы получаете в JSON? - Можете ли вы увидеть код статуса ответа HTTP? –

+0

@thefredelement Да, я могу получить код ошибки ответа, который он отправляет моим сервером, специфичным для любого продукта, например, пытается получить недоступную деталь продукта. –

+0

Я бы порекомендовал загрузить библиотеку SwiftyJSON из Github, поэтому вам не нужно иметь 10 уровней вложенных if-let's –

ответ

2

Задача 1: Для попытке поймать, добавьте, если пусть для заливки объекта как NSDictionary или NSArray как:

do { 
    let jsonObject = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) 
    if let jsonDict = jsonObject as? NSDictionary { 
     // Do smthg. 
    } 
    if let jsonArray = jsonObject as? NSArray { 
     // Do smthg. 
    } 
}catch { 
//... 
} 

Для задачи 2: Я думаю, что охранник не поможет. Он нуждается в smthg, как return/break в своем заявлении else. Если вы не хотите бросать свои методы, если одно из ваших значений недоступно, вы должны использовать этот длинный, если хотите, стиль кода. Возможно, в вашем случае лучшей практикой будет создание модели данных для продукта с дополнительными свойствами.

Class product { 
var name:String? 
var image:[NSData]? // maybe UIImage or smthg. 
var price:Int? 
var discount:Int? 

    init(jsonDic:NSDictionary){ 
// if it's not there it would be nil 
    self.name = jsonDic["name"] as? String 
    self.image = jsonDic["image"] as? NSArray 
    self.discount = jsonDic["discount"] as? Int 
    self.price = jsonDic["price"] as? Int 
    } 
} 

Теперь вы можете загрузить эти модели с вашими данными без, если пусть и т.д .. Но если вы хотите прочитать те значения, которые вы должны использовать, если позволить фиксирование, если ее не равен нулю. Для инициализации в вашем случае это должно быть что-то вроде этого: Добавить это в случае пусть заявление блока сделать улова (?. ... в NSArray // DO smthg)

for item in jsonArray { 
    guard let jsonDic = item as? NSDictionary else { return } 
// if you dont know every key you can just iterate through this dictionary 
    for (_,value) in jsonDic { 
     guard let jsonDicValues = value as? NSDictionary else { return } 
     productArray.append(Product(jsonDic: jsonDicValues) 
    } 
} 

Как я сказал, знаете, что у вас есть целое, если пусть материал при чтении с модели не при написании (чтение json)

+0

Хорошо, у меня есть sol для problem1 by малое изменение, например, добавление else до второго, если это поможет мне выполнить либо словарь, либо часть массива –

+0

Да, все в порядке, bcz оба не могут получить правду (не ноль) –

+0

Это поможет мне, если вы дадите, например, while хранение данных в продукте модели данных, потому что даже с использованием модели данных я должен проверять –

0

Вы можете поймать класс своего ответа. Если ваш ответ является своего рода словарем класса, назначьте его в качестве словаря else, если ваш ответ является видом массива классов, назначьте его массиву. Удачи.

+0

Я знаю, как это сделать в Objective-C, но я не в swift –

1

У вас есть несколько вещей, здесь происходит, один, я бы проанализировать код состояния ответа HTTP вашего сервера и только попытаться обработать данные, если вы получили код статуса вы будете иметь хорошие данные

// In practical scenarios, this may be a range 
if statusCode != 200 { 
// Handle a scenario where you don't have good data. 
return 
} 

Во-вторых Я бы защититься от ответа, он выглядит, как вы назвали его «данные», как так:

guard let receivedData = data else { 
return 
} 

с этого момента, вы можете использовать константу receivedData.

Here'd Я бы попытаться использовать NSJSONSeralization, как вы это делаете, но, бросая его в Swift словарь, например, так:

if let responseDictionary = try? NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? [String:AnyObject] { 

// Here you can try to access keys on the response 
// You can try things like 
let products = responseDictionary?["products"] as? [[String:AnyObject]] 

for product in products { 

    let productName = product["name"] as? String 

    if productName == nil { 
    continue 
    } 

    let newProduct = Product(name: productName) 
    // Do something with newly processed data 

} 

} 

Я пытался быть общими, а также показать вам пример охранника ,

1

Прежде всего, я рекомендую использовать SwiftyJSON pod или класс прямо в ваш Xcode, он работает как шарм, и вы выиграли Не нужно бросать вещи, чтобы понять, есть ли у вас строка или словарь или что-то еще. Это золото.

Как только у вас есть JSON, вы можете использовать эту рекурсивную функцию, которую я создал, которая делает именно то, что вам нужно. Он превращает любого Json в словарь. В основном я использую его для сохранения данных в Firebase, без необходимости разбирать все.

После импорта SwiftyJSON в свой проект и добавил импорта SwiftyJSON в свой Swift файл вы можете:

let json = JSON(value) // Value is the json structure you received from API. 
var myDictionary = [String:AnyObject]() 
myDictionary = json2dic(json) 

//JSON is created using the awesome SwiftyJSON pod 
func json2dic(j: JSON) -> [String:AnyObject] { 
    var post = [String:AnyObject]() 
    for (key, object) in j { 
     post[key] = object.stringValue 
     if object.stringValue == "" { 
      post[key] = json2dic(object) 
     } 
    } 
    return post 
} 
Смежные вопросы