Issue in Parsing JSON object from CoreData - ios

I converted a JSON object to string and stored it to CoreData. But how to parse the individual elements and get each of the elements after retrieving the JSON object that I'm not able to figure out....
This is how I'm getting the json object:
let mobileNumber = mobileNumberTextfield.text
let firstName = firstNameTextField.text
let jsonObject: [String: [String:Any]] = [
"user1": [
"mobile_number": mobileNumber,
"first_Name": firstName,
]
]
I'm printing JSON string like so...
if let data = try? JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted),
let str = String(data: data, encoding: .utf8) {
print(str)
}
printing str gives:
{
"user1" : {
"mobile_number" : "567567567",
"first_Name" : "iopiopi",
}
}
I'm storing it as it is to coredata and so when I retrive it I get it back in the very same format as above. But how can I retrieve the individual elements for later use that I can't figure out.
If I fetch it something like so...
for result in newProductDetails {
if let prodID = result.value(forKey: "address") as? String {
print(prodID)
}
}
and do a for (key, value) in addDetails.enumerated() & print value, it give this..
data: {
address = "{
\n \"user1\" : {
\n \"mobile_number\" : \"1236594525\",
\n \"first_Name\" : \"ghj\"
\n
}
\n
}";
})
But how can I extract individual values of mobile_number & first_Namefrom it ...?

You are storing the data (NSData obtained from the string encoding the JSON) and getting back that same data from CoreData. That means you have to parse the JSON in that NSData instance again. The round trip to JSON/NSData and back makes little sense. You probably just want to create an User entity and store the mobile number and first name into CoreData directly.

Convert Json string to Dictionary:
func convertToDictionary(text: String) -> [String: Any]? {
if let data = text.data(using: .utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
} catch {
print(error.localizedDescription)
}
}
return nil
}
let str = "{\"name\":\"James\"}"
let dict = convertToDictionary(text: str)
You should save like this in CoreData:
if let reposArray: AnyObject = json["user1"] as? NSDictionary {
self.mbleNo = reposArray["mobile_number"] as? String
let appDelegate = UIApplication.shared.delegate as! AppDelegate
if #available(iOS 10.0, *) {
let managedObjectContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Fields")
let entityDescription = NSEntityDescription.entity(forEntityName: "Fields", in:managedObjectContext)
let titleInfo = NSManagedObject(entity: entityDescription!, insertInto: managedObjectContext) as? Fields
titleInfo?.setValue(self.mbleNo, forKey: "mobile_number")
do {
try titleInfo?.managedObjectContext?.save()
}
catch {
print(error)
}
}
}

Related

How to convert stored values to JSON format using Swift?

I am trying to convert stored coredata values to JSON format and the JSON format value need to assign a single variable, because this generated JSON I need to send to server. Below code I tried to get coredata stored values but don’t know how to generate JSON required format.
Getting values from coredata
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "User")
do {
let results = try context.fetch(fetchRequest)
let dateCreated = results as! [Userscore]
for _datecreated in dateCreated {
print("\(_datecreated.id!)-\(_datecreated.name!)") // Output: 79-b \n 80-c \n 78-a
}
} catch let err as NSError {
print(err.debugDescription)
}
Need to Convert Coredata Value to Below JSON format
{
    "status": true,
    "data": [
        {
            "id": "20",
            "name": "a"
        },
        {
            "id": "21",
            "name": "b"
        },
        {
            "id": "22",
            "name": "c"
        }
    ]
}
Probably the easiest is to convert your object(s) to either dictionaries or arrays (depending on what you need).
First you need to be able to convert your Userscore to dictionary. I will use extension on it since I have no idea what your entity looks like:
extension Userscore {
func toDictionary() -> [String: Any]? {
guard let id = id else { return nil }
guard let name = name else { return nil }
return [
"id": id,
"name": name
]
}
}
Now this method can be used to generate an array of your dictionaries simply using let arrayOfUserscores: [[String: Any]] = userscores.compactMap { $0.toDictionary() }.
Or to build up your whole JSON as posted in question:
func generateUserscoreJSON(userscores: [Userscore]) -> Data? {
var payload: [String: Any] = [String: Any]()
payload["status"] = true
payload["data"] = userscores.compactMap { $0.toDictionary() }
return try? JSONSerialization.data(withJSONObject: payload, options: .prettyPrinted)
}
This will now create raw data ready to be sent to server for instance
var request = URLRequest(url: myURL)
request.httpBody = generateUserscoreJSON(userscores: userscores)
You can use the properties of an Encodable to make this happen. This has the added benefit of not resorting to the Any type.
For the JSON, you could use the following types:
struct JSONMessage: Encodable {
var status: Bool
var data: [JSONDataEntry]
}
struct JSONDataEntry: Encodable {
var id: String
var name: String
}
Then you can adjust your do/try/catch as follows:
do {
let results = try context.fetch(fetchRequest)
let dateCreated = results as! [Userscore]
// *starting here*
let data = dateCreated.map { JSONDataEntry(id: String($0.id!), name: $0.name!) }
let status = true // <- not sure where status comes from, so adding here
let message = JSONMessage(status: status, data: data)
let jsonData = try JSONEncoder().encode(message)
if let json = String(data: jsonData, encoding: .utf8) {
// do something with the JSON string
print(json)
}
// *ending here*
} catch let err as NSError {
print(err.debugDescription)
}

