How does one know when it's safe to use a parent method in NS subclasses? - objective-c

As an example, when I'm using an NSMutableDictionary, I know it inherits all the methods of NSDictionary, but how can I know/trust that it has overridden the behavior of those methods if I want to use NSDictionary methods (such as +dictionaryWithObjectsAndKeys) to create my mutable dictionary instance?
More generally, is it the Framework's responsibility to make sure subclasses don't blindly inherit methods that can potentially break instances of the subclass if used? Or is it the coder's responsibility to know not to use them? If Square inherits from Rectangle, and via inheritance I can call
Square *newSquare = [[Square alloc] init];
[newSquare setWidth:3 andHeight:6]; //instead of -(void)setSide:(int)side
I've "broken" the square and other methods which depend on width being equal to height will not work now. What are the rules of the game?

The rule would be only expose what you would allow to be override it means, put on your interface what is really public. When necessary explicitly state that when overriding an specific method call at some point [super methodName].
On your example you would override the method - (void)setWidth:(int)width andHeight:(int)height, and you would like to throw an error if width != height. Or you could also throw an error and force the user to only use - (void)setSide:(int)side.
For example you could do:
// If you want to test and accept cases when width == height
- (void)setWidth:(int)width andHeight:(int)height {
NSAssert(width == height, NSLocalizedString(#"This is a Square. Width has to be height.", nil));
[super setWidth:width andHeight:height];
// Or
[self setSide:width];
}
// Or if you want to completely prohibit the usage of the method
- (void)setWidth:(int)width andHeight:(int)height {
NSAssert(NO, NSLocalizedString(#"This is a Square! Please use - (void)setSide:(int)side method.", nil));
}
If you would like to throw some errors and warnings at compilation time, you could use on the declaration of your methods, some of the macros defined on NSObjCRuntime.h.

I wouldn't trust the parent convenience method to call your inheriting init method. For example, that dictionary method could be defined as:
+ (id)dictionaryWithObjectsAndKeys:...
{
return [[[NSDictionary alloc] initWithObjectsAndKeys:...] autorelease];
}
If that method is defined that way then it won't be even be aware of your implementation.
You'd have to create your own convenience method. Something like would be in your MyDictionary implementation:
+ (id)myDictionaryWithObjectsAndKeys:...
{
return [[[MyDictionary alloc] initWithObjectsAndKeys:...] autorelease];
}
--
Also...
You probably should inherit Rectangle from Square. Inheritance is additive. You can describe Square with one size (width), but for Rectangle you have two sizes (width, height).

Related

Non-animatable properties in subclasses of CALAyer

I have defined a subclass of CALayer with an animatable property as discussed here. I would now like to add another (non-animatable) property to that layer to support its internal bookkeeping.
I set the value of the new property in drawInContext: but what I find that it is always reset to 0 when the next call is made. Is this so because Core Animation assumes that this property is also for animation, and that it "animates" its value at constant 0 lacking further instructions? In any case, how can I add truly non-animatable properties to subclasses of CALayer?
I have found a preliminary workaround, which is using a global CGFloat _property instead of #property (assign) CGFloat property but would prefer to use normal property syntax.
UPDATE 1
This is how I try to define the property in MyLayer.m:
#interface MyLayer()
#property (assign) CGFloat property;
#end
And this is how I assign a value to it at the end of drawInContext::
self.property = nonZero;
The property is e.g. read at the start of drawInContext: like so:
NSLog(#"property=%f", self.property);
UPDATE 2
Maybe this it was causes the problem (code inherited from this sample)?
- (id)actionForKey:(NSString *) aKey {
if ([aKey isEqualToString:#"someAnimatableProperty"]) {
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:aKey];
animation.fromValue = [self.presentationLayer valueForKey:aKey];
return animation;
}
return [super actionForKey:aKey]; // also applies to my "property"
}
To access your standard property from within the drawing method, during an animation, you need to make a few modifications.
Implement initializer
When CoreAnimation performs your animation, it creates shadow copies of your layer, and each copy will be rendered in a different frame. To create such copies, it calls -initWithLayer:.
From Apple's documentation:
If you are implementing a custom layer subclass, you can override this method and use it to copy the values of instance variables into the new object. Subclasses should always invoke the superclass implementation.
Therefore, you need to implement -initWithLayer: and use it to copy manually the value of your property on the new instance, like this:
- (id)initWithLayer:(id)layer
{
if ((self = [super initWithLayer:layer])) {
// Check if it's the right class before casting
if ([layer isKindOfClass:[MyCustomLayer class]]) {
// Copy the value of "myProperty" over from the other layer
self.myProperty = ((MyCustomLayer *)layer).myProperty;
}
}
return self;
}
Access properties through model layer
The copy, anyway, takes place before the animation starts: you can see this by adding a NSLog call to -initWithLayer:. So as far as CoreAnimation knows, your property will always be zero. Moreover, the copies it creates are readonly, if you try to set self.myProperty from within -drawInContext:, when the method is called on one of the presentation copies, you get an exception:
*** Terminating app due to uncaught exception 'CALayerReadOnly', reason:
'attempting to modify read-only layer <MyLayer: 0x8e94010>' ***
Instead of setting self.myProperty, you should write
self.modelLayer.myProperty = 42.0f
as modelLayer will instead refer to the original MyCustomLayer instance, and all the presentation copies share the same model. Note that you must do this also when you read the variable, not only when you set it. For completeness, one should mention as well the property presentationLayer, that instead returns the current (copy of the) layer being displayed.

Call a method every time a parameter is set on Objective-C (Cocoa)

I currently have a class with 15 properties (and growing), and I'm finding myself having to call an update method every time one of those properties change.
Currently, I'm overriding every setter with a code like this:
-(void)setParameterName:(NSUInteger)newValue {
if (_param == newValue)
return;
_param = newValue;
[self redraw];
}
The method [self redraw]; being the key here.
Is there a better way to do it? Should I be using keyValue observers (the method observeValue:forKeyPath:ofObject:change:context:)?
Notes:
All properties (so far) are assign (mostly enum, NSUInteger, CGFloat and BOOL);
All those properties are set using bindings (method bind:toObject:withKeyPath:options:). Except when loading from the filesystem (which is not important, as I already call the drawing methods on every object after the loading is done);
The value changes are only for the current object. I do not need to be told when changes occur on other objects;
I have other properties that I don't need to watch the changes on it (because it will have no effect on my output and drawing the output is kinda time-consuming).
Thanks!
Since these properties are updated using bindings, which invoke -setValue:forKey:, you can override that method instead of writing custom setters:
+ (NSArray *) keysAffectingDrawing {
static NSArray *singleton;
if (!singleton)
singleton = [NSArray arrayWithObjects:
#"property1",
#"property2",
#"property3",
nil];
return singleton;
}
- (void) setValue:(id) value forKey:(NSString *) key {
[super setValue:value forKey:key];
if ([[CustomClass keysAffectingDrawing] containsObject:key]) [self redraw];
}
(I was first inclined recommend key-value observing but agree it's not the best solution here. I think the reason is in part that there's only one object, and in part because the design doesn't follow MVC. Usually in MVC an object that draws itself isn't the one with all the properties.)
(Added: Ahh, I see. The model is responsible for rendering the properties to a bitmap, and that's what -redraw does. That's fine MVC. To make it clearer, I recommend changing the name of the method from -redraw to something like -updateImage or -renderImage, since it doesn't actually do any drawing.)
You could use the Key-Value Observing to avoid repeating in all properties setter the method call, however i think that calling the method directly in the setter is not the wrong way to do it, and could even be faster ...

Managing objects of different classes in a single NSMutableArray

I'm looking for advice on whether or not this is a good practice. I apologize for the long form explanation. I have a large grid of x,y coordinates. The grid is occupied by objects of varying classes, all with different methods and data. When a user touches a grid coordinate, I'm looking for the cleanest way to route my program to the proper method, dependent on the object type.
I'll use shapes as an easy way to explain what I'm doing. Say I have 2 classes, Circle and Square both with a parent class of Shape.
I'm adding objects of Circle class and Square class to an NSMutableArray called shapeManager. When a user touches the grid I want to figure out the object type for that coordinate so I can route to the appropriate method.
for (Shape *shape in shapeManager) {
if (shape.type == kCircle) {
[self circleSelected:shape];
}
}
-(void)circleSelected:(circle *)circle { }
Am I recasting the pointer as a different class when I do this? Are there any downsides to this? I'm just looking for a good way to handle a touch event on a grid, when the object that lives at that coordinate is unknown and of multiple possible classes.
The downside to your approach comes if you add another Shape - you end up having to change this code. The other approach is to add a method, say userSelected, to your Shape class and have each subclass override this method to do whatever is appropriate for the kind of shape they represent.
In this other approach your loop becomes:
for(Shape *shape in shapeManager)
[shape userSelected];
And, for example, Circle gains a method:
#implementation Circle
// override Shape's userSelected and do what a circle needs to do
- (void) userSelected
{
...
}
Which approach you choose is up to you, there is no right answer per se, but object-oriented style usually favours the latter.
Comment Followup
To go from a child to a parent you do not need a cast, but can include one - this is a fundamental plank of inheritance-based object-oriented languages like Obj-C.
Going the other way, from parent to child, in Obj-C (a) requires a cast and (b) should be protected by a check - both because you don't know which, if any, of the children you have. In Obj-C (a) just tells the compiler you think you know and it should trust you, (b) is you checking to make sure!
You do (b) with [<obj> isKindOfClass:[<classname> class] which tests if <obj> is of type <classname> or any of its children; or you can use isMemberOfClass which tests if <obj> is of type <classname> but not any of its children. The former is more common to allow for easy expansion (e.g. you may start off with Rectangle being a Shape and later introduce Square being a Rectangle; a test for isMemberOfClass:[Rectangle class] would be YES for both Rectangle and Square while isKindOfClass:[Rectangle class] is only YES for Rectangle).
Explicit testing is commonly not required as method dispatch often subsumes it - as in [shape userSelected] above which will call the appropriate implementation of userSelected based on the actual type of shape at runtime. When explicit testing is required using tests and casts is the way to do it.
And yes, collections of mixed type are common, indeed they are another of the planks of inheritance-based object-oriented languages like Obj-C.
[Note: What Obj-C lacks which a number of other languages have is a way to limit what a collection may contain. E.g. an NSMutableArray can contain any object, while in your case it might be beneficial to be able to say NSMutableArray of Shape to limit it to just Shape and its subclasses. C#, Ada, and even C++ (in as much as it enforces anything) all provide this. If you need to you can do it yourself in Obj-C, see this answer.]
All classes that derive from NSObject inherit a method called isMemberOfClass: that will test for class membership using introspection. You may find this useful for your purposes.
for (Shape *shape in shapeManager) {
if ([shape isMemberOfClass:[Circle class]]) {
[self circleSelected:(Circle*)shape];
}
else if ([shape isMemberOfClass:[Square class]]} {
[self squareSelected:(Square*)shape];
}
}
There is also an isKindOfClass: method that does a similar test, but will also return true if the receiving object is a subclass of the class you are testing against.
How about implementing 'selected' method in the subclasses of Shape, which are Circle and Square class. Then the object can call 'selected' method directly.
for (Shape *shape in shapeManager) {
[self selected];
}
Circle implementation
#interface Circle: Shape
{
}
#implementation Circle
-(void)selected
{
// do your circle select stuff here
}
#end
Square implementation
#interface Square: Shape
{
}
#implementation Square
-(void)selected
{
// do your square select stuff here
}
#end

Objective-C pattern for class instance variables?

What would be a nice pattern in Objective-C for class variables that can be "overridden" by subclasses?
Regular Class variables are usually simulated in Objective-C using a file-local static variables together with exposed accessors defined as Class methods.
However, this, as any Class variables, means the value is shared between the class and all its subclasses. Sometimes, it's interesting for the subclass to change the value for itself only. This is typically the case when Class variables are used for configuration.
Here is an example: in some iOS App, I have many objects of a given common abstract superclass (Annotation) that come in a number of concrete variations (subclasses). All annotations are represented graphically with a label, and the label color must reflect the specific kind (subclass) of its annotation. So all Foo annotations must have a green label, and all Bar annotations must have a blue label. Storing the label color in each instance would be wasteful (and in reality, perhaps impossible as I have many objects, and actual configuration data - common to each instance - is far larger than a single color).
At runtime, the user could decide that all Foo annotations now will have a red label. And so on.
Since in Objective-C, Classes are actual objects, this calls for storing the Foo label color in the Foo class object. But is that even possible? What would be a good pattern for this kind of things? Of course, it's possible to define some sort of global dictionary mapping the class to its configuration value, but that would be kind of ugly.
Of course, it's possible to define some sort of global dictionary mapping the class to its configuration value, but that would be kind of ugly.
Why do you think this would be ugly? It is a very simple approach since you can use [self className] as the key in the dictionary. It is also easy to make it persistent since you can simply store the dictionary in NSUserDefaults (as long as it contains only property-list objects). You could also have each class default to its superclass's values by calling the superclass method until you find a class with a value.
+ (id)classConfigurationForKey:(NSString *)key {
if(_configurationDict == nil) [self loadConfigurations]; // Gets stored values
Class c = [self class];
id value = nil;
while(value == nil) {
NSDictionary *classConfig = [_configurationDict objectForKey:[c className]];
if(classConfig) {
value = [classConfig objectForKey:key];
}
c = [c superclass];
}
return value;
}
+ (void)setClassConfiguration:(id)value forKey:(NSString *)key {
if(_configurationDict == nil) [self loadConfigurations]; // Gets stored values
NSMutableDictionary *classConfig = [_configurationDict objectForKey:[self className]];
if(classConfig == nil) {
classConfig = [NSMutableDictionary dictionary];
[_configurationDict setObject:classConfig forKey:[self className]];
}
[classConfig setObject:value forKey:key];
}
This implementation provides no checking to make sure you don't go over the top superclass, so you will need to ensure that there is a value for that class to avoid an infinite loop.
If you want to store objects which can't be stored in a property list, you can use a method to convert back and forth when you access the dictionary. Here is an example for accessing the labelColor property, which is a UIColor object.
+ (UIColor *)classLabelColor {
NSData *data = [self classConfigurationForKey:#"labelColor"];
return [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
+ (void)setClassLabelColor:(UIColor *)color {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:color];
[self setClassConfiguration:data forKey:#"labelColor"];
}
my answer here may help:
What is the recommended method of styling an iOS app?
in that case, your annotation just holds a reference to a style (e.g. you need only one per style), and the size of a pointer for an entire style is not bad. either way, that post may give you some ideas.
Update
Jean-Denis Muys: That addresses the sample use case of my question, but not my question itself (a pattern to simulate class instance variables).
you're right, i didn't know how closely your example modeled your problem and i considered commenting on that.
for a more general and reusable solution, i'd probably just write a threadsafe global dictionary if your global data is nontrivial (as you mentioned in your OP). you could either populate it in +initialize or lazily by introducing a class method. then you could add a few categories to NSObject to access and mutate the static data -- do this for syntactical ease.
i suppose the good thing about that approach is that you can reuse it in any program (even though it may appear ugly or complex to write). if that's too much locking, then you may want to divide dictionaries by prefixes or create a simple thread safe dictionary which your class holds a reference to -- you can then synthesize an instance variable via the objc runtime to store it and declare an instance method to access it. the class method would still have to use the global data interface directly.

Pull-up refactoring, Objective-C

I have two similar classes, MultiSlotBlock and SingleSlotBlock. They have started to share a lot of common code so I have decided to do some refactoring and pull some of the methods up to a new superclass, let's call it Block.
Now one of the methods that I pull up, simplified for the example, looks like this:
// (Block.mm)
- (void)doACommonBehaviour
{
// .. does some stuff
[self doAUniqueBehaviour];
}
The problem here is that [self doAUniqueBehaviour] is showing a warning because of course my superclass doesn't implement this method anywhere.
The two solutions I thought of don't sound great to me. One is to use a protocol (the way I am currently doing it) like so:
// (Block.mm)
- (void)doACommonBehaviour
{
// .. does some stuff
if ([self conformsToProtocol:#protocol(UniqueBehaviourProtocol)])
{
id<UniqueBehaviourProtocol> block = (id<UniqueBehaviourProtocol>)self;
[block doAUniqueBehaviour];
}
}
The other is to have a blank method body in my superclass (in this case there would be a lot) and just return doesNotRespondToSelector.
Something is tingling at the back of my mind that I should be using the Strategy Pattern, but I might be way off, and I haven't thought through how that would be implemented.
Any ideas? Thanks.
EDIT: I know for a fact that doAUniqueBehaviour will be implemented in all subclasses, it is just the implementation that will differ.
The superclass should not know about its subclasses. You should implement the
- (void)doACommonBehaviour method in every subclass and there:
- (void)doACommonBehaviour
{
[super doACommonBehaviour];
[self doAUniqueBehaviour];
}
EDIT - clarification:
If all the subclasses are going to implement -doAUniqueBehaviour then it should be implemented in the superclass (even empty) and each subclass will override it to its needs.
If subclass1 implements -doAUniqueBehaviour1, subclass2 implements -doAUniqueBehaviour2 etc then do what I propose above; eg. in subclass1:
- (void)doACommonBehaviour
{
[super doACommonBehaviour];
[self doAUniqueBehaviour1];
}
There is not such concept as abstract class in Objective-C. In order to avoid the warning, you have to provide a default implementation in your base class. Usually, this implementation will throw a doesNotRespondToSelector error at runtime:
- (id)someMethod:(SomeObject*)blah
[self doesNotRecognizeSelector:_cmd];
return nil;
}
Note: the _cmd argument is the invoked selector.
#Dimitri's suggestion will work, but instead of forcing each subclass to implement the same method, you can declare it once in Block, and just above that method (in the implementation file, not header) declare the unique method like so:
- (void) doUniqueBehaviour { }
- (void) doCommonBehaviour {
// any common code you need
[self doUniqueBehaviour];
}
This will prevent any compiler warnings, and you can override -doUniqueBehaviour in subclasses as you like. It also avoids code duplication and reduces the potential for changing the code in one subclass but not another. Plus, you don't need a separate protocol, and dynamic typing is preserved.