retrieve values from firestore's struct in swift - ios

I'm querying some data from my firestore,and I put it in my Usersdata,
but I dont know how to get my values from Usersdata.
Please help me to query my data!
This is my struct base on Firestroe example
struct Usersdata {
let uid:String?
let facebook:String?
let google:String?
let name:String?
let age:Int?
let birthday:String?
let smokeage:Int?
let smokeaddiction:Int?
let smokebrand:String?
let gold:Int?
let score:Int?
let fish:Int?
let shit:Int?
let userimage:String?
init?(dictionary: [String: Any]) {
guard let uid = dictionary["uid"] as? String else { return nil }
self.uid = uid
self.facebook = dictionary["facebook"] as? String
self.google = dictionary["google"] as? String
self.name = dictionary["name"] as? String
self.age = dictionary["age"] as? Int
self.birthday = dictionary["birthday"] as? String
self.smokeage = dictionary["smokeage"] as? Int
self.smokeaddiction = dictionary["smokeaddiction"] as? Int
self.smokebrand = dictionary["smokebrand"] as? String
self.gold = dictionary["gold"] as? Int
self.score = dictionary["score"] as? Int
self.fish = dictionary["fish"] as? Int
self.shit = dictionary["shit"] as? Int
self.userimage = dictionary["userimage"] as? String
}
}
this is my function to query data from firebase
func test(schema:String , collection:String , document : String){
let queryRef = db.collection("Users").document(userID).collection(collection).document(document)
queryRef.getDocument { (document, error) in
if let user = document.flatMap({
$0.data().flatMap({ (data) in
return Usersdata(dictionary: data)
})
}) {
print("Success \(user)")
} else {
print("Document does not exist")
}
}
}

I think you are asking how to work with a structure with Firebase data. Here's a solution that will read in a known user, populate a structure with that data and then print the uid and name.
Assume a stucture
Users
uid_0
name: "Henry"
and then a structure to hold that data
struct Usersdata {
let uid:String?
let user_name:String?
init(aDoc: DocumentSnapshot) {
self.uid = aDoc.documentID
self.user_name = aDoc.get("name") as? String ?? ""
}
}
and a function to read that user, populate the struct and print out data from the struct
func readAUser() {
let docRef = self.db.collection("Users").document("uid_0")
docRef.getDocument { (document, error) in
if let document = document, document.exists {
let aUser = Usersdata(aDoc: document)
print(aUser.uid, aUser.user_name)
} else {
print("Document does not exist")
}
}
}
and the output
uid_0 Henry

Related

How do I return an object from a document stored in Firestore (Swift)

I have a users collection in firebase and a user struct. I need to write a function that takes in the user's id and returns the corresponding user object:
struct AppUser: Codable {
var id: String
var displayName: String
var photoURL: String
var points: Int?
var knownLanguageCodes: Set<String>?
}
This is my function that I have so far.
func getUser(id: String) -> AppUser? {
let db = Firestore.firestore()
let userRef = db.collection("users").document(id)
userRef.getDocument { (document, error) in
if let document = document, document.exists {
let userID = document.data()?["id"] as! String
let userDisplayName = document.data()?["displayName"] as! String
let userPhotoURL = document.data()?["photoURL"] as! String
let userPoints = document.data()?["points"] as! Int?
let userKnownLanguageCodes = document.data()?["knownLanguageCode"] as! Set<String>?
let user = AppUser(id: userID,
displayName: userDisplayName,
photoURL: userPhotoURL,
points: userPoints,
knownLanguageCodes: userKnownLanguageCodes)
return user
} else {
print("Error getting user")
return nil
}
}
}
Both of the return statements above give the error: Unexpected non-void return value in void function
I have looked at the code here https://cloud.google.com/firestore/docs/query-data/get-data under the heading 'Custom objects' and it doesn't seem to work for me. I get the error: Value of type 'NSObject' has no member 'data'. This is produced on line 6 of the code in the link.
You can't return inside a closure use a completion like
func getUser(id: String,completion:#escaping((AppUser?) -> ())) {
let db = Firestore.firestore()
let userRef = db.collection("users").document(id)
userRef.getDocument { (document, error) in
if let document = document, document.exists {
let userID = document.data()?["id"] as! String
let userDisplayName = document.data()?["displayName"] as! String
let userPhotoURL = document.data()?["photoURL"] as! String
let userPoints = document.data()?["points"] as! Int?
let userKnownLanguageCodes = document.data()?["knownLanguageCode"] as! Set<String>?
let user = AppUser(id: userID,
displayName: userDisplayName,
photoURL: userPhotoURL,
points: userPoints,
knownLanguageCodes: userKnownLanguageCodes)
completion(user)
} else {
print("Error getting user")
completion(nil)
}
}
}
Call
getUser(id:<#str#>) { user in
print(user)
}

