Creating a Model Object with an NSDictionary - ios

This is something I have been playing with, and have yet to make my mind up about.
When querying a database, it is extremely common that you will use the data in the response to create custom model objects. Let's use 'Book' as an example.
I have received JSON describing multiple Book objects. I parse the JSON into an NSArray of NSDictionarys. I now have a few options:
Make all properties on Book mutable (I hate this option). You could then have a BookManager class with takes an NSArray of NSDictionarys and maps the data in the dictionary to the correct properties.
Add an initialiser to the Book object which accepts the important details.
Example:
- (instancetype)initWithTitle:(NSString *)title author:(NSString *)author publishDate:(NSDate *)publishDate;
The aforementioned BookManager class could then take the NSDictionarys as before, but create the Book objects with this initialiser. This is nice, because you could then make all of the public facing properties on Book readonly. However, it is very limited, and if (as is often the case) there are a lot of properties on the model, this is not feasible.
Add an initialiser to Book which accepts the NSDictionary representation of itself. I dislike this approach in one way because I feel the responsibility is not the model's to create itself from a dictionary. I prefer the idea of a manager class mapping the dictionary to the model. However, I do like the fact that it means that all properties can be readonly.
There is no doubt in my mind I am missing other options, and if you are aware of them, please point them out. The aim of this question is to finally determine the best way to approach this scenario.

I regularly use an init method with the important arguments, but yes, it becomes very unwieldily when the number of arguments reach double digits and/or several of the arguments can be nil. The longest such method I have seen in the iOS SDK is CLLocation's
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate
altitude:(CLLocationDistance)altitude
horizontalAccuracy:(CLLocationAccuracy)hAccuracy
verticalAccuracy:(CLLocationAccuracy)vAccuracy
course:(CLLocationDirection)course
speed:(CLLocationSpeed)speed
timestamp:(NSDate *)timestamp
Regarding your last option, adding an initWithDictionary: method to Book could be expanded to also include a class-level method for creating instances of Book from an NSDictionary.
+ (instancetype)bookWithDictionary:(NSDictionary *)dictionary
And optionally a convenient way to get a dictionary representation from a Book instance.
- (NSDictionary *)dictionaryRepresentation
If you search the iOS documentation for "withDictionary" and "dictionaryRepresentation" you will see a few places where this is used. In other SDKs, you will sometimes see the method named as someObjectFromDictionary:

I think u can do this using JSONModel
see this
http://code.tutsplus.com/tutorials/getting-started-with-jsonmodel--cms-19840
https://github.com/icanzilb/JSONModel

Related

Upcasting NSObject to RLMObject

How would you upcast an NSObject to a RLMObject?
Say you have a model object that's of type NSObject, and say you wanted to dynamically upcast it to RLMObject, how would you do it?
It's worth mentioning that RLMObject's properties can't be populated at runtime, else I probably would've done it through <objc/runtime.h>. (I mean.. They technically can... It would just be too much of a hack)
What I'm trying to do:
The main purpose behind this is to create a caching framework that would dynamically choose between interchangeable caching dependencies such as Realm, SQLite, Core Data, etc. For example, I imagine having a preprocessor flag to hopefully switch from using Realm to SQLite, without having to change my models subclass.
This would require all of my models being a subclass of NSObject, simply because RLMObject wouldn't make sense in a SQLite environment for example.
I've been thinking about this a whole lot, and here's my approach:
1) Loop through the NSObject's properties at runtime & create a key/value object of them
2) Create a subclass of RLMObject at runtime and copy the property list from the passed NSObject model
3) Utilize Realm's initWithValue: to populate the properties
What's your opinion?
It looks like this method that you mention - RLMObject.initWithValue or a static equivalent createInDefaultRealmWithValue has to be called on an RLMObject subclass, or else it throws an exception: "Object type 'RLMObject' is not managed by the Realm".
You need a dynamic schema creation API (what underlies RLMObject), that I don't see being a public API.
An alternative would be to manually encode the object to some dictionary or NSData and attach it to a fixed RLMObject subclass.
You might lose some Realm features by not inheriting RLMObject like knowing when the object becomes dirty, but still probably get some success.
I think you'll get the same problem with Core Data. Normally Core Data supports only NSManagedObject subclasses, and moreover it requires you to define a fixed schema in advance in a model file (represented in code by NSManagedObjectModel).
Of course you could just treat your objects as dictionaries of property names and values, and place them into a giant ("type","id","property","value") table, but it is not the best approach (likely to be slow).
The same strategy is possible to implement with the SQLite backend. Interesting to see which schema would you choose for this.
I'd recommend to look at key-value stores as the backend for this, and avoid SQL. Or treat SQL as a key-value store, as in ("type+id", "encoded_object_data") :)

Is the use of id type in method a good practice?

