4
votes

I have created a document-based app that uses Core Data. I created the mac version first, and now that it's working properly, I am moving on to create an iOS version of it.

I just can't get my head around how to maximize code reuse between the iOS/mac versions, with respect to the Core data bit, since they don't use the same classes.

My document class that handles saving and such is a subclass of NSPersistentDocument. My intention is that a well-designed model class should work in both environments, especially since I don't do all that much fancy stuff with regards to Core data.

Now, since NSPersistentDocument isn't available in iOS, I hit a wall. I tried to get around this by using #if TARGET_OS_MAC and TARGET_OS_IPHONE and in that manner make it a subclass of UIManagedDocument in the iOS version. That obviously would have been convenient, but I can't seem to make it work like that. And it's really looks quite messy, since there are a lot of other stuff that has to be conditionalized as well.

I also tried building the classes atop of NSDocument/UIDocument instead, implementing the Core data hooks myself, but it also looks quite messy, leaving me thinking it's not the right way to go.

The question:

To me, it seems like a good idea to reuse the same document class between the iOS/mac versions, but maybe I'm being naive.

What's the best way to do this?

Should I forget about the code sharing and create a separate document class for the iOS version that emulates all the methods present in the mac version?

2
I can't speak to this specific scenario, but it might be helpful to consider the general case: you have two classes that must inherit from different superclasses, but you have code you want to share between them. The usual answer to such (in ObjC) is composition: put the shared code into a different class, and reference an instance of that class from both.rickster
This seems like a good idea. Please post is an answer, and I'll pick it. One follow-up question though, it seems like I'm writing 20-30 methods in my composite object that only forwards them to the exact same method on the specialized receiver. Is there any nicer way?Frost

2 Answers

3
votes

Am I right that the code you're wanting to share is model-related? I suggest refactoring that code to a separate object, which both an NSDocument and UIDocument contain (as rickster suggested above).

I use a DocumentRoot Core Data entity with its own NSManagedObject subclass, but if there are no properties you want to manage using Core Data, you can just subclass NSObject.

This may sound strange, but NSDocument and UIDocument are actually controller classes. (To be specific, they're part of the model-controller.) Their jobs are to load the model, set up windows, and save the model. If you need to provide an interface for higher-level access to model objects, it could be in a document root or model helper class instead.

Similarly NSPersistentDocument's job is to configure the managed object context and the persistent store and handle loading and saving. It doesn't necessarily need to provide a complete interface for accessing the model.

2
votes

(Bringing this over from my comment.)

In general, the situation where you have two classes which must inherit from different superclasses but which also want to share a lot of code is composition. Put the shared code in a separate class; your NSDocument and UIDocument subclasses can each keep an instance of that class, and message it whenever they need to invoke that shared code. (Though as @noa mentions, you might want to consider whether all of that code belongs in your document class to begin with.)

Of course, then you might end up writing a bunch of methods that read like:

- (id)doSomething {
    return [sharedController doSomething]
}

That can get to be a pain... so you might want to look into Objective-C's message forwarding system.