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.
Related
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.
Currently I am trying to loop through NSArray which contains NSManagedObject.
When I am trying to cast the fetched object its throwing me an error.
Here is the code
for var i = 0; i < self.displayedHistoryListContent.count ; i=i+1{
var productObject: Product = self.displayedHistoryListContent.objectAtIndex(i) as Product
}
Product is my NSManagedObject.
Application crashes at the line where I am doing casting 'as Product'
Can someone tell me where I am going wrong?
Are you sure that the objects in the array are in fact of the class Product? When dealing with NSManagedObject's it is easy to get confused and refer to a set instead of the object itself.
You probably know that a cast is not a conversion?
Use a println() to see wat kind of object is really in there
It really looks like your array does not contain Products only. Try with as? instead of as to confirm this. You can use NSLog to see what is in the array when you expect a Product.
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 have a form that I'm creating and to simplify things, I'm trying to create a form field mapper to an object. As such, I create the following dictionary:
self.fieldPropertyMapper = #{
#(CompanyFieldName):self.company,
#(CompanyFieldDescription):self.company.description,
#(CompanyFieldWebsite):self.company.website,
#(CompanyFieldTwitter):self.company.twitter,
#(CompanyFieldAddress):self.company.address,
#(CompanyFieldAddress2):self.company.address2,
#(CompanyFieldCity):self.company.city,
#(CompanyFieldState):self.company.state,
#(CompanyFieldZipcode):self.company.zipcode,
#(CompanyFieldPhone):self.company.phone
};
The keys here are members of the CompanyFieldType enum.
My goal here is to later in my form to assign a value to the returned pointer. Here's what I mean: when a text field in one of my forms stops editing, I'm looking to set the value. Here's what I'd like to accomplish:
- (void)textFieldDidEndEditing:(UITextField *)textField
{
CompanyFieldType fieldType = [self fieldTypeForTag:textField.tag];
// Set the value of the respective company property
// In theory it would be something like:
// self.fieldPropertyMapper[#(fieldType)] = textField.text;
}
I'm assuming there's a way to assign by reference but I'm forgetting how to do this. (Is it using the & symbol or **?) I don't remember. Help appreciated! If I'm messing up my terminology, feel free to let me know.
You can't do exactly what you want to do. That is to say, there is no pointer magic that will do what you want.
You can get essentially the same effect, though, with key-value coding. Instead of storing the result of accessing the property (e.g. self.company.website), instead you want to just store the key path to the value you're interested in as a string — e.g. #"company.website". Then you can do like so:
[self setValue:textField.text forKey:self.fieldPropertyMapper[textField.tag]];
Using NSMapTable initialized with NSPointerFunctionsStrongMemory for the keys and NSPointerFunctionsOpaqueMemory for the values. Then you could store the addresses of your iVars backing your properties as the values in the table.
[self.mapTable setObject:&_company forKey:#(CompanyFieldName)];
Haven't tested this but this should get you started.