Why does the compiler warn when redeclaring base class's readwrite property as readonly in subclass? - objective-c

The Apple doc quoted later seems to indicate this is permissible, though I'll admit never having a reason to do it in a subclass until now.
I have a base class with a public readwrite property and a subclass where I redeclare the property as readonly. The subclass also has a class extension which again redeclares the property as readwrite to achieve the common "public readonly, private readwrite" Objective-C pattern. However, I get the following compiler warning:
warning: Semantic Issue: Attribute 'readonly' of property 'foo' restricts attribute 'readwrite' of property inherited from 'Base'
I'm using Xcode 4.1 build 4B110 with LLVM 2.1 (though LLVM GCC4.2 and GCC4.2 give the same warning) on 10.7.
Here's a stripped-down example which exhibits the compiler warning:
#import <Foundation/Foundation.h>
#interface Base : NSObject
#property (nonatomic, readwrite) BOOL foo;
#end
#implementation Base
#dynamic foo;
#end
// Subclass
#interface Sub : Base
#property (nonatomic, readonly) BOOL foo;
#end
// Class extension
#interface Sub ()
#property (nonatomic, readwrite) BOOL foo;
#end
#implementation Sub
#dynamic foo; // it warns with #synthesize as well
#end
Here's a relevant passage from Apple's The Objective-C Programming Language:
Property Redeclaration
You can redeclare a property in a subclass, but (with the exception of
readonly versus readwrite) you must repeat its attributes in whole in
the subclasses. The same holds true for a property declared in a
category or protocol—while the property may be redeclared in a category
or protocol, the property’s attributes must be repeated in whole.
If you declare a property in one class as readonly, you can redeclare it
as readwrite in a class extension (see “Extensions”), in a protocol, or
in a subclass (see “Subclassing with Properties”). In the case of a class
extension redeclaration, the fact that the property was redeclared prior
to any #synthesize statement causes the setter to be synthesized. The
ability to redeclare a read-only property as read/write enables two
common implementation patterns: a mutable subclass of an immutable class
(NSString, NSArray, and NSDictionary are all examples) and a property that
has a public API that is readonly but a private readwrite implementation
internal to the class. The following example shows using a class extension
to provide a property that is declared as read-only in the public header
but is redeclared privately as read/write.
I redeclare public readonly properties readwrite in class extensions all the time, but I guess I've never had cause to do it an a subclass. However, unless I'm reading it wrong, the paragraphs above seem to indicate that it's kosher. Can anyone set me straight and/or reconcile the apparent conflict between the docs and the compiler?
Why do I want to do this? My real-world situation is more complex, of course. I can make design changes to work around this if needed, but this seemed like the least-friction alternative (the need to do this at all is being driven by other changes).

It says you can redeclare a readonly property as readwrite but you're doing the opposite. You can't/shouldn't do it because it's possible to do this:
Sub* s = [[[Sub alloc] init] autorelease];
Base* b = s;
b.foo = YES; //legal for `Base` objects, but not legal for `Sub` objects
It's a violation of the the Liskov Substitution Priciple.

Related

Will declaring a property in an ObjC category override a property of the same name that's declared on the public interface?

This is not intended to solve any particular problem, just looking to understand the nuances of properties in Objc.
say I have a class Dude
# Dude.h
#interface Dude: NSObject
#property (readonly, nonatomic) NSNumber *height;
#end
I extend the class in the implementation file but change the attributes.
# Dude.m
#interface Dude()
#property (readwrite, atomic) NSNumber *height;
#end
#implementation Dude
#end
I get an error.
'atomic' attribute on property 'height' does not match the property
inherited from 'Dude'
So what is actually going on here. Is the property on the extension the same property? Am I just overriding the accessors?
Also when I change the order so that the public interface is readwrite but the private interface is readonly I get the error:
Illegal redeclaration of property in class extension 'Dude' (attribute
must be 'readwrite', while its primary must be 'readonly')
This makes me think it's an entire redeclaration but now I am less sure about what is actually happening. Looking for clarification.
You can think of this more like a public and private interface.
The interface declared in the .h file is the public interface for your class.
So if you have a reason to declare a property readonly it makes sense there.
The nameless category (Dude()) in your .m file is your private sight on the properties. So you can specify readwrite here to make your class able to change the property internally but not to the outside world.
You can also use these declaration for your methods to declare a public interface in .h and private methods in interface Dude() in .m.
The combination in your public and private interface must make sense, you can't declare a public property readwrite and say internally it is just readonly ...
And finally this is Objective-C: this is just for your editor and compiler. Everything that exists can be accessed even if it is declared some kind of private.
In Apple’s The Objective-C Programming Language, they describe “extensions” as follows, using the redeclaration of a property as an example:
Extensions
Class extensions are like anonymous categories, except that the methods they declare must be implemented in the main #implementation block for the corresponding class. Using the Clang/LLVM 2.0 compiler, you can also declare properties and instance variables in a class extension.
A common use for class extensions is to redeclare property that is publicly declared as read-only privately as readwrite:
#interface MyClass : NSObject
#property (retain, readonly) float value;
#end
// Private extension, typically hidden in the main implementation file.
#interface MyClass ()
#property (retain, readwrite) float value;
#end
...
So, as illustrated here, this pattern is to “redeclare” a property. It’s the same property, though. You only redeclare a property when you want the compiler to synthesize a private setter even though the public interface is declared as readonly. If you don’t redeclare the property as readwrite in the extension, a setter will not be synthesized at all.
Your various warnings actually illustrate the fact that we’re dealing with the same property, because are merely examples where the nature of your redeclaration isn’t compatible with what was included in the public interface.

