Skip to content
Dan Hassin edited this page May 24, 2012 · 33 revisions

Summary

This article is on subclassing subclasses of NSRRemoteObject – subclassing your own already-linked class. This isn’t a common case and the following shouldn’t be your concern if you are simply subclassing NSRRemoteObject and nothing else. However, this is possible if you have a hierarchy of Rails models and you wish to parallel that structure in Objective-C.

For these examples, assume we have a “base class” of GeoObject, which inherits from NSRRemoteObject. GeoObject has coordinate properties that we want to share with our Rails server. Suppose we also have classes like GeoUser and GeoNote that inherit from GeoObject (in order to include the coordinate properties), along with their own properties.

The goal here is to allow these classes to communicate all or certain parts of the class hierarchy:

Properties

By default, your subclasses (GeoUser, GeoNote) will inherit all NSRMap properties defined in the “base class” (GeoObject). (* will only apply to properties of that class specifically.) However, if you want to turn this feature off and only have your subclasses (GeoUser) consider their own NSRMap properties and nothing else, add the constant NSRNoCarryFromSuper anywhere in that class’s NSRMap. Here’s an example where GeoUser would act like a subclass in Objective-C, but only communicate its own properties to its corresponding model in Rails, inheriting no sharables:

@implementation GeoUser
NSRMap(*, NSRNoCarryFromSuper)
//or NSRMap(username, password, NSRNoCarryFromSuper)
...
@end

Another way to do this with more precision is to use the -x property flag in your subclass. Defining this flag on an inherited property will exclude it from any inherited NSRMap properties. For example, if we have an owner property that’ll be relevant to all subclasses of GeoObject except for GeoUser (but say we still want to keep the coordinate properties), we’ll define NSRMap something like this:

@implementation GeoUser
NSRMap(*, objectOwner -x)
...
@end

Important note

Regardless of what you do, every class that subclasses NSRRemoteObject directly or indirectly (inherits from a “base class” like GeoObject) should define NSRMap, even if its parameters are blank. This is important due to the way the macro works.

Custom model names

If you set a custom model name using NSRailsUseModelName anywhere along the hierarchy, that config or model name will apply to every class underneath it in the hierarchy that doesn’t itself implement that macro. This is where you have to be careful.

For example, if the GeoObject model is simply “geo” in your Rails app (with controller “geos”), you would set the model name like so in the GeoObject implementation:

@implementation GeoObject
@synthesize coordinates;
NSRailsUseModelName(@"object")

@end

However, if the GeoNote class implements the NSRMap macro and nothing else, it’ll also inherit the custom model name. To override this:

@implementation GeoNote
// without defining one of those macros, GeoNote will inherit the model name defined for GeoObject! (Not good!)
NSRailsUseDefaultModelName    // use default behavior (ie, get model name from class name - would be "geo_note")
//or:
NSRailsUseModelName(@"note")  // can be used again to define a custom model name for this subclass

@end
  • Just a note: if NSRailsUseDefaultModelName was used here, and you then have a class that inherits from GeoNote, say, GeoLoveNote, GeoLoveNote would “inherit” NSRailsUseDefaultModelName. Meaning, it would default to normal behavior.

For obvious reasons, when dealing with model names you will typically want to override it in every class in the hierarchy. (Only if at least one of the classes in the hierarchy uses a custom name!)

Custom configs

If you set a custom config model name using NSRailsUseConfig anywhere along the hierarchy, that config or model name will also apply to every class underneath it in the hierarchy that doesn’t itself implement that macro. This is also where you have to be careful.

Inheriting custom config settings could have more use than inheriting model names, ie, if you want every class in that hierarchy to use one config:

@implementation GeoObject
NSRailsUseConfig(@"non-default.domain.com", @"otherUsername", @"password")
@end

This will make GeoNote, which inherits from GeoObject, also use this config. If this is not the desired behavior, the pattern used above for model names applies:

@implementation GeoNote

// without defining one of those macros, GeoNote will inherit the Config defined for GeoObject
NSRailsUseDefaultConfig                      // use default behavior (ie, use NSRConfig's defaultConfig)
//or
NSRailsUseConfig(@"notesserver.domain.com")  // can be used again to define a custom config for this subclass

...
@end
Clone this wiki locally