AddSnapShotListener is repeating the document reading in one instance

When I am using addSnapshotListener for realtime updates, the documents are repeated which should not be the case, but when using getDocuments() the documents are repeated once only, I need to use addSnaphotListener but not want to duplicate the document reading, please assist where I am wrong in using snapshot listener.
I am using Firestore database in Swift iOS. Below is the code I am using
Code with addSnapShotListener():
func getComments() {
//print(postId + "received")
let commentsRef = Firestore.firestore().collection("posts").document(postId).collection("comments")
commentsRef.addSnapshotListener { (snapshot, error) in
if let error = error {
print(error.localizedDescription)
} else {
if let snapshot = snapshot {
for document in snapshot.documents {
// self.length = snapshot.count
let data = document.data()
let username = data["comment_author_username"] as? String ?? ""
let comment = data["comment_author_comment"] as? String ?? ""
let spinnerC = data["comment_author_spinnerC"] as? String ?? ""
let fullname = data["comment_author_fullname"] as? String ?? ""
let email = data["comment_author_email"] as? String ?? ""
let commentUserImageUrl = data["comment_user_image"] as? String ?? ""
let commentuser_id = data["comment_author_id"] as? String ?? ""
self.checkl1value = data["l1"] as? Bool
let newComment = Comment(_documentId: document.documentID, _commentAuthorUsername: username, _commentAuthorFullName: fullname, _commentAuthorComment: comment, _commentUserImage: commentUserImageUrl, _commentAuthorSpinnerC: spinnerC, _commentAuthorId:commentuser_id, _checkl1value: self.checkl1value)
self.comments.append(newComment)
// print(self.length!)
}
self.tableView.reloadData()
}
}
}
}
Code With getDocuments():
func getComments() {
//print(postId + "received")
let commentsRef = Firestore.firestore().collection("posts").document(postId).collection("comments")
commentsRef.getDocuments { (snapshot, error) in
if let error = error {
print(error.localizedDescription)
} else {
if let snapshot = snapshot {
for document in snapshot.documents {
// self.length = snapshot.count
let data = document.data()
let username = data["comment_author_username"] as? String ?? ""
let comment = data["comment_author_comment"] as? String ?? ""
let spinnerC = data["comment_author_spinnerC"] as? String ?? ""
let fullname = data["comment_author_fullname"] as? String ?? ""
let email = data["comment_author_email"] as? String ?? ""
let commentUserImageUrl = data["comment_user_image"] as? String ?? ""
let commentuser_id = data["comment_author_id"] as? String ?? ""
self.checkl1value = data["l1"] as? Bool
let newComment = Comment(_documentId: document.documentID, _commentAuthorUsername: username, _commentAuthorFullName: fullname, _commentAuthorComment: comment, _commentUserImage: commentUserImageUrl, _commentAuthorSpinnerC: spinnerC, _commentAuthorId:commentuser_id, _checkl1value: self.checkl1value)
self.comments.append(newComment)
// print(self.length!)
}
self.tableView.reloadData()
}
}
}
}
You're probably looking to only handle the changes between the snapshots. To do that you'll want to loop over instead of, as shown in the documentation on viewing changes between snapshots:
db.collection("cities").whereField("state", isEqualTo: "CA")
.addSnapshotListener { querySnapshot, error in
guard let snapshot = querySnapshot else {
print("Error fetching snapshots: \(error!)")
return
}
snapshot.documentChanges.forEach { diff in
if (diff.type == .added) {
print("New city: \(diff.document.data())")
}
if (diff.type == .modified) {
print("Modified city: \(diff.document.data())")
}
if (diff.type == .removed) {
print("Removed city: \(diff.document.data())")
}
}
}
Initially your listener will get called with diff.type == .added for each existing document, and then when there are changes it'll get called with the right mix of types.