property inheritance: Auto property synthesis will not synthesize property

Abstract:
This question is about inheritance of properties in combination with different read/write accesses from inside and outside of the classes inheriting the property from one another.
Details:
I have one class A and another class B, which inherits from A. There is the property someProperty declared in A. I want the property to be readonly from outside these classes and read/write from inside.
With only one class, this is dead-simple: You declare the property in the .h as readonly and you declare it again as readwrite in the .m inside of a category. Done.
But with the two classes, one deriving from the other, I get the below compiler warning in B:
Auto property synthesis will not synthesize property 'someProperty'
because it is 'readwrite' but it will be synthesized 'readonly' via
another property
Here is the code:
A.h:
#import <Foundation/Foundation.h>
#interface A : NSObject
// This property shall be readonly from outside, but read/write from subclasses
#property (readonly) SInt32 someProperty;
#end
A.m:
#import "A.h"
#implementation A
#end
B.h:
#import <Foundation/Foundation.h>
#import "A.h"
#interface B : A
#end
B.m:
#import "B.h"
#interface B ()
// compiler warning in the following property declaration:
// /Users/.../B.m:12:41: Auto property synthesis will not synthesize property
// 'someProperty' because it is 'readwrite' but it will be synthesized
// 'readonly' via another property
#property (readwrite) SInt32 someProperty;
#end
#implementation B
#end
Why does this warning appear and how should I structure my code to avoid it?
You need to declare the property as read-write on the owning class (A), and then redeclare on the subclass (B) to make the compiler aware that you want to use it there. So, A hosts the accessor method and B uses it. Generally you don't want B to create another accessor method so you can use #dynamic to tell the compiler that the superclass (technically, just another class) will provide the implementation.
Note that you can also declare a category (not extension) on A, in B.m which declares the accessor method explicitly (not using a property, just a method) as that is what you're actually interested in (you don't actually want any of the other things that a property specifies and you don't really want the maintenance overhead of ensuring that the property attributes match in the super and subclass)...

Many readonly properties, when do I initialise them?

