Swift JSONEncoder: Unterschied zwischen den Versionen

Aus Wikizone
Wechseln zu: Navigation, Suche
 
(Eine dazwischenliegende Version desselben Benutzers wird nicht angezeigt)
Zeile 1: Zeile 1:
 
== Links ==
 
== Links ==
 
  [[Swift (Programmiersprache)]]
 
  [[Swift (Programmiersprache)]]
 +
[[Swift - Decodable & Encodable]]
  
 
== Beispiele ==
 
== Beispiele ==
Zeile 54: Zeile 55:
 
Dieser Code verwendet encoded Data und wandelt es in einen String um, indem es es decodiert und UTF-8 als Encoding verwendet. Wenn die Konvertierung erfolgreich ist, wird der Inhalt des Strings auf der Konsole ausgegeben.
 
Dieser Code verwendet encoded Data und wandelt es in einen String um, indem es es decodiert und UTF-8 als Encoding verwendet. Wenn die Konvertierung erfolgreich ist, wird der Inhalt des Strings auf der Konsole ausgegeben.
 
Es ist zu beachten, dass der JSON String nicht immer lesbar ausfällt, da die Reihenfolge der Werte innerhalb des Objekts oder des Arrays unvorhersehbar ist.
 
Es ist zu beachten, dass der JSON String nicht immer lesbar ausfällt, da die Reihenfolge der Werte innerhalb des Objekts oder des Arrays unvorhersehbar ist.
 +
 +
=== Ausführliches Beispiel mit Fehlerbehandlung ===
 +
Hier werden Daten von openWeather verarbeitet. Es gibt ein Struct, das auf die JSON Daten angepasst ist.
 +
 +
<syntaxhighlight lang="swift">
 +
// WeatherData for decoding JSON
 +
import Foundation
 +
 +
struct WeatherData: Codable{
 +
    let name: String
 +
    let main: Main
 +
    let weather: [Weather]
 +
}
 +
 +
struct Main: Codable{
 +
    let temp: Double
 +
}
 +
struct Weather: Codable{
 +
    let description: String
 +
    let id: Int
 +
}
 +
</syntaxhighlight>
 +
 +
In WeatherManager gibe es ein delegate protocol um später die Infos / Fehler weiterzugeben
 +
 +
Das JSON Parsing nutzt ein WeatherData Objekt um die JSON Infos darin zu speichern.
 +
<syntaxhighlight lang="swift">
 +
import Foundation
 +
import CoreLocation
 +
 +
protocol WeatherManagerDelegate{
 +
    func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel)
 +
    func didFailWithError(error: Error)
 +
}
 +
 +
struct WeatherManager{
 +
   
 +
    let weatherURL = "https://api.openweathermap.org/data/2.5/weather?units=metric&appid=63981dbcfa548021dd77394d24f34674"
 +
   
 +
    var delegate: WeatherManagerDelegate?
 +
   
 +
    func fetchWeather(cityName: String){
 +
        let urlString = "\(weatherURL)&q=\(cityName)"
 +
        performRequest(with: urlString)
 +
    }
 +
   
 +
    func fetchWeather(latitude: CLLocationDegrees, longitude: CLLocationDegrees){
 +
        let urlString = "\(weatherURL)&lat=\(latitude)&lon=\(longitude)"
 +
        performRequest(with: urlString)
 +
    }
 +
   
 +
    func performRequest(with urlString: String){
 +
        // 1. create URL
 +
        let allowedCharacters = CharacterSet.urlQueryAllowed
 +
        let encodedString = urlString.addingPercentEncoding(withAllowedCharacters: allowedCharacters) ?? ""
 +
        if let url = URL(string: encodedString) {
 +
            // 2. create URLSession
 +
            let session = URLSession(configuration: .default)
 +
            // 3. give session a task
 +
            let task = session.dataTask(with: url) { data, response, error in
 +
                if error != nil {
 +
                    delegate?.didFailWithError(error: error!)
 +
                    return
 +
                }
 +
                if let safeData = data {
 +
                    if let weather = self.parseJSON(safeData){
 +
                        self.delegate?.didUpdateWeather(self, weather: weather)
 +
                    }
 +
                }
 +
            }
 +
            // 4. start the task
 +
            task.resume()
 +
        }
 +
    }
 +
   
 +
    func parseJSON(_ weatherData: Data)->WeatherModel? {
 +
        let decoder = JSONDecoder()
 +
        // decode needs a type not an object as parameter. We refer to the type with .self i.e. WeatherData.self
 +
        do {
 +
            let decodedData = try decoder.decode(WeatherData.self, from: weatherData)
 +
            let id = decodedData.weather[0].id
 +
            let temp = decodedData.main.temp
 +
            let name = decodedData.name
 +
           
 +
            let weather = WeatherModel(conditionId: id, cityName: name, temperature: temp)
 +
           
 +
            print( "weatherName (sf-symbol): \(weather.conditionName)")
 +
            print( "temperature: \(weather.temperatureStr)")
 +
           
 +
            return weather
 +
           
 +
        } catch {
 +
            //print("Error parsing JSON: \(error)")
 +
            delegate?.didFailWithError(error: error)
 +
            return nil
 +
        }
 +
    }
 +
   
 +
   
 +
   
 +
}
 +
</syntaxhighlight>
 +
 +