Nil in OpenWeather API

I've just started to learn Swift and iOS and I have problem in my weather app. I'm trying to get weather data and print in console, but there is still nil and I no have idea what could be wrong. I tried to change the model, pasted all url and is still nil. Sometimes app sends data and there is no answer, but at other times is answer or no sending, no answer. In console always nil...
Generated model class:
import Foundation
class CurrentWeather : NSObject, NSCoding{
var base : String!
var clouds : Cloud!
var cod : Int!
var coord : Coord!
var dt : Int!
var id : Int!
var main : Main!
var name : String!
var sys : Sy!
var visibility : Int!
var weather : [Weather]!
var wind : Wind!
/**
* Instantiate the instance using the passed dictionary values to set the properties values
*/
init(fromDictionary dictionary: [String:Any]){
base = dictionary["base"] as? String
cod = dictionary["cod"] as? Int
dt = dictionary["dt"] as? Int
id = dictionary["id"] as? Int
name = dictionary["name"] as? String
visibility = dictionary["visibility"] as? Int
if let cloudsData = dictionary["clouds"] as? [String:Any]{
clouds = Cloud(fromDictionary: cloudsData)
}
if let coordData = dictionary["coord"] as? [String:Any]{
coord = Coord(fromDictionary: coordData)
}
if let mainData = dictionary["main"] as? [String:Any]{
main = Main(fromDictionary: mainData)
}
if let sysData = dictionary["sys"] as? [String:Any]{
sys = Sy(fromDictionary: sysData)
}
if let windData = dictionary["wind"] as? [String:Any]{
wind = Wind(fromDictionary: windData)
}
weather = [Weather]()
if let weatherArray = dictionary["weather"] as? [[String:Any]]{
for dic in weatherArray{
let value = Weather(fromDictionary: dic)
weather.append(value)
}
}
}
/**
* Returns all the available property values in the form of [String:Any] object where the key is the approperiate json key and the value is the value of the corresponding property
*/
func toDictionary() -> [String:Any]
{
var dictionary = [String:Any]()
if base != nil{
dictionary["base"] = base
}
if cod != nil{
dictionary["cod"] = cod
}
if dt != nil{
dictionary["dt"] = dt
}
if id != nil{
dictionary["id"] = id
}
if name != nil{
dictionary["name"] = name
}
if visibility != nil{
dictionary["visibility"] = visibility
}
if clouds != nil{
dictionary["clouds"] = clouds.toDictionary()
}
if coord != nil{
dictionary["coord"] = coord.toDictionary()
}
if main != nil{
dictionary["main"] = main.toDictionary()
}
if sys != nil{
dictionary["sys"] = sys.toDictionary()
}
if wind != nil{
dictionary["wind"] = wind.toDictionary()
}
if weather != nil{
var dictionaryElements = [[String:Any]]()
for weatherElement in weather {
dictionaryElements.append(weatherElement.toDictionary())
}
dictionary["weather"] = dictionaryElements
}
return dictionary
}
/**
* NSCoding required initializer.
* Fills the data from the passed decoder
*/
#objc required init(coder aDecoder: NSCoder)
{
base = aDecoder.decodeObject(forKey: "base") as? String
clouds = aDecoder.decodeObject(forKey: "clouds") as? Cloud
cod = aDecoder.decodeObject(forKey: "cod") as? Int
coord = aDecoder.decodeObject(forKey: "coord") as? Coord
dt = aDecoder.decodeObject(forKey: "dt") as? Int
id = aDecoder.decodeObject(forKey: "id") as? Int
main = aDecoder.decodeObject(forKey: "main") as? Main
name = aDecoder.decodeObject(forKey: "name") as? String
sys = aDecoder.decodeObject(forKey: "sys") as? Sy
visibility = aDecoder.decodeObject(forKey: "visibility") as? Int
weather = aDecoder.decodeObject(forKey: "weather") as? [Weather]
wind = aDecoder.decodeObject(forKey: "wind") as? Wind
}
/**
* NSCoding required method.
* Encodes mode properties into the decoder
*/
#objc func encode(with aCoder: NSCoder)
{
if base != nil{
aCoder.encode(base, forKey: "base")
}
if clouds != nil{
aCoder.encode(clouds, forKey: "clouds")
}
if cod != nil{
aCoder.encode(cod, forKey: "cod")
}
if coord != nil{
aCoder.encode(coord, forKey: "coord")
}
if dt != nil{
aCoder.encode(dt, forKey: "dt")
}
if id != nil{
aCoder.encode(id, forKey: "id")
}
if main != nil{
aCoder.encode(main, forKey: "main")
}
if name != nil{
aCoder.encode(name, forKey: "name")
}
if sys != nil{
aCoder.encode(sys, forKey: "sys")
}
if visibility != nil{
aCoder.encode(visibility, forKey: "visibility")
}
if weather != nil{
aCoder.encode(weather, forKey: "weather")
}
if wind != nil{
aCoder.encode(wind, forKey: "wind")
}
}
}
WeatherService:
import Foundation
class WeatherSerice {
let weatherAPIKey: String
let weatherBaseURL: URL?
init(APIKey: String) {
self.weatherAPIKey = APIKey
weatherBaseURL = URL(string: "https://api.openweathermap.org/data/2.5/weather?")
}
func getCurrentWeather(city: String, completion: #escaping (CurrentWeather?) -> Void) {
if let weatherURL = URL(string: "\(weatherBaseURL!)q=\(city)&appid=\(weatherAPIKey)") {
let networkProcessor = NetworkProcessor(url: weatherURL)
networkProcessor.downloadJSONFromURL({(jsonDictionary) in
if let currentWeatherDictionary = jsonDictionary?["currently"] as?
[String : Any] {
let currentWeather = CurrentWeather(fromDictionary: currentWeatherDictionary)
completion(currentWeather)
} else {
completion(nil)
}
})
}
}
}
Part of the UIViewController:
let weatherService = WeatherSerice(APIKey: "52e6ff60bba8613b4850e065dcd3d0ac")
weatherService.getCurrentWeather(city: "London") {
(currentWeather) in
print (currentWeather)
}
Please, please drop NSCoding in favor of Codable, you will get rid of all that ugly boilerplate code
struct WeatherData : Decodable {
let coord : Coordinate
let cod, visibility, id : Int
let name : String
let base : String
let weather : [Weather]
let clouds: Clouds
let sys : Sys
let main : Main
let wind : Wind
let dt : Date
}
struct Coordinate : Decodable {
let lat, lon : Double
}
struct Weather : Decodable {
let id : Int
let icon : String
let main : MainEnum
let description: String
}
struct Sys : Decodable {
let type, id : Int
let sunrise, sunset : Date
let message : Double
let country : String
}
struct Main : Decodable {
let temp, tempMin, tempMax : Double
let pressure, humidity : Int
}
struct Wind : Decodable {
let speed : Double
let deg : Int
let gust : Double?
}
struct Clouds: Decodable {
let all: Int
}
enum MainEnum: String, Decodable {
case clear = "Clear"
case clouds = "Clouds"
case rain = "Rain"
}
As you can see the dates are decoded as Date and the main values in Weather are decoded as enum.
I don't know the API NetworkProcessor so I replaced it with traditional URLSession. The added URLComponents provide proper URL encoding for example if the city contains space characters
import Foundation
class WeatherSerice {
let weatherAPIKey: String
let weatherBase = "https://api.openweathermap.org/data/2.5/weather"
init(APIKey: String) {
self.weatherAPIKey = APIKey
}
func getCurrentWeather(city: String, completion: #escaping (WeatherData?) -> Void) {
var urlComponents = URLComponents(string: weatherBase)!
let queryItems = [URLQueryItem(name: "q", value: city),
URLQueryItem(name: "appid", value: weatherAPIKey)]
urlComponents.queryItems = queryItems
if let weatherURL = urlComponents.url {
let task = URLSession.shared.dataTask(with: weatherURL) { (data, response, error) in
if let error = error { print(error); completion(nil) }
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .secondsSince1970
let result = try decoder.decode(WeatherData.self, from: data!)
completion(result)
} catch {
print(error)
completion(nil)
}
}
task.resume()
}
}
}
I recommend to use the new Result type in Swift 5 to return the error, too.
func getCurrentWeather(city: String, completion: #escaping (Result<WeatherData,Error>) -> Void) {
var urlComponents = URLComponents(string: weatherBase)!
let queryItems = [URLQueryItem(name: "q", value: city),
URLQueryItem(name: "appid", value: weatherAPIKey)]
urlComponents.queryItems = queryItems
if let weatherURL = urlComponents.url {
let task = URLSession.shared.dataTask(with: weatherURL) { (data, response, error) in
if let error = error { completion(.failure(error)) }
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .secondsSince1970
let result = try decoder.decode(WeatherData.self, from: data!)
completion(.success(result))
} catch {
completion(.failure(error))
}
}
task.resume()
}
and use it
weatherService.getCurrentWeather(city: "London") { result in
switch result {
case .success(let result): print(result)
case .failure(let error): print(error)
}
}