Getting filtered data in search bar from json

I'm having a name assigned to my name textfield like so..
for asd in orderDetails {
if let jsonStr = asd.value(forKey: "customerJson") as? String {
let data = sdf?.data(using: String.Encoding.utf8, allowLossyConversion: false)!
do {
if let json = try JSONSerialization.jsonObject(with: data!) as? [String: Any] {
for item in json {
if item.key == "first_Name" {
cell.nameLabel.text = item.value as? String //ASSIGNED HERE
}
}
}
} catch let error as NSError {
print("Failed to load: \(error.localizedDescription)")
}
}
}
Now I want to search on the search bar based on this name. While searching in other views where the core data attributes were mentioned directly I did something like so which worked fine..
filtered = self.newProdDetails.filter({( data : NewProduct) -> Bool in
return (data.name?.lowercased().contains(searchText.lowercased()))! //Here the entity NewProduct has an attribute name
})
But in the current scenario, the attribute is a called customer_json which is a json string like so..
customer_json={
"mobile_number”:”9876543210”,
"first_name”:”testName”,
"last_name”:”testLastName”,
"seller_id":"93"
}
How can I mention first_name in the search parameter
It's bad idea to keep working with Data object or even JSON string directly as your Model. I recommend you to create few Structs, make the conform to Codeable protocol, so I will make the easy to work with and easy to convert into JSON whoever you want. I'm strongly advice you to consider it.
JSONSerialization.jsonObject(with:) converting your data into Dictionary, so instead of enumerating it you can access value you want by key:
Like this:
if let json = try JSONSerialization.jsonObject(with: data!) as? [String: Any],
let name = json["first_Name"] {
cell.nameLabel.text = name
}
And definitely you can access you data same way:
orderDetails.filter{ asd in
if
let jsonStr = asd.value(forKey: "customerJson") as? String,
let data = sdf?.data(using: String.Encoding.utf8, allowLossyConversion: false)
let json = try JSONSerialization.jsonObject(with: data!) as? [String: Any],
let name = json["first_Name"],
name == cell.nameLabel.text {
return true
} else {
return false
}
}

Convert Json string to Json object in Swift 4

