I have a Realm database called NewsCount. I need to download a new news only if there is a new news (respectively when newsCount change). And I make a comparison with the data parsing. But I can not compare them properly. How do you compare them?
Thi is my code
private func parseJSONData(_ data: Data) {
do {
let temp: NSString = NSString(data: data, encoding: String.Encoding.utf8.rawValue)!
let myNSData = temp.data(using: String.Encoding.utf8.rawValue)!
guard let jsonResult = try JSONSerialization.jsonObject(with: myNSData, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary else {
return
}
guard let jsonNews = jsonResult["categories"] as? [AnyObject] else {
print("Empty array")
return
}
let realm = try Realm()
let category = realm.objects(NewsCount.self)
var array = [Int]()
for i in category {
array.append(i.newsCount)
}
print(array)
print("News COUNT2 \(category)")
for jsonnewes in jsonNews {
let newsJson = NewsCount()
//HERE I COMPARE
if !UserDefaults.standard.bool(forKey: "AppStarted") || jsonnewes["count"] as! Int > array[jsonnewes as! Int]{
newsJson.newsID = jsonnewes["term_id"] as! Int
newsJson.newsCount = jsonnewes["count"] as! Int
//print("News COUNT2 \(newsJson.newsCount)")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "downloadNew"), object: nil)
} else {
newsJson.newsID = jsonnewes["term_id"] as! Int
newsJson.newsCount = jsonnewes["count"] as! Int
//print("News COUNT3 \(newsJson.newsCount)")
}
insertOrUpdate(newsJson)
}
} catch {
print(error)
}
}
Because Realm uses RealmOptional to use Int values you have to call the value atribute to the RealmOptional
Try change this:
for i in category {
array.append(i.newsCount.value)
}
First off, it's probably more appropriate to use Int(string) instead of as! Int force-casting to convert your JSON data to integers.
From the looks of it, jsonnewes is a dictionary full of JSON data, but you're casting it as an array index in array[jsonnewes as! Int] which (given array is an array and not a dictionary) shouldn't work.
Instead, in order to make sure you're explicitly retrieving the item you want, I'd recommend using Realm's primary key query method in order to retrieve the item you want.
let realm = try! Realm()
for newsItem in jsonNews {
let newsPrimaryKey = Int(newsItem)
let realmNews = realm.object(ofType: NewsCount.self, forPrimaryKey: newsPrimaryKey)
// Don't continue if a Realm object couldn't be found
guard let realmNews = realmNews else {
continue
}
// Perform comparison
if Int(newsItem["count"]) > realmNews.newsCount {
// Perform the update
}
}
Related
until version 10.7.6 of Realm I could convert to dictionary and then to json with this code below, but the ListBase class no longer exists.
extension Object {
func toDictionary() -> NSDictionary {
let properties = self.objectSchema.properties.map { $0.name }
let dictionary = self.dictionaryWithValues(forKeys: properties)
let mutabledic = NSMutableDictionary()
mutabledic.setValuesForKeys(dictionary)
for prop in self.objectSchema.properties as [Property] {
// find lists
if let nestedObject = self[prop.name] as? Object {
mutabledic.setValue(nestedObject.toDictionary(), forKey: prop.name)
} else if let nestedListObject = self[prop.name] as? ListBase { /*Cannot find type 'ListBase' in scope*/
var objects = [AnyObject]()
for index in 0..<nestedListObject._rlmArray.count {
let object = nestedListObject._rlmArray[index] as! Object
objects.append(object.toDictionary())
}
mutabledic.setObject(objects, forKey: prop.name as NSCopying)
}
}
return mutabledic
}
}
let parameterDictionary = myRealmData.toDictionary()
guard let postData = try? JSONSerialization.data(withJSONObject: parameterDictionary, options: []) else {
return
}
List now inherits from RLMSwiftCollectionBase apparently, so you can check for that instead. Also, this is Swift. Use [String: Any] instead of NSDictionary.
extension Object {
func toDictionary() -> [String: Any] {
let properties = self.objectSchema.properties.map { $0.name }
var mutabledic = self.dictionaryWithValues(forKeys: properties)
for prop in self.objectSchema.properties as [Property] {
// find lists
if let nestedObject = self[prop.name] as? Object {
mutabledic[prop.name] = nestedObject.toDictionary()
} else if let nestedListObject = self[prop.name] as? RLMSwiftCollectionBase {
var objects = [[String: Any]]()
for index in 0..<nestedListObject._rlmCollection.count {
let object = nestedListObject._rlmCollection[index] as! Object
objects.append(object.toDictionary())
}
mutabledic[prop.name] = objects
}
}
return mutabledic
}
}
Thanks to #Eduardo Dos Santos. Just do the following steps. You will be good to go.
Change ListBase to RLMSwiftCollectionBase
Change _rlmArray to _rlmCollection
Import Realm
I'm getting JSON format data from the server, then I convert the data format to the [String:Any].
JSON--> {
integer = 1;
length = "<null>";
object = (
"692b663b-b7d5-43-287ddaadc2ff"
);
string = "SANJEEV TREHAN";
}
Here is the code:
if let data = data{
do{
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
if let integer = json["integer"] as? Int {
DispatchQueue.main.async {
if integer == 1{
//retrieve data here
print(json)
}
else{
print("alert")
}
}
}
else{
print("no name")
}
}
after converting the data as [String: Any]:
json = `["length": <null>, "integer": 1, "string": SANJEEV TREHAN, "object": <__NSSingleObjectArrayI 0x2806acb10>(
692b663b-b7d5-43d5-daadc2ff) ]`
I want to retrieve the object key value from the json variable.
The data I want only is 692b663b-b7d54a-7dd-aadc2ff as the String
I tried many things but not getting the data which format I want.
Since you're using Swift, why not use Codable types instead? They're much easier to use and you don't have to do weird casting or testing everywhere.
struct Response: Codable {
let length: Int?
let integer: Int
let string: String
let object: SomeObject
}
struct SomeObject: Codable {
let uuid: UUID
}
do {
let response = try JSONDecoder().decode(Response.self, from: data)
} catch {
print(error)
}
Now you can now ask for the fields directly.
print(response.object.uuid)
Seems like your object key is an array of string. Here is how you can get the value.
if let yourObject = json["object"] as? [String] {
if yourObject.count != 0 {
yourObjectValue = yourObject[0]
}
}
I'm new to Swift and I'm learning how to use parse.com to store data an retrive it. I'm downloading an array of PFObjects from PARSE and then I need to turn it into a structure, so I created this function:
func queryDownload (user : PFUser) {
let objects: [PFObject]
let query = PFQuery(className: "Gluc")
query.whereKey("user", equalTo: user)
do {
objects = try query.findObjects() as [PFObject]
} catch {
print("ERROR")
}
let returnedObjects = objects {
let elements = self.returnedObjects.count
for i in 0...elements-1 {
self.dataArray.append(MyData(gluc: Int(self.returnedObjects[i]["meassure"] as! String)!, fec: self.returnedObjects[i]["fec"] as! Date, alimento: self.returnedObjects[i]["alim"] as! Int, comentarios: self.returnedObjects[i]["notes"] as! String))
}
}
self.dataArrayOrdered = self.dataArray.sorted(by: { $0.fec.compare($1.fec) == .orderedAscending})
print(self.dataArrayOrdered)
}
But I can't run it because in this line:
let returnedObjects = objects {
It sais "Cannot call value of non-function type [PFObject]"
I'm not sure how to avoid this problem, so any help would be appreciated
Thanks
let returnedObjects = objects { ... }
is a syntax error, you probably wanted to optional bind the value
if let returnedObjects = objects { ... }
but objects is non-optional and optional binding is not possible.
Just assign the value to the variable and remove the braces
do {
let objects = try query.findObjects() as [PFObject]
let returnedObjects = objects
let elements = self.returnedObjects.count
for i in 0...elements-1 {
self.dataArray.append(MyData(gluc: Int(self.returnedObjects[i]["meassure"] as! String)!, fec: self.returnedObjects[i]["fec"] as! Date, alimento: self.returnedObjects[i]["alim"] as! Int, comentarios: self.returnedObjects[i]["notes"] as! String))
}
self.dataArrayOrdered = self.dataArray.sorted(by: { $0.fec.compare($1.fec) == .orderedAscending})
print(self.dataArrayOrdered)
} catch {
print("ERROR", error)
}
It's very important to put all good code in the do block and print the actual error rather than the simple literal string "ERROR"
However this is Swift and there is a smarter and more convenient way using the map function
do {
let objects = try query.findObjects() as [PFObject]
self.dataArray = objects.map { MyData(gluc: Int($0["meassure"] as! String)!, fec: $0["fec"] as! Date, alimento: $0["alim"] as! Int, comentarios: $0["notes"] as! String) }
self.dataArrayOrdered = self.dataArray.sorted(by: { $0.fec.compare($1.fec) == .orderedAscending})
print(self.dataArrayOrdered)
} catch {
print("ERROR", error)
}
I am trying to parse the emergency data in into emergency struct but it never statifies the condition and get into else case.Here is my code and structure.Some thing i have written woring in first line.
if let emergencyDict = snapshotValue["emergency"] as? [String:[String:Any]]{
for (emerId, emerData) in emergencyDict {
let emer = Emergency.init(emergency: emerData as NSDictionary)
emergency.append(emer)
}
}
else{
let emer = Emergency.init(emerg: "" as AnyObject)
emergency.append(emer)
}
struct Emergency{
var emer_id: String
var emer_name: String
var emer_phoneNo: String
init(emergency: NSDictionary) {
if emergency.object(forKey: "id") != nil {
emer_id = emergency.object(forKey: "id") as! String
}
else{
emer_id = ""
}
}
}
The problem you are having emergency as Array with type [Any] and if you remove the first object then you get Array of type [[String:Any]]. So try like this way.
if let array = snapshotValue["emergency"] as? [Any],
let emergencyArrar = Array(array.dropFirst()) as? [[String:Any]] {
print(emergencyArray)
for emergency in emergencyArray {
print(emergency)
}
}
You have written wrong in this line:
if let emergencyDict = snapshotValue["emergency"] as? [String:[String:Any]]{
It should be:
if let emergencyDict = snapshotValue["emergency"] as? [[String:Any]]{
This question should belong to query from firebase database.
// you have to get the children in emergency,
// then get the value(dictionary) of each child
ref.child("emergency").observeSingleEvent(of: .value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
let keys = value?.allKeys // [1, 2, 3 ....]
for key in keys {
ref.child("emergency").child(key)..observeSingleEvent(of: .value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
// Here is your dictionary
}
}
}) { (error) in
print(error.localizedDescription)
}
I am trying to check the id of a record before I put it into the array, using xcode swift
here is the code. But, i get the following error
Notifications.swift:50:46: Cannot convert value of type 'String?!' to expected argument type 'Notifications'
on this line
*if (readRecordCoreData(result["MessageID"])==false)*
Please can some one help to explain this error
import CoreData
struct Notifications{
var NotifyID = [NSManagedObject]()
let MessageDesc: String
let Messageid: String
init(MessageDesc: String, Messageid:String) {
self.MessageDesc = MessageDesc
self.Messageid = Messageid
// self.MessageDate = MessageDate
}
static func MessagesWithJSON(results: NSArray) -> [Notifications] {
// Create an empty array of Albums to append to from this list
var Notification = [Notifications]()
// Store the results in our table data array
if results.count>0 {
for result in results {
//get fields from json
let Messageid = result["MessageID"] as! String
let MessageDesc = result["MessageDesc"] as? String
let newMessages = Notifications(MessageDesc: MessageDesc!, Messageid:Messageid)
//check with id's from core data
if (readRecordCoreData(result["MessageID"])==false)
{
Notification.append(newMessages)
}
}
}
return Notification
}
//check id
func readRecordCoreData(Jsonid: String) -> Bool {
var idStaus = false
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
//2
let fetchRequest = NSFetchRequest(entityName: "ItemLog")
//3
do {
let resultsCD = try! managedContext.executeFetchRequest(fetchRequest)
if (resultsCD.count > 0) {
for i in 0 ..< resultsCD.count {
let match = resultsCD[i] as! NSManagedObject
let id = match.valueForKey("notificationID") as! String
if (Jsonid as String! == id)
{
idStaus = true
}
else{
idStaus = false
}
}
}
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
return idStaus
}
One of your methods is static and the other one is not :
func readRecordCoreData(Jsonid: String) -> Bool
static func MessagesWithJSON(results: NSArray) -> [Notifications]
Depending on what you want to accomplish you could declare both static, none, or replace
//check with id's from core data
if (readRecordCoreData(result["MessageID"])==false)
{
Notification.append(newMessages)
}
By
//check with id's from core data
if (Notifications.readRecordCoreData(Messageid)==false)
{
Notification.append(newMessages)
}
Not sure if the code will work past compilation however as there are many readability issues