How to write model class for json data with dictionary?

In this class already i had written model class but here some of the data has been added newly but i am trying to create for the model class for remaining dictionaries but unable to implement it can anyone help me how to implement it ?
In this already i had implemented model class for items array and here i need to create a model class for search criteria dictionary and inside arrays
func listCategoryDownloadJsonWithURL() {
let url = URL(string: listPageUrl)!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil { print(error!); return }
do {
if let jsonObj = try JSONSerialization.jsonObject(with: data!) as? [String:Any] {
let objArr = jsonObj["items"] as? [[String:Any]]
self.list = objArr!.map{List(dict: $0)}
DispatchQueue.main.async {
let itemsCount = self.list.count
for i in 0..<itemsCount {
let customAttribute = self.list[i].customAttribute
for j in 0..<customAttribute.count {
if customAttribute[j].attributeCode == "image" {
let baseUrl = "http://192.168.1.11/magento2/pub/media/catalog/product"
self.listCategoryImageArray.append(baseUrl + customAttribute[j].value)
}
}
}
self.activityIndicator.stopAnimating()
self.activityIndicator.hidesWhenStopped = true
self.collectionView.reloadData()
self.collectionView.isHidden = false
self.tableView.reloadData()
}
}
} catch {
print(error)
}
}
task.resume()
}
struct List {
let name : String
let sku : Any
let id : Int
let attributeSetId : Int
let price : Int
let status : Int
let visibility : Int
let typeId: String
let createdAt : Any
let updatedAt : Any
var customAttribute = [ListAttribute]()
init(dict : [String:Any]) {
if let customAttribute = dict["custom_attributes"] as? [[String: AnyObject]] {
var result = [ListAttribute]()
for obj in customAttribute {
result.append(ListAttribute(json: obj as! [String : String])!)
}
self.customAttribute = result
} else {
self.customAttribute = [ListAttribute]()
}
self.name = (dict["name"] as? String)!
self.sku = dict["sku"]!
self.id = (dict["id"] as? Int)!
self.attributeSetId = (dict["attribute_set_id"] as? Int)!
self.price = (dict["price"] as? Int)!
self.status = (dict["status"] as? Int)!
self.visibility = (dict["visibility"] as? Int)!
self.typeId = (dict["type_id"] as? String)!
self.createdAt = dict["created_at"]!
self.updatedAt = dict["updated_at"]!
}
}
struct ListAttribute {
let attributeCode : String
let value : String
init?(json : [String:String]) {
self.attributeCode = (json["attribute_code"])!
self.value = (json["value"])!
}
}