<syntaxhighlight lang="swift">
 +
</syntaxhighlight>

Aktuelle Version vom 21. Januar 2023, 06:06 Uhr

Links[Bearbeiten]

Swift (Programmiersprache)
Swift - Decodable & Encodable

Beispiele[Bearbeiten]

Speichern von JSON Daten mit File I/O[Bearbeiten]

Siehe auch Swift JSONEncoder

struct Setlist: Codable {
    var title: String = "Default"
    var songs = [Song]()

    mutating func addSong(title: String, frequency: Float){
        print("Setlist::addSong")
        songs.append(Song(title:title, frequency: frequency))
    }
}

struct Song: Codable {
    let title: String
    let frequency: Float
}

// convert Setlist to json Data
let setlist = Setlist()
setlist.addSong(title: "song1", frequency: 44.1)
let encoder = JSONEncoder()
guard let encoded = try? encoder.encode(setlist) else {
    print("Encoding Failed")
    return
}

// write json Data to file
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let fileURL = documentsURL.appendingPathComponent("setlist.json")
do {
    try encoded.write(to: fileURL, options: .atomic)
} catch {
    print("Error saving file: \(error)")
}

In diesem Beispiel wird die JSONEncoder Klasse verwendet, um eine Instanz des Structs Setlist in ein JSON-kodiertes Data-Objekt umzuwandeln. Das erzeugte JSON-kodierte Data wird in einer Datei gespeichert . In diesem Fall wird die Datei "setlist.json" im Dokumentenverzeichnis des Geräts gespeichert. Es ist zu beachten, dass es je nach Anwendungsfall sinnvoll sein kann, die Daten an einem anderen Ort oder in einem anderen Format zu speichern.

JSON Data Objekt als String ausgeben[Bearbeiten]

if let jsonString = String(data: encoded, encoding: .utf8) {
    print(jsonString)
} else {
    print("Could not convert encoded Data to String")
}

Dieser Code verwendet encoded Data und wandelt es in einen String um, indem es es decodiert und UTF-8 als Encoding verwendet. Wenn die Konvertierung erfolgreich ist, wird der Inhalt des Strings auf der Konsole ausgegeben. Es ist zu beachten, dass der JSON String nicht immer lesbar ausfällt, da die Reihenfolge der Werte innerhalb des Objekts oder des Arrays unvorhersehbar ist.

Ausführliches Beispiel mit Fehlerbehandlung[Bearbeiten]

Hier werden Daten von openWeather verarbeitet. Es gibt ein Struct, das auf die JSON Daten angepasst ist.

// WeatherData for decoding JSON
import Foundation

struct WeatherData: Codable{
    let name: String
    let main: Main
    let weather: [Weather]
}

struct Main: Codable{
    let temp: Double
}
struct Weather: Codable{
    let description: String
    let id: Int
}

In WeatherManager gibe es ein delegate protocol um später die Infos / Fehler weiterzugeben

Das JSON Parsing nutzt ein WeatherData Objekt um die JSON Infos darin zu speichern.

import Foundation
import CoreLocation

protocol WeatherManagerDelegate{
    func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel)
    func didFailWithError(error: Error)
}

struct WeatherManager{
    
    let weatherURL = "https://api.openweathermap.org/data/2.5/weather?units=metric&appid=63981dbcfa548021dd77394d24f34674"
    
    var delegate: WeatherManagerDelegate?
    
    func fetchWeather(cityName: String){
        let urlString = "\(weatherURL)&q=\(cityName)"
        performRequest(with: urlString)
    }
    
    func fetchWeather(latitude: CLLocationDegrees, longitude: CLLocationDegrees){
        let urlString = "\(weatherURL)&lat=\(latitude)&lon=\(longitude)"
        performRequest(with: urlString)
    }
    
    func performRequest(with urlString: String){
        // 1. create URL
        let allowedCharacters = CharacterSet.urlQueryAllowed
        let encodedString = urlString.addingPercentEncoding(withAllowedCharacters: allowedCharacters) ?? ""
        if let url = URL(string: encodedString) {
            // 2. create URLSession
            let session = URLSession(configuration: .default)
            // 3. give session a task
            let task = session.dataTask(with: url) { data, response, error in
                if error != nil {
                    delegate?.didFailWithError(error: error!)
                    return
                }
                if let safeData = data {
                    if let weather = self.parseJSON(safeData){
                        self.delegate?.didUpdateWeather(self, weather: weather)
                    }
                }
            }
            // 4. start the task
            task.resume()
        }
    }
    
    func parseJSON(_ weatherData: Data)->WeatherModel? {
        let decoder = JSONDecoder()
        // decode needs a type not an object as parameter. We refer to the type with .self i.e. WeatherData.self
        do {
            let decodedData = try decoder.decode(WeatherData.self, from: weatherData)
            let id = decodedData.weather[0].id
            let temp = decodedData.main.temp
            let name = decodedData.name
            
            let weather = WeatherModel(conditionId: id, cityName: name, temperature: temp)
            
            print( "weatherName (sf-symbol): \(weather.conditionName)")
            print( "temperature: \(weather.temperatureStr)")
            
            return weather
            
        } catch {
            //print("Error parsing JSON: \(error)")
            delegate?.didFailWithError(error: error)
            return nil
        }
    }
    
    
    
}