I try to convert JSON string to a JSON object but after JSONSerialization the output is nil in JSON.
Response String:
[{\"form_id\":3465,\"canonical_name\":\"df_SAWERQ\",\"form_name\":\"Activity 4 with Images\",\"form_desc\":null}]
I try to convert this string with my code below:
let jsonString = response.result.value
let data: Data? = jsonString?.data(using: .utf8)
let json = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String:AnyObject]
print(json ?? "Empty Data")
The problem is that you thought your jsonString is a dictionary. It's not.
It's an array of dictionaries.
In raw json strings, arrays begin with [ and dictionaries begin with {.
I used your json string with below code :
let string = "[{\"form_id\":3465,\"canonical_name\":\"df_SAWERQ\",\"form_name\":\"Activity 4 with Images\",\"form_desc\":null}]"
let data = string.data(using: .utf8)!
do {
if let jsonArray = try JSONSerialization.jsonObject(with: data, options : .allowFragments) as? [Dictionary<String,Any>]
{
print(jsonArray) // use the json here
} else {
print("bad json")
}
} catch let error as NSError {
print(error)
}
and I am getting the output :
[["form_desc": <null>, "form_name": Activity 4 with Images, "canonical_name": df_SAWERQ, "form_id": 3465]]
Using JSONSerialization always felt unSwifty and unwieldy, but it is even more so with the arrival of Codable in Swift 4. If you wield a [String:Any] in front of a simple struct it will ... hurt. Check out this in a Playground:
import Cocoa
let data = "[{\"form_id\":3465,\"canonical_name\":\"df_SAWERQ\",\"form_name\":\"Activity 4 with Images\",\"form_desc\":null}]".data(using: .utf8)!
struct Form: Codable {
let id: Int
let name: String
let description: String?
private enum CodingKeys: String, CodingKey {
case id = "form_id"
case name = "form_name"
case description = "form_desc"
}
}
do {
let f = try JSONDecoder().decode([Form].self, from: data)
print(f)
print(f[0])
} catch {
print(error)
}
With minimal effort handling this will feel a whole lot more comfortable. And you are given a lot more information if your JSON does not parse properly.
I tried the solutions here, and as? [String:AnyObject] worked for me:
do{
if let json = stringToParse.data(using: String.Encoding.utf8){
if let jsonData = try JSONSerialization.jsonObject(with: json, options: .allowFragments) as? [String:AnyObject]{
let id = jsonData["id"] as! String
...
}
}
}catch {
print(error.localizedDescription)
}
I used below code and it's working fine for me. :
let jsonText = "{\"userName\":\"Bhavsang\"}"
var dictonary:NSDictionary?
if let data = jsonText.dataUsingEncoding(NSUTF8StringEncoding) {
do {
dictonary = try NSJSONSerialization.JSONObjectWithData(data, options: [.allowFragments]) as? [String:AnyObject]
if let myDictionary = dictonary
{
print(" User name is: \(myDictionary["userName"]!)")
}
} catch let error as NSError {
print(error)
}
}
static func getJSONStringFromObject(object: Any?) -> String? {
do {
let jsonData = try JSONSerialization.data(withJSONObject: object ?? DUMMY_STRING, options: [])
return String(data: jsonData, encoding: .utf8) ?? DUMMY_STRING
} catch {
print(error.localizedDescription)
}
return DUMMY_STRING
}

Parse data from socket.io response swift

I have response from socket io library with response like this
socket.on("response-names") { data, ack in
print(data)
}
can print this,
[{
"person": [{
"_id":"56512323212132",
"name":"John Smith",
"id":"0000001",
"geolocation":{
"latitude":5.12312323443,
"longitude":101.12312464564354
}
}]
}]
How do you guys access the name, id and the geolocation(lat, long) in swift ?,
As far as I know the data is NSArray. but accessing is with data[0] will produce nil. but i can do data.count which will return with 1.
Thank you
Finally i solved it, just for future reference for others. It looks like you need to know the type before you parsing it. and check it with print.
and the debug code really helping, something like NSCFArray means your data as NSArray and try to read from that.
let dataArray = data as NSArray
let dataString = dataArray[0] as! String
let dataNewNow = dataString.data(using: String.Encoding.utf8, allowLossyConversion: false)!
do {
let json = try NSJSONSerialization.JSONObjectWithData(dataNewNow, options: []) as! [String: AnyObject]
let str = json["person"] as! NSArray
let str2 = str[0] as! NSDictionary
let personName = str2["name"] as! String
let personId = str2["id"] as! String
let personGeoLocation = str2["geolocation"] as! NSDictionary
let personLatitude = personGeoLocation["latitude"] as! NSNumber
let personLongitude = personGeoLocation["longitude"] as! NSNumber
print("personName =", personName)
print("personID =", personId)
print("Person Latitude =", personLatitude)
print("Person Longitude =", personLongitude)
} catch let error as NSError {
print("Failed to load: \(error.localizedDescription)")
}
in my case this worked
let dataArray = data as NSArray
let dataString = dataArray[0] as! String
let dataNewNow = dataString.data(using: String.Encoding.utf8, allowLossyConversion: false)!
do {
let json = try JSONSerialization.jsonObject(with: dataNewNow, options: []) as! [String: AnyObject]
let nMsgType = json["msg_type"] as! String
print(nMsgType)
} catch let error as NSError {
print("Failed to load: \(error.localizedDescription)")
}
I know it's a very old question but my answer may help someone ... In today's swift 5 it's very easy than before...
Create a SocketParser and use the below code to parse data...
class SocketParser {
static func convert<T: Decodable>(data: Any) throws -> T {
let jsonData = try JSONSerialization.data(withJSONObject: data)
let decoder = JSONDecoder()
do{
let _ = try decoder.decode(T.self, from: jsonData)
}catch{
createLog("CheckError \(error)")
}
return try decoder.decode(T.self, from: jsonData)
}
}
Now Create a simple model for your JSON ... in you case as bellow...
import Foundation
// MARK: - WelcomeElement
struct WelcomeElement: Codable {
let person: [Person]
}
// MARK: - Person
struct Person: Codable {
let id, name, personID: String
let geolocation: Geolocation
enum CodingKeys: String, CodingKey {
case id = "_id"
case name
case personID = "id"
case geolocation
}
}
// MARK: - Geolocation
struct Geolocation: Codable {
let latitude, longitude: Double
}
It's time to use these in response as below...
socket.on("response-names") { data, ack in
guard let data = data.first else{
return
}
if let response : WelcomeElement = try? SocketParser.convert(data: data) {
print(responce)
}

parsing JSON with Swift

I'm coming from android programming to Swift iOS programming and have a hard time parsing a json
here's String I try to parse :
{"response":[{"uid":111,"first_name":"someName","last_name":"someLastName","photo_100":"http:someUrl/face.jpg"}]}
here how I try to parse this :
if let dict = Utils.convertStringToDictionary(response)! as? [String: AnyObject]{
// this part is yet doing ok
if let response = dict["response"] as? [String: AnyObject]{
NSLog("let response \(response)")
if let first_name = response["first_name"] as? String {
NSLog("first_name = \(first_name)")
}
}
else {
NSLog("not an []")
}
the Log message gives me "not an []" as it can't make a response object. As far as I understand, I'm doing right as [String: AnyObject] is what is in "response" body of my json
Just in case, here's my Utils.convertStringToDictionary method:
public static func convertStringToDictionary(text: String) -> [String:AnyObject]? {
if let data = text.dataUsingEncoding(NSUTF8StringEncoding) {
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers) as? [String:AnyObject]
return json
} catch {
NSLog("Something went wrong")
}
}
return nil
}
Array in swift denotes with []
Dictionary in swift denotes with [:]
your response parameter is array of dictionary ... so it denotes with [[:]]
so just parse it with [[String: AnyObject]]
if let response = dict["response"] as? [[String: AnyObject]]{
for user in response{
NSLog("let response \(user)")
if let first_name = user["first_name"] as? String {
NSLog("first_name = \(first_name)")
}
}
}
Problem here is response is an array
if let response = dict["response"] as? NSArray{
for value in response as? NSDictionary{
print(value["uid"]) /// prints 111
print(value["first_name"]) /// prints someName
}
}
Try this code
if let dict = Utils.convertStringToDictionary(response)! as? [String: AnyObject]{
// this part is yet doing ok
if let response = dict["response"] as? NSArray{
NSLog("let response \(response)")
for dict in response{
if let first_name = dict["first_name"] as? String {
NSLog("first_name = \(first_name)")
}
}
}
else{
NSLog("not an []")
}
}

Resources