Преобразование JSON из AlamoFire/SwiftyJSON в словарь в Swift/Xcode

Моя голова взорвется :) - Я пытался получить строку JSON с моего сервера в значение словаря, и я не могу заставить ее работать.

Я пытаюсь получить (с моего сервера - он динамический, и я хочу, чтобы мое приложение могло при необходимости извлекать новые данные с сервера):

{"1":"Location 1","2":"Location 2","3":"Location 3"}

К этому словарю в Xcode с использованием Swift:

  var labels = [

        1 : "Location 1",
        2 : "Location 2",
        3 : "Location 3"

    ]

Это должно быть довольно прямолинейно, но, хоть убей, я не могу этого понять...

Вот мой Swift — я могу заставить его вытягивать информацию с сервера, но я не могу вставить ее в словарь, как мне нужно

var postEndpoint: String = "http://www.myserver.net/app/campus.php"

    Alamofire.request(.GET, postEndpoint)
        .responseJSON { (request, response, data, error) in
            if let anError = error
            {
                println("error")
                println(error)
            }
            else if let data: AnyObject = data 
            {
                 let post = JSON(data)
                 println(post)
            }
    }

что приводит к:

{
  "1" : "Location 1",
  "2" : "Location 2",
  "3" : "Location 3"
}

Конечным результатом, для которого я это использую, является реализация iBeacon со следующим кодом:

 let knownBeacons = beacons.filter{ $0.proximity != CLProximity.Unknown }
    if (knownBeacons.count > 0) {
        let closestBeacon = knownBeacons[0] as CLBeacon

        let locationID = post[closestBeacon.minor.integerValue]

        self.locationLabel.text = locationID
        self.view.backgroundColor = self.colors[closestBeacon.minor.integerValue]
    }

Я получаю сообщение об ошибке: self.locationLabel.text = locationID «JSON» не может быть преобразован в «String», я не получаю эту ошибку, когда использую словарь статических меток var. Я пытаюсь получить данные с сервера неправильно? Что я делаю не так??? Я думаю, что метки var с необъявленным типом позволяют Swift понять, что ему нужно, как мне сделать то же самое из части JSON?


person davidbii    schedule 04.03.2015    source источник


Ответы (4)


О, ты был так близок!

Ваша проблема в том, что ваш post словарь является [String: String], а не [Int: String], как вы думаете. У вас есть несколько способов исправить это, но на данный момент проще всего сделать следующее:

let locationID = post[String(closestBeacon.minor.integerValue)]!

Хотя это, безусловно, сработает, лучшим решением было бы преобразовать ваш post в словарь, типизированный [Int: String], как вы ожидаете в замыкании responseJSON. Вот как это может работать.

let json = JSON(data)
var post = [Int: String]()

for (key, object) in json {
    post[key.toInt()!] = object.stringValue
}

Вы хотели бы добавить некоторую безопасность в отношении того, что делать, если key или object нельзя преобразовать в Int или String соответственно, но я оставлю это на ваше усмотрение.

person cnoon    schedule 05.03.2015
comment
Спасибо! Как бы я отобразил это? Извините, я совершенно новичок в Swift. - person davidbii; 07.03.2015
comment
Привет @davidbii, я обновил свой ответ, чтобы показать, как преобразовать объект json в словарь [Int: String]. - person cnoon; 07.03.2015
comment
Есть ли рекурсивный способ, если мой json «глубже»? Результат в [String: AnyObject] - person OrangePot; 04.01.2018

Если кому-то достаточно [String: String], он может попробовать следующий код:

let responseString = "{\"1\":\"Location 1\",\"2\":\"Location 2\",\"3\":\"Location 3\"}"

if let dataFromString = responseString.data(using: String.Encoding.utf8, allowLossyConversion: false) {

    let json = JSON(data: dataFromString)

    var labels = json.dictionaryObject! as! [String: String]

    print(labels)
}

Результат: ["2": "Location 2", "1": "Location 1", "3": "Location 3"].

person Ali Momen Sani    schedule 03.10.2016

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

closestBeacon.minor.integerValue

А затем получить строку, которая мне нужна, с сервера, и это решило мою проблему. По-прежнему имеет такое же количество обращений к серверу, поэтому никаких дополнительных накладных расходов не добавляется. Иногда вам просто нужно мыслить нестандартно, в которые вы себя ставите.

Если кто-нибудь может решить это в другом направлении, я все еще хочу услышать, как это может работать.

person davidbii    schedule 04.03.2015

Вам также необходимо рекурсивно проверить внутренний JSON. Используйте функцию ниже для преобразования в словарь или массив.

static func toDictionary(from: JSON) -> Any? {
    if from.type == .array {
        var array = [Any]()
        for _i in 0..<from.count {
            array.append(toDictionary(from: from[_i]) as Any)
        }
        return array
    } else if from.type == .dictionary {
        var dictionary = [String: Any]()
        for (key, value) in from {
            dictionary[key] = toDictionary(from: value)
        }
        return dictionary
    } else {
        return from.stringValue
    }
}
person Community    schedule 24.03.2021
comment
поймите, что у вас там много кода, но это ответ на вопрос OP или просто руководство по хорошей практике. Пожалуйста, обновите свой ответ - чтобы сослаться на решение (а затем включить передовую практику) ИЛИ преобразовать в ответ. - person Mr R; 25.03.2021