Is it possible to create Dictionary from string data that log area of xcode display. Like
0 = {
"Key1" = "ABC";
};
1 = {
"Key1" = "DEF";
};
No way whatsoever. The output of NSLog is purely for debugging purposes. You have no chance in hell reconstructing a dictionary from this. Don't even try.
What are you actually trying to achieve?
It looks to me, as you are printing an array, containing two NSDictionary objects.
When you write it out to the console, then you must know the object type (or can find it, using the debugger).
If its an array, you can loop through it, taking out the individual key and values, and adding them to a new NSMutableDisctionay, that then will contain a all keys/values. Just ensure that your keys are unique.
Related
How can i add a queryConstraint on a object?
This is my current code but it returns no objects. I guess my current code is actually to query on arrays and not objects. But I can't find a way to do this for objects.
let query = Device.query()
.where(containsString(key: "apps", substring: "Google"))
This is the database
I recommend looking at the playgrounds to see how to use ParseSwift properly. More specifically, finding objects.
The first problem is apps is an object, which is actually a dictionary. You can’t use a substring constraint on a dictionary or other object. The actual way to do it is:
let objectToFind = [“Google”: “300”]
let query = Device.query("apps" == objectToFind),
I have two dictionaries. Both declared in a viewController, both based on a model structure class.
// ItemDictionary
var ItemDictionary = ItemModel()
var JSONDictionary = ItemModel()
JSON data is fed into the JSONDictionary and then this data is passed to ItemDictionary which feeds a table within ViewDidLoad.
self.ItemDictionary = self.JSONDictionary
All good. The table is nicely populated from JSON data. I can also delete items from the table and the ItemDictionary. However, when I try and add items back by referring to the original dictionary (JSONDictionary) the item has gone.
I understand this is expected. If Dictionary1 = Dictionary2, a new dictionary is not actually created. Only an second address. So if you change Dictionary1, Dictionary2 also changes.
A practical example could be setting a price range. You can reduce the range and have less items displayed on the table. But you can't replace previously deleted items if you wanted to increase the price range. I do not want to recall the JSON script each time I edit the range. Advice appreciated.
As confirmed by the OP, ItemModel is a class and not a Dictionary. To fix this you need to make ItemModel a real Dictionary and thus a value type. This is probably the preferred choice but will be more work.
An alternative would be to add an convenience initializer to the ItemModel class that instantiates a new copy of itself and call that instead of setting self.ItemDictionary = self.JSONDictionary.
Something like this.
init(model: ItemDictionary) -> ItemDictionary {
// copy properties
}
Then create the new copy.
self.ItemDictionary = ItemDictionary(self.JSONDictionary)
Later you can reinitialize ItemDictionary with the same call.
Try this code out-
var dictionary1 = ["name": "Magnus"]
var dictionary2 = dictionary1
dictionary2.removeAll()
print("\(dictionary2) \(dictionary1)")
The output is :-
[:] ["name": "Magnus"]
Thus 2 new dictionaries are being created. If you refer to the Swift documentation, You will find that in swift, references are hardly present.
Some other portion of code might be responsible. Hope this helps :-)
Say you do this,
NSString *teste = yourData[#"title"];
no problem if "title" is completely missing in the json: you just get null. If you do this:
NSString *teste = yourData[#"location"][#"city"];
if "city" is missing in the json nest, no problem. if the whole "location" section does not exist, again no problem
However! You'll often see json like this, " largeImage = "<null>"; "
In that case, the app will crash if you are using the code above.
In practice you have to do this:
NSString *imageUrl = nil;
if ([yourResults[thisRow][#"largeImage"] isKindOfClass:[NSDictionary class]])
imageUrl = yourResults[thisRow][#"largeImage"][#"URL"];
My question was really:
is there some dead clever way to perhaps override the literal syntax (ie, override the underlying message, perhaps??) to cover this problem?
So essentially, make this concept [#"blah"] basically first check that indeed it is a dictionary at hand, before trying the operation.
It's a shame because, effectively, you can never use this wonderful syntax
yourData[#"location"][#"city"]
in practice, due to the problem I outline.
PS sorry for the earlier confusion on this question, fixed by Paramag. below - good one Paramag.
Personally i use with JSON category which returns null instead NSNull so my code looks:
[[json objectForKeyNotNull:#"Key"] objectForKeyNotNull:#"Other"]
As you want to have code shorter, i think i would create the category on NSDictionary which could be used as :
[json objectForPath:#"Key.Value"]
Which would expand the path into the keys.
There is some nice gist which looks like it's doing it:
https://gist.github.com/Yulong/229a62c1188c3c024247#file-nsdictionary-beeextension-m-L68
to check this kind of null , you can use valueForKeyPath:
NSString *teste = [CLOUD.yourData[thisRow] valueForKeyPath:#"location.city"];
it will first check for "location" and then for "city".
I would say this is a problem with your schema. null in JSON and a dictionary (called an "object") in JSON are different types of things. The fact that your key can have a value that is sometimes null and sometimes a dictionary seems to me that you guys are not following a rigorous schema.
A good design would have the key either not be there, or if it is there, its value is guaranteed to be a dictionary. In such a case, the Objective-C code NSString *teste = yourData[#"location"][#"city"]; would work without modification because if the key "location" didn't exist, then its value would be nil in Objective-C, and subsequent accesses won't crash, and will also return nil.
So long story short, there's a discrepancy between the output of a NSMutableDictionary's contents and the result of calling allValues on the same object. Below is some debugger output after inspecting the object which demonstrates my problem: (made generic of course)
(lldb) po self.someDict.allKeys
<__NSArrayI 0xa5a2e00>(
<SomeObject: 0xa5a2dc0>,
<SomeObject: 0xa5a2de0>
)
(lldb) po self.someDict.allValues
<__NSArrayI 0xa895ca0>(
0.5,
0.5
)
(lldb) po self.someDict
{
"<SomeObject: 0xa5a2dc0>" = (null);
"<SomeObject: 0xa5a2de0>" = (null);
}
So as we can see, the actual output of the NSMutableDictionary contains null values for both its entries, but the contents of .allValues contains the proper data. These three outputs were taken at the same time in execution.
I'm not sure why this is happening, but I think it may have something to do with the fact that I'm encoding/decoding the object which this dictionary is a property of using CoreData. I believe I'm doing this properly:
[aCoder encodeObject:self.someDict forKey:#"someDict"];
and to decode
self.someDict = [aDecoder decodeObjectForKey:#"someDict"];
The weird thing is that if I inspect the dictionary before it ever gets encoded, it is still in the state described at the beginning of the post, so this is why I'm doubtful the CoreData actions are screwing with the contents.
As always, please don't hesitate to request additional information.
EDIT: The problem was as answered below. I was using a custom class which didn't cooperate with isEqual, so my solution was to change the storage and structure of my logic, which made using a Dictionary unnecessary.
I have not been able to duplicate the problem using NSString as keys and NSNumber as values. I suspect that your custom class does not properly implement hash and/or isEqual. Specifically, the results from those two methods must be consistent, meaning that if isEqual returns true, then the hash values for the two objects must be identical.
You also need to ensure that your class implements NSCopying properly and that a copy is equal to the original.
As a general rule, don't use custom objects for dictionary keys. Just use strings and be done with it.
As user3386109 points out, custom objects must properly implement the -hash and -isEqual methods in order to be used as dictionary keys, and even then, custom objects don't work correctly for dictionary keys for things like key/value coding.
I just migrated my new data model and added a new attribute called "author_mail".However I discover at when I output my records:
attachments = "<relationship fault: 0xd2459c0 'attachments'>";
author = nil;
"author_mail" = nil; <-- ABNORMAL
category1 = World;
I set the author_mail to string type but I don't think the author_mail should wrap with quotation mark. I don't know if it related to my migration but it does not output any error.
Any clue where should I start look on? I found nothing on the internet.
Result I want:
attachments = "<relationship fault: 0xd2459c0 'attachments'>";
author = nil;
author_mail = nil;
category1 = World;
Thanks everyone.
That's not abnormal, and it does not mean what you think it means. Relax, nothing is wrong.
What you're seeing is the result of calling description on NSManagedObject. By default, this is how NSManagedObject formats the result. If a key name contains any non-alphanumeric characters, it puts quote marks around the key name. That's just how they decided to do it. As a result:
This only affects the result of calling description on the object, which is what happens if you call NSLog to print the object.
This does not indicate that the quote marks are part of the key name. If you try to set a value for author_name, you'll find that you should not include the quotes, because they're not part of the name.
This has no effect on anything aside from printing the objects using the description method.
You can and should just ignore this.
If it really bothers you for some reason, create your own subclass of NSManagedObject and override the description method. Make it print whatever you want, with whatever formatting you want.