I have a class which has 5 properties which should not be modified by other classes (and subclasses with more of these). I want to make these properties readonly, but I would then have to write a monster -init... to supply values for all these properties.
Of course I could edit the ivars directly, but I don't want to fetch the values in the constructor, as I want to pull those values from the StackExchange API. Separating this into a factory class seems more appropriate here.
tl;dr: How to initialise readonly properties from a factory class without an abnormally long constructor?
It might be a design error. If so, please add an answer suggesting a different approach, because the point of this project is to learn about design.
If you want the factory class to have the ability to update generally readonly properties and you want to avoid exceptionally long init method with a dizzying array of parameters, the typical solution in Objective-C is inelegant, but consists of defining a .h class category (used only by the factory class) that exposes the otherwise private or readonly properties.
For example, consider your CustomObject defined like so:
// CustomObject.h
#import <Foundation/Foundation.h>
#interface CustomObject : NSObject
#property (nonatomic, readonly) NSUInteger identifier; // public interface is readonly
#end
The implementation would define a private class extension that makes it clear that it's really readwrite even thought the public interface is readonly:
// CustomObject.m
#import "CustomObject.h"
#interface CustomObject ()
#property (nonatomic, readwrite) NSUInteger identifier; // it's really readwrite and setter will be synthesized, too
#end
#implementation CustomObject
#end
You can then define category header, that will be used only by the factory class, that exposes the fact that the CustomObject property of identifier is readwrite:
// CustomObject+Factory.h
#import "CustomObject.h"
#interface CustomObject (Factory)
#property (nonatomic, readwrite) NSUInteger identifier;
#end
If you look at <UIKit/UIGestureRecognizerSubclass.h> you'll see a slightly different application of the same concept, in which they expose the notion that the state property is readwrite (whereas it otherwise appears to be readonly).
Normally, in that case, you would make them publicly readonly, but privately readwrite. You can do so by adding a class extension (nameless category at the top of your .m), where you redefine the property without the readonly classifier.
// MyClass.h
#interface MyClass
#property (nonatomic, readonly) NSInteger myProperty;
#end
// MyClass.m
#interface MyClass () // Note the ()
#property (nonatomic) NSInteger myProperty;
#end
Now, within your class you can write the property, but outsiders can only read it.
You can't have it both ways. To my knowledge, Objective-C does not have the concept of "friend" members, meaning members that are accessible to only certain classes. Therefore, your only choice is to create public read-only properties and set their values in the constructor. In essence, your class could be treated as immutable. Yes, the init method may get quite long, but blame that on Objective-C's verbosity for such things. It's still the correct design choice.
MyClass.h:
#interface MyClass : NSObject
#property (copy, readonly, nonatomic) NSString *value1;
#property (assign, readonly, nonatomic) NSInteger value2;
- (instancetype)initWithValue1:(NSString *)value1 value2:(NSInteger)value2;
#end
MyClass.m:
#implementation MyClass
- (instancetype)initWithValue1:(NSString *)value1 value2:(NSInteger)value2
{
self = [super init];
if (self)
{
_value1 = value1;
_value2 = value2;
}
return self;
}
#end
You may also want to consider using JetBrains' AppCode product, as it has refactoring tools that might help with creating init methods from properties (although I haven't done this myself).
You can make constructor with only one parameter (NSArray or NSDictionary, dictionary seems less preferred because of keys), and send all 5 properties values in defined order or with defined key (as you will initialize you objects only in factory you will need to carry about correct order only in one place). In this case, if number of properties grows will be no needs to rename constructor method and adding more and more parameter names.
Also, you can simply use setVale:forKey: method, whith no matter is property readonly.
There are two approaches, and you may be trying to force these two into one model (physical object):
1) If the base provides the storage (e.g. ivars), then the values belong in the initializer. Simple as that - do guarantee the values are readonly for your sanity.
2) Lazy initialization. Your post suggests this is ideal for execution. The answer to this is that storage is an implementation detail. Let your ivars be stored by the class, and written when loaded.
Really, you want to reuse your programs and avoid making monstrous hierarchies and relying on inheritance for reuse. Consider how your 5 properties may be abstracted -- this would be by one or multiple helper classes (e.g. which provide these properties) which adopt a common protocol of the properties they vend. In this way, you may load lazily, copy, use initialization, or a number of other approaches.
Then your "subclasses" would just have a property which contains one of these objects which represents the "Base 5 Properties". Subclasses would not need 5 parameters. They would only need an id<MonBase5Properties> parameter. Again, an implementation (which adopts the protocol) may store the properties, and another may load them on demand. Either way, it's a convenient way to pack up a common set of data or interface into a type (class or protocol).

Objective-C: Compiler error when overriding a superclass getter and trying to access ivar