Access array of dictionaries Swift 3

I need to access the work data which is inside an array of dictionaries and I'm a little bit confuse with this. I'm using swift 3. Some one can give-me some piece of coding to make it done?
I'm using this
let work: NSArray! = fbData.value(forKey: "work") as! NSArray
if let position: NSArray = work[0] as! NSArray {
let positionName: String = position.value(forKey: "name") as! String
self.userWorkExpLabel.text = "\(positionName)" as String
}
but I'm having this answer:
Could not cast value of type '__NSDictionaryI' (0x1106c7288) to 'NSArray' (0x1106c6e28).
there's the API
{
"work": [
{
"employer": {
"id": "93643283467",
"name": "Oracast"
},
"location": {
"id": "111983945494775",
"name": "Calgary, Alberta"
},
"position": {
"id": "146883511988628",
"name": "Mobile Developer"
},
"start_date": "2017-04-30",
"id": "1446626725564198"
}
],
Ok guys. I tried what you posted and what I have now is something like this:
a structs class:
import Foundation
struct Worker{
let employer: Employer
let location: Location
let position: Position
let startDate:String
let id: String
init?(fromDict dict: Dictionary<String, Any>){
guard let employer = Employer(fromDict: dict["employer"] as? Dictionary<String, String>),
let location = Location(fromDict: dict["location"] as? Dictionary<String, String>),
let position = Position(fromDict: dict["position"] as? Dictionary<String, String>),
let startDate = dict["start_date"] as? String,
let id = dict["id"] as? String else {
return nil
}
self.employer = employer
self.location = location
self.position = position
self.startDate = startDate
self.id = id
}
}
struct Employer{
let id: String
let name: String
init?(fromDict dict:Dictionary<String, String>?){
guard let id = dict?["id"],
let name = dict?["name"] else{
return nil
}
self.id = id
self.name = name
}
}
struct Location {
let id:String
let name:String
init?(fromDict dict:Dictionary<String, String>?) {
guard let id = dict?["id"],
let name = dict?["name"] else {
return nil
}
self.id = id
self.name = name
}
}
struct Position {
let id:String
let name:String
init?(fromDict dict:Dictionary<String, String>?) {
guard let id = dict?["id"],
let name = dict?["name"] else {
return nil
}
self.id = id
self.name = name
}
}
Ive created a class called facebookGraphRequest.
import Foundation
import UIKit
import FBSDKCoreKit
import FBSDKLoginKit
import FBSDKShareKit
class facebookGraphRequest: NSObject {
class func graphRequestWork(completion: #escaping(_ error: Error?, _ facebookUserWork: Worker)-> Void){
if ((FBSDKAccessToken.current()) != nil){
let parameters = ["fields": "name, picture.width(198).height(198), location{location}, work{employer}, education, about, id"]
let graphRequest: FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: parameters)
graphRequest.start { (connection, result, error) in
if ((error) != nil ){
print(error!)
}else {
print(result!)
func workersArray(data:Dictionary<String, Any>)->[Worker]?{
guard let arrayOfDict = data["work"] as? Array<Dictionary<String, Any>> else {
return nil
}
return arrayOfDict.flatMap({ Worker(fromDict: $0)})
}
}
}
}
}
}
and I'm calling this data inside the viewController with:
func facebookLogin(){
facebookGraphRequest.graphRequestWork { (error: Error?, facebookUserWork: Worker) in
self.userNameJobPositionLabel.text = "\(facebookUserWork.position)"
self.companyNameLabel.text = "\(facebookUserWork.employer)"
}
}
Somebody knows what's happening? There's nothing happening with the labels.
I thought this apis was easier than that. I'm really confused with this process... Sorry if it looks like stupid questions but I'm really messing my mind because of this things... I really need your help guys. My work depends on that :(
After experimenting with Swift 4 and going in the direction that #PuneetSharma demonstrated I found it's even easier when you use raw JSON text, Codable, and JSONDecoder:
import Foundation
// define the nested structures
struct Work: Codable {
let work: [Worker]
}
struct Worker: Codable {
let employer: Employer
let location: Location
let position: Position
let startDate: String
let id: String
// needed a custom key for start_date
enum CodingKeys : String, CodingKey {
case employer, location, position, startDate = "start_date", id
}
}
struct Employer: Codable {
let id: String
let name: String
}
struct Location: Codable {
let id: String
let name: String
}
struct Position: Codable {
let id: String
let name: String
}
// turn the text into `Data` and then
// decode as the outermost structure
if let jsonData = json.data(using: .utf8),
let work = try? JSONDecoder().decode(Work.self, from: jsonData) {
print(work)
}
The result is a Work structure with all the data:
Work(work: [
Model.Worker(employer : Model.Employer(id : "93643283467",
name: "Oracast"),
location : Model.Location(id : "111983945494775",
name: "Calgary, Alberta"),
position : Model.Position(id : "146883511988628",
name: "Mobile Developer"),
startDate: "2017-04-30",
id : "1446626725564198")
])
(I formatted the output a bit to clarify the structures produced.)
You get a lot of functionality for free just by using Codable. It's also simple to go the other way and produce JSON text from any of the structures.
You should ideally introduce model classes like this:
struct Worker {
let employer:Employer
let location:Location
let position:Position
let startDate:String
let id:String
init?(fromDict dict:Dictionary<String, Any>) {
guard let employer = Employer(fromDict: dict["employer"] as? Dictionary<String, String>), let location = Location(fromDict: dict["location"] as? Dictionary<String, String>), let position = Position(fromDict: dict["position"] as? Dictionary<String, String>), let startDate = dict["start_date"] as? String, let id = dict["id"] as? String else {
return nil
}
self.employer = employer
self.location = location
self.position = position
self.startDate = startDate
self.id = id
}
}
struct Employer {
let id:String
let name:String
init?(fromDict dict:Dictionary<String, String>?) {
guard let id = dict?["id"], let name = dict?["name"] else {
return nil
}
self.id = id
self.name = name
}
}
struct Location {
let id:String
let name:String
init?(fromDict dict:Dictionary<String, String>?) {
guard let id = dict?["id"], let name = dict?["name"] else {
return nil
}
self.id = id
self.name = name
}
}
struct Position {
let id:String
let name:String
init?(fromDict dict:Dictionary<String, String>?) {
guard let id = dict?["id"], let name = dict?["name"] else {
return nil
}
self.id = id
self.name = name
}
}
Now, you can introduce a function like this:
func workersArray(data:Dictionary<String, Any>)->[Worker]?{
guard let arrayOfDict = data["work"] as? Array<Dictionary<String, Any>> else {
return nil
}
return arrayOfDict.flatMap({ Worker(fromDict: $0)})
}
Use this code
if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
if let workArray = json["work"] as? [[String: Any]] {
if let dictWork = workArray.first {
if let dictPosition = dictWork["position"] as? [String: String] {
print("position name : \(dictPosition["name"])")
}
}
}
}

Resources