Up until now, I've been using NSUserDefaults to save my NSMutableDictionaries, but now I want to save a dictionary which would look like this: It'll hold different Car objects with keys: the model of the car. The Car class will have a dictionary of its basic characteristics and a dictionary of Person objects (who use the car). Every Person class will have personal information as properties. I can do everything else, but not the saving of the first NSMutableDictionary which will hold all of that info.(dictionaries must contain only non-property values error) What is an appropriate way to save it?
You have to use an archiver like NSKeyedArchiver to serialise / deserialize your objects to an NSData archive.
All objects in your graph
Car
Person
All properties of these objects not being a value-object
(i.e not NSString, NSDate, NSArray, NSNumber,...)
must adopt the NSCoding protocol. To do so you use:
-(id)initWithCoder:(NSCoder *)coder
{
// Tell the unarchiver how to read your object properties from the archive
_oneObjectProperty = [coder decodeObjectForKey:#"propertyKey"];
.....
}
-(void)encodeWithCoder:(NSCoder *)coder
{
// Tell the archiver how to serialise your object properties
[coder encodeObject:_oneObjectProperty ForKey:#"propertyKey"];
....
}
You'll find code example in here:
Why NSUserDefaults failed to save NSMutableDictionary in iPhone SDK?
You could use NSKeyedArchiver to save objects and NSKeyUnarchiver to retrieve them.
Related
In my iPhone App.
Problem: When I am trying to get the value from dictionary in model class it is giving me the nil values.
Why this is happening, is this the memory management issue ?
I did this,
I am passing NSDictionary, from my viewController to NSMutableArray Category and from that I am passing it to my Modelclass.
If you want to see the coding,
In my ViewController.m file
[arrayNews convertToNewsArticles];
In my NSMutableArray category I am calling method convertToNewsArticles.
for(NSMutableDictionary *dictionary in self) {
NewsArticle *newsArticle=[[NewsArticle alloc] initWithDictionary:dictionary];
[arrayConverted addObject:newsArticle];
}
I am talking about this dictionary that I am passing.
Here is my Model class
-(NewsArticle*)initWithDictionary:dictionary{
self.title=dictionary[#"title"];
self.author=dictionary[#"author"];
self.urlString=dictionary[#"url"];
return self;
}
Update:
I solved by using IAModelBase class on GitHub.IAModelBase
If it is subclass of NSMutableArray then you can add object like,
[self addObject:newsArticle];
in your for loop and return self will return your final mutable array and you can use it as per desired need!
And refer Apple documentation for more detail. You have to implement some mandatory methods if you want to subclass the NSMutableArray.
When I was trying to convert NSDictionary Objects to Model Objects.
I could not pass the whole dictionary to Model class. Like mentioned in the question.
But instead I used,
IAModel classes
Read the readme file.
Also see the 1st Issue,it is solved.
Pull Issue
I am importing a json where the objects have many array attributes such as images:
"images": [
"model1.jpg",
"model2.jpg"
],
"models": []
"one model",
"another model",
"third model"
]
Currently I just do:
[ExampleObject MR_importFromArray:objectArrayFromJson];
but these arrays break this auto import since it can't auto fit NSArray to NSData (the binary from when setting the model up in Xcode).
Is there anyway to modify the Model class files (like custom setters/getters) so the MagicalRecord can import my array and store it in the entitys´ attribute and when I retrieve it I get an NSArray in return?
I solved this myself after some research and I want to share it to whoever might get stuck with same problem.
My problem was that I wanted to save an NSArray into an entity attribute of type NSData. To be able to do this with MagicalRecord I needed to implement a method in my NSManagedObject m-file like this:
- (BOOL) importImages: (id) array {
NSData *imagesData = [NSKeyedArchiver archivedDataWithRootObject:array];
self.images = imagesData;
return YES;
}
so import<;attribute-name without ;> the method must be called.
EDIT:
According to this page you return YES if your code process the data. Return NO if you want MagicalImport to continue processing the attribute and use the default import routines.
I am trying to write a method which will allow me to keep the order of my NSMutableDictionary keys when they are being inserted into the data structure. I know that the NSMutableDictionary works of a hash map, hence not maintaining specific order.
So I need to somehow keep track of the keys which are being inserted into the dictionary, and when retrieving the values from the dictionary, the keys are to be printed(key values) in this same order as when originally inserted. The keys which are inserted into the dictionary are alphanumeric. They just need to be printed out in the same order as when inserted into the NSMutableDictionary.
Can this be achieved? I would like to remain using the NSDictionary Data Structure.
NSDictionary (and all its relations) are unordered collections so to "keep its order" makes no sense as there is no order.
If you are wanting to retrieve objects in a specific order then you need to be using an NSArray. (Or NSOrderedSet if uniqueness of hashes is important).
Simple and naive option
If you have a dictionary structure of...
{
key1:value1,
key2:value2,
key3:value3,
//and so on
}
Then you might be better using something like...
[
{
key1:value1
},
{
key2:value2
},
{
key3:value3
}
]
// i.e. an array of dictionaries
More code but much better option
Or you could create a new collection class as a subclass of NSObject.
In the class you could have something like...
- (void)addObject:(id)object forKey:(id)key
{
self.dictionary[key] = object;
[self.array addObject:key];
}
And...
- (id)objectForKey:(key
{
return self.dictionary[key];
}
And...
- (id)objectAtIndex:(NSUInteger)index
{
return self.dictionary[self.array[index]];
}
And even...
- (void)removeObjectForKey:(id)key
{
[self.dictionary removeObjectForKey:key];
[self.array removeObject:key];
}
You could even make it conform to fast enumeration so you can do...
for (id object in mySuperSpecialCollection) {
}
and make it dispense objects in the order of the array.
Can this be achieved? I would like to remain using the NSDictionary Data Structure.
No. When using instances of NSDictionary the actual class is private. As often with class clusters, it's not possible to subclass NSDictionary and use derived functionality (storing key value pairs).
The best way to go is to set up your own data structure, maybe using an NSOrderedSet and an NSDictionary in conjunction.
Custom object (not derived from NSObject) to be successfully stored in NSUserDefaults.StandardUserDefaults dictionary
I wasn't even able to store a List of string items into the dictionary
NSArchiver also doesn't work on objects which are not derived from NSObject
Is it mandatory to derive objects from NSObject ...
Also if an object contains child objects ( which are non-standard ) are they mandated to be derived from NSOBJECT as well?
You tagged your question as monotouch, so I guess you expect a monotouch answer.
You can wrap your objects as NSObjects quite easily. strings can be wrapped in NSStrings. List can be converted to/from NSArrays.
var nsobject = NSObject.FromObject (myCustomObject);
var string = new NSString ("hello, world");
var array = NSArray.FromStrings ("hello", "world");
NSString and NSArray, are NSObjects
I am not using core data. Just to keep it simple, let's say I have data which were formerly of type NSString, and now they are supposed to be objects of a custom class Person whose only ivar is a "name" ivar of type NSString. In the updated version of the app, I want my Person objects to have their "name" set to whatever the NSString was in the saved data. But suppose my people appear in lots of different places in the app, so telling it how to handle each one individually would be a pain.
What is the best way to handle this? In particular, is there some trick I can do to catch it in the un-archiving process? Or do I have to go through every un-archived object and turn the appropriate NSStrings into Person objects?
You can create a utility class that check the value that come back from your unarchiver, run it through this method. If the value is an NSString, then you can construct a new Person object, if not, then just returns that object back.
+ (Person *)personFromStringOrPersonObject:(id)object {
if ([object isKindOfClass:[NSString class]]) {
// Construct your Person object
Person person = [Person new];
person.name = object;
return person;
} else {
return object;
}
}