Why isn't there a default implementation of NSCoding? - ios

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.

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") :)

Cannot assign a value of type 'AnyDataSource<NSManagedObjectSubclass>' to a value of type 'AnyDataSource<NSManagedObject>'

I'm stumped.
The title of this question the compiler error.
I am creating an object that basically marries the delegates of NSFetchedResultsController and UITableViewDataSource. The type parameter is used to indicate which NSManagedObject subclass should be used in the fetch requests.
Here is an example where Swift lacks dynamism and we end up writing all sorts of crazy code, (OR, I'm new to Swift and dislike being told what I'm not allowed to do)
So, on a UITableViewController subclass, i'd like to have a property
var dataSource: AnyDataSource<NSManagedObject>?
when I try to create one of these with a subclass of NSManagedObject and assign it to that property, the compiler complains. There seems to be nothing I can do that will succeed without a warning.
You would think that I should be able to use NSManagedObject or any of its subclasses, so I'm a little confused.
Any ideas? I'm using typical "type erasure" patterns that can be found on the internet, like via realm.io.
Ultimately I found that this approach was not possible. I mean, to achieve these with completely protocol-based programming.
I defined a few base protocols with no associated type, implemented an abstract baseclass that implements that protocol, then introduced generic type parameters in subclasses, that implement further protocols that have associated type.
I'll post my generalized solution on github when it's finished.

how are protocol methods in iOS automatically invoked?

Im trying to understand the high level implementation of protocols without delegates in Apple frameworks. When a subClass conforms to and implements a protocol method, how is that method called? Lets consider the NSCoder protocol methods (encodeWithCoder: and initWithCoder:) for instance.
Without delegates, could you provide any uses cases for protocols (other than achieving polymorphism? I see that some methods could be abstracted away from base classes and grouped into an interfaces but without any implementation (as mixins for instance), what is the significant use?
First, protocol methods are not special in any way. They, like every other Objective-C method, gets called by a message sent to an object. There's nothing special about that part of things. Protocols are basically just a hint to the compiler, though you can query whether an object conforms to one at runtime and make decisions based on that.
You can verify this by implementing a protocol method (or the entire protocol) without declaring that fact in a classes' interface, and call the function on an instance of that object after casting it to be id<YourProtocol>, and it will work.
You can (and sometimes should) call NSCoding methods yourself -- you may decide that you want to persist objects to the disk, and that this is the best way to do it.
NSCoding is actually a great example of why protocols are still useful even though they do not provide any implementation -- the implementation of initWithCoder: and encodeWithCoder: will be different for every class that implements them -- there is no sense in providing an implementation.
Building on that, consider the datasource property of a UICollectionView; as there is no multiple inheritance in Objective-C, it would be undesirable for the datasource to be a class itself, as that would prevent you from using a UIViewController as the data source, and force you to make a whole new class for that express purpose.
Protocols can also be used to implement multiple inheritance in a type safe way without redeclaring the interface of the giver in the inheritor. If the entire interface of the class being inherited from is a protocol, then the inheritor can simply conform to that protocol as well.
Objective-C does provide mixins in the form of Categories, which can implement protocols on existing classes.
For a full throated defense of protocols (in Swift), see the Protocol-Oriented Programming WWWDC 2015 talk.
Taking the example of the NSCoding Protocol, the two required methods in the protocol, basically implement the steps an object should perform to encode itself to be archived. It also implements the initWithCoder to recreate the object from the archive.
Lets say you create a custom object, only your object knows which properties it needs to archive.
When you call a method to archive your custom object, the method call ultimately flow to your encodeWithCoder or initWithCoder to take action specific to your class.
***** Updated ****
Looking at this with an example :
Lets say our data structure looks like this
someArray = [String,CustomObject,aDictionary]
When we want to archive someArray, we call the archiveRootObject method on it. Now inorder for someArray to archive itself, it needs all its contained items to inturn archive themselves. The Array simply instructs the sub items to archiver themselves calling the encodeWithCoder method on them.
By adopting and conforming to the NSCoding protocol, you are just confirming to the root array that Yes, I know how to archive and unarchive myself.
Hope this helps.

Adding properties in Objective-C category

Is it recommended to add properties in categories to an Objective-C class? Is there an official Apple link?
First of all I want to say that Peter Segerblom's answer is not correct. But maybe Daji-Djan's comment is misleading.
From the very beginning:
A declared-property is solely a declaration of two (one – for readonly properties) methods. Period.
This means that it is a declaration.
This means that it refers to methods.
Therefore you can add declared-properties in a category.
But if the property is explicitly or implicitly (Apple: automatically) synthesized, it will synthesize an ivar, if there is none. This is impossible, because it would change the memory footprint of instance objects and a point in time, instance objects are already allocated.
So you have to do one of the things below:
Already having an ivar. (What makes it a bit meaningless.)
No synthesization of the declared-property.
However, this can be useful for computed properties, for properties, whose values are stored in another object, for properties, whose values are stored as associated object, for …
You can do this with associated objects. Although this is not recommended. This link has everything you need to know.
http://nshipster.com/associated-objects/
Section out of the blog:
Associated objects should be seen as a method of last resort, rather than a solution in search of a problem (and really, categories themselves really shouldn't be at the top of the toolchain to begin with).
You can easily do that -- if apple does this, I don't know. They often expose properties in categories though..
anyway, if it makes sense for your design, go ahead! Remember though that while you can add properties, you can't add variables to existing classes.
so either have computed properties, that are a kind of 'convenience wrapper' around existing functionality OR add variables using associated storage
You can't add properties to categories. I think this has something to do with the way memory is handled. Adding instance variables to a already existing object would change the size of the object.

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.

Resources