I'm working on building an iOS 6 app.
I have a class TDBeam which inherits from superclass TDWeapon.
The superclass TDWeapon declares a #property in the TDWeapon.h file:
#interface TDWeapon : UIView
#property (nonatomic) int damage;
#end
I do not explicitly #synthesize the property, as I'm letting Xcode automatically do so.
In the subclass TDBeam I override the getter in the TDBeam.m file:
#import "TDBeam.h"
#implementation TDBeam
- (int)damage {
return _damage;
}
#end
Xcode auto-completes the getter method name, as expected. But when I attempt to reference the _damage instance variable (inherited from the superclass), I get a compiler error:
Use of undeclared identifier '_damage'
What am I doing wrong here? I've tried explicitly adding #synthesize, and changing the name of the _damage ivar, but the compiler doesn't "see" it or any other ivars from the superclass. I thought ivars were visible and accessible from subclasses?
Synthesized ivars are not visible to subclasses, whether they are explicitly or automatically created: What is the visibility of #synthesized instance variables? Since they are effectively declared in the implementation file, their declaration isn't included in the "translation unit" that includes the subclass.
If you really want to access that ivar directly, you'll have to explicitly declare it (in its default "protected" form) somewhere that the subclass can see it, such as a class extension of the superclass in a private header.
There are a lot of posts on this topic on Stack Overflow, none of which offer simple concrete advice, but this topic sums it up most succinctly, and Josh's answer is the best in any.
What he kinda stops short of saying outright, is, if this is the kind of thing you want to do, don't use #property at all. Declare your regular protected variable in your base class as he says, and write you're own setters and getters if you need them. The ivar will be visible to any subclasses who can then write their own setters/getters.
At least that's where i've landed on the issue, although I'd a total newb to subclassing.
The idea of creating private headers to host your anonymous category and re-#sythesizing your ivars in your subclass just seems wrong on so many levels. I'm also sure I've probably missed some fundamental point somewhere.
Edit
Okay after some lost sleep, and inspired by Stanford's 2013 iTunes U course, here I believe is an example solution to this problem.
MYFoo.h
#import <Foundation/Foundation.h>
#interface MYFoo : NSObject
// Optional, depending on your class
#property (strong, nonatomic, readonly) NSString * myProperty;
- (NSString *)makeValueForNewMyProperty; //override this in your subclass
#end
MYFoo.m
#import "MYFoo.h"
#interface MYFoo ()
#property (strong, nonatomic, readwrite) NSString * myProperty;
#end
#implementation MYFoo
// Base class getter, generic
- (NSDateComponents *)myProperty {
if (!_myProperty) {
_myProperty = [self makeValueForNewMyProperty];
}
return _myProperty;
}
// Replace this method in your subclass with your logic on how to create a new myProperty
- (NSString *)makeValueForNewMyProperty {
// If this is an abstract base class, we'd return nil and/or throw an exception
NSString * newMyProperty = [[NSString alloc]init];
// Do stuff to make the property the way you need it...
return newMyProperty;
}
#end
Then you just replace makeValueForNewMyProperty in your subclass with whatever custom logic you need. Your property is 'protected' in the base class but you have control over how it is created, which is basically what you are trying to achieve in most cases.
If your makeValueForNewMyProperty method requires access to other ivars of the base class, they will, at the very least, have to be be public readonly properties (or just naked ivars).
Not exactly 'over-ridding a getter' but it achieves the same sort of thing, with a little thought. My apologies if, in trying to make the example generic, some elegance and clarity has been lost.

Is declare new property in class extension a bad practice in Objective-C?

One strong advantage of class extension is that with class extension you can declare a readonly property in the header file and override this property in class extension as readwrite property. Like below :
//SomeClass.h
#interface SomeClass : NSObject
{
NSInteger someInt; //with modern runtime you can omit this line
}
#property (readonly) NSInteger someInt;
#end
//SomeClass.m
#interface SomeClass ()
#property (readwrite) NSInteger someInt;
#end
#implementation SomeClass
#synthesize someInt;
#end
But if you use a modern runtime ,you can also declare a totally new property in the class extension (which also generate an iVar for that property if there isn't).
//SomeClass.h
#interface SomeClass : NSObject
{
}
#end
//SomeClass.m
#interface SomeClass ()
#property (readwrite) NSInteger someInt;
#end
#implementation SomeClass
#synthesize someInt;
#end
Here's my question : I think declare a totally new property in class extention is somehow has some side effects. Because class extension my not be in the header file and someone else who subclass the class may not know about that "secret property". And if he declare a property with the same name of that "secret property". And this new property's getter and setter method will override the super class's. Isn't this a problem?And why would modern runtime allow such thing happen?
EDIT I posted another question about this topic , please check it out:
The risk of declare new propery in class extension (Ojbective-C) , how to solve it?
I don't think it's bad practice to declare a new property in a class extension. I do this with some frequency. The only reason to include the readonly property in the header in the first place is to allow other classes to get the value, while only you are allowed to modify it. Quite often, that ivar should be of no concern to other classes, and is an implementation detail only. As such, it has no place in the header file.
Implementing this ivar as a private property (a new property only declared in the Class Extension) is still useful, because of the convenient memory management boilerplate code it can abstract for you. Unfortunately, name collisions are just a fact of life in Objective C. Apple lays out some pretty clear naming conventions for you to follow (or not follow) to prevent collisions with their method names. If you're worried about collisions with the getters and setters you've invisibly created with that private property, just adopt and obsessively follow some naming convention for those private property names that you only ever use when implementing a private property. That's the best you're going to do with Objective C, but I personally think the benefits outweigh the risks.