I am creating a set of API and some users have suggested that I use id type for a particular method that can accept custom object (defined by the API) or string instead of creating two versions. Is the use of id type in method a good or acceptable practice? Does Apple do it with their any of their API?
That would be very poor practice. If you're creating an API you need to retain full control, and allowing users to pass any object to your method at which point you would have to cast it to that object or string you mentioned could be fatal depending on what's passed. Creating two methods with different parameters is not only okay, but follows the tenets of polymorphism to the T.
Accepting id is not in itself good or bad practice. How much manual procedural if/then/else/if/then/else nonsense will you acquire? If quite a lot then something is wrong.
Put another way: if the conditional logic related to different kinds of object ends up being implicit, via the Objective-C dispatch mechanisms, then the design is good. If you end up impliedly reimplementing dynamic dispatch then you've gone completely wrong.
Apple does it frequently. Just off the top of my head there are:
as per Nikolai's comment, all the collection types: set, dictionary, array, etc.
anything that takes %# as a format specifier: NSLog, certain methods on NSString, etc.
anything that still uses an informal protocol.
anything in or semi-close to the runtime like key-value coding.
archiving and the user defaults.
anywhere that storage is offered for your own use — the hardy userInfo on NSTimer and the rest.
anywhere that target/action is used — all UIControls, the notification centre, etc.
As per my comment, suppose your custom class had this method:
- (NSData *)dataUsingEncoding:(NSStringEncoding)encoding
And suppose it were the only method being called by whomever is being passed either a string or your custom object. Then id would be the right choice, since you'd have in effect implemented an informal protocol, and the thing being passed an object genuinely doesn't care whether it's a string or not. The only contractual requirement is the informal protocol and the protocol is informal i.e. has no footprint on the type syntax.
Conversely, suppose your custom class had no methods in common with NSString and your code just looked like:
- (void)myMethod:(id)object
{
if([object isKindOfClass:[NSString class]])
[self myMethodOnString:object];
else
[self myMethodOnCustomClass:object];
}
Then id would be inappropriate. You're just obscuring what the method does and implicitly reproducing work that's built into the runtime anyway.

Why isn't there a default implementation of NSCoding?

I understand how to use NSCoding to convert my objects to archive objects. That's not my question.
What I'm wondering is why there isn't a default implementation of NSCoding that could handle probably 99% of cases.
For instance, every time I write a custom class that I want to archive, I perform the following:
Implement -(void)encodeWithCoder: and -(id)initWithCoder:.
Go down my property list, writing a pair of statements (one encode, one decode) for each property.
If the property is an object, I use the encode/decodeObject method.
If the property is a value, I use the corresponding encode/decode method.
I always use the property's name as my key.
I would suspect that almost every implementation of NSCoding is exactly like mine, with the only changes being the particular properties that need to be manipulated.
It seems to me that this would be a perfect place for a standard implementation, with the option to override if your particular case if funky.
Do I have a misunderstanding of what's going on? If not, could I add a category on NSObject to implement this common method on all objects in my projects?
I suspect that the answer to your question is simply that NSCoding was designed long before Objective-C properties existed. (NSCoding was part of the OpenStep spec in 1994, whereas properties arrived with Objective-C 2.0 in 2007.) Additionally, some classes have properties that are not appropriate to be serialized for later.
However, your proposed solution could be a great time-saver! At least one such solution already exists. Check out AutoCoding.

Xcode auto-complete suggests mysterious "songsAtIndexes" for NSArray getter

I have a property of type NSArray on my class called "songs". I'm creating a custom getter for it and XCode gives me an option of creating a method:
songsAtIndexes:(NSIndexSet *)indexes
What is this and why is XCode offering this? Is this specific to NSArray properties? What is the purpose of creating a method/getter for this method? If I don't define it manually, will it be automatically created/synthesized?
This is the result of a little-used KVC optimization for indexed collections which can be used on your class. You can read about this here, but to excerpt:
Indexed To-Many Relationship Compliance
For indexed to-many relationships, KVC compliance requires that your class:
Implement a method named -<key> that returns an array.
Or have an array instance variable named <key> or _<key>.
Or implement the method -countOf<Key> and one or both of -objectInAtIndex: or -<key>AtIndexes:.
Optionally, you can also implement -get<Key>:range: to improve performance.
It's only really used with Core Data with KVC (and occasionally NSPredicates), but you can leverage these methods if you'd like to.
It's really not necessary in 99% of cases to implement this, but you can if you'd like.

A NSZombie of an odd type

so i am getting a NSzombie and it says this
-[__NSArrayI _cfTypeID]: message sent to deallocated instance
Any idea what that is? assumably an array although i thought if it were an NS type it would say.
Yes — that'll be some type of array. Rather than being single classes, most of the foundation types are class clusters. So exactly how you initialise the array affects exactly which subclass of NSArray you get back.
The exact behaviour is undocumented and basically guaranteed to change over time but for example if you created an immutable array with less than a certain number of entries then the system might decide to return a single linked array and perform searches as simple linear searches. If you create one above the threshold then it might instead create an array that adds some sort of hierarchical logic for searching (or, more likely, contains the logic to create suitable hierarchical tables if the user starts trying to search the array).
Related lessons to learn:
never try to subclass a foundation class;
don't expect isMemberOfClass: to work properly;
don't even expect isKindOfClass: necessarily to be able to tell immutable from mutable versions of the foundation classes.
Apple needs a way to differentiate these classes and to flag them as private, so you end up with underscores and suffixes. In practice I think __NSArrayI is a vanilla immutable array.
Basically that means your NSArray object is already deallocated.
Something in Foundation.framework tried to access your NSArray's private method _cfTypeID and crashed.
And about question why there's _cfTypeID method in NSArray object. NSArray Core Foundation counterpart of CFArray. Two type's are interchangeable with "toll-free bridge".
So actually apple uses that method for internal uses.
If you want deeper understand of this. You can visit http://code.google.com/p/cocotron/source/browse/Foundation/NSArray/NSArray.m and this is Cocotron's implementation of NSArray. It is not same with the apple's implementation but still implementations are similar.

Resources