property inheritance: Auto property synthesis will not synthesize property - objective-c

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)...

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.

Quick inquiry about ivars scope [duplicate]

If you have a property in your public interface like the following
#interface MyClass : NSObject
#property(strong) NSString *myProp;
#end
And then synthesize it, in effect synthesizing the variable:
#implementation MyClass
#synthesize myProp = _myProp; // or just leave it at the default name..
#end
What is the visibility of the instance variable _myProp? That is, is this considered #public, #protected or #private? I'm guessing since MySubClass could inherit from MyClass then it would also get the properties (naturally), but would it also inherit the instance variable visibility?
What difference does it make if I put the property in a class extension? That would hide the property from subclasses, and I'm guessing the instance variable, too. Is this documented anywhere?
A synthesized ivar is completely invisible to all code that cannot see the #synthesize line (which basically means anything outside of the .m file). It's not #protected, it's not #private, it's simply unknown. With a #private ivar, other code trying to access it will be told that it's private, but with a synthesized ivar, other code trying to access it will be told that the field simply doesn't exist.
As a thought experiment, try imagining a situation where the ivar acted like it was #protected. You make a subclass, and you muck about with the ivar there. Now you go back to the superclass and change #synthesize myProp to #synthesize myProp=foo. What happens in the subclass? When the compiler processes the subclass, it cannot see the #synthesize line, so it would have no idea that you just changed the name of the ivar. In fact, it cannot even tell if the property is backed by an ivar at all, or if it's implemented with custom-written accessor methods. I hope it's obvious why this means that the subclass cannot possibly access the ivar, and neither can any other class.
That said, I'm not quite sure what the compiler does if you write code in the same .m file that tries to access the ivar. I expect it will treat the ivar as #private (since the compiler can, in fact, see that the ivar exists).
Also, none of this has any bearing on the runtime methods. Other classes can still use the obj-c runtime methods to dynamically look up your class's ivar list and muck about with it.
If it is declared in your interface it is virtually public when using the #property declarative. If you want to use #property declaratives and keep them property truly private, you should create a private category in your implementation.
MyClass.h
#interface MyClass : NSObject {
#private
NSObject* foo;
}
#end
MyClass.m
#import "ClassWithPrivateProperty.h"
#interface MyClass ()
#property (nonatomic,retain) NSObject* foo;
#end
#implementation MyClass
#synthesize foo;
// class implementation...
#end
A synthesized variable acts as if declared #private:
#interface Garble : NSObject
#property (copy) NSString * s;
#end
#implementation Garble
#synthesize s;
#end
#interface Bargle : Garble
#end
#implementation Bargle
- (void) useS {
NSLog(#"%#", s); // error: instance variable 's' is private
}
#end
I swear I've seen this in the docs, but I can't find it right now. Will update if I track it down.
You can create a dynamic property and indicate it to the compiler that its instantiation would be at run time.
And then in your subclass write your own getter or synthesize the property.
#interface BaseClass : NSObject
#property (nonatomic, strong) NSString *ThisWillBeSynthesizedInRespectiveSubclasses;
#end
#implementation BaseClass
#dynamic ThisWillBeSynthesizedInRespectiveSubclasses;
#end
In Sub classes
#interface Subclass : BaseClass
#end
#implementation Subclass
#synthesize ThisWillBeSynthesizedInRespectiveSubclasses = _ThisWillBeSynthesizedInRespectiveSubclasses;
#end
or you write your own setter / getter methods.
Hope this helps !
Other classes have access to everything that they #include. In other words, to everything that is inside your header.
If something appears only in your implementation file, other classes (including subclasses) don't know it exists. A synthesized property is like that. Other classes know only about the property (a property means a getter and a setter method) but they don't know anything about the inner implementation of its methods.
Note, that the access specifiers (public/private/protected) in obj-c are only a hint to the compiler that even if something appears in the header file, it can't be accessed. The runtime does not check it in any way.
What happens if you put it into a class extension? Note that a property is a set of two methods. You just hide the methods from every class which includes your class main header but not the class extension header.
We use this for example to declare a property as readonly and in class continuation we declare it as readwrite. Then, we can use the setter only from inside of the class.

Public iVar; readonly from other classes

What is the best way to make an iVar writeable by its owning class, but readonly by other classes?
Is there more than one way?
The only way I can think of is to set a #property (readonly) for the iVar, but not use dot notation inside the owning class (which I'm guessing wouldn't work with readonly), and in the owning class just reference it directly, without dot notation, then in other class, reference it with dot notation.
But I'm curious if there are other methods.
You can make a property read/write just for the implementation. You do this using a class extension, or anonymous category, in your implementation. Easier to demonstrate so, for example, in your .h:
#interface MyClass
#property (readonly) NSInteger age;
...
#end
and in your .m:
#interface MyClass () // class extension/anonymous category for private methods & properties
// implementation of these go in main #implementation
#property (readwrite) NSInteger age;
...
#end
#implementation MyClass
#synthesize age;
...
#end
Now you can use the property within your class read/write and from outside as read-only.
You do the same for private methods.
[Note: This is Objective-C so the above isn't bullet proof - there are ways around it to call the properties setter - but the compiler will flag errors which assign to the property from outside the class.]
After comments:
[Note 2: an anonymous category/class extension is very similar to a named category. The former must be implemented in the main implementation, the latter may be implemented in an #implementation classname (categoryname) or in the main implementation. Furthermore only the main interface, the interface for a class extension/anonymous category, and the main implementation may declare instance variables; interfaces and implementations for named categories may not. Properties may be declared in both anonymous and named categories, however they may only be synthesized in the main implementation and not in named category implementations. This note is correct at press time, some of these features have changed as Objective-C/Xcode develops.]
Use the private specifier for ivars and a class extension to define the accessor - that way the ivar is private to the class.
// FooClass.h
#interface FooClass : NSObject {
#private int boo;
}
#end
// FooClass.m
#interface FooClass () {
}
#property (nonatomic,assign) int boo;
#end
#implementation FooClass
#synthesize boo;
// ....
#end

What is the visibility of #synthesized instance variables?

If you have a property in your public interface like the following
#interface MyClass : NSObject
#property(strong) NSString *myProp;
#end
And then synthesize it, in effect synthesizing the variable:
#implementation MyClass
#synthesize myProp = _myProp; // or just leave it at the default name..
#end
What is the visibility of the instance variable _myProp? That is, is this considered #public, #protected or #private? I'm guessing since MySubClass could inherit from MyClass then it would also get the properties (naturally), but would it also inherit the instance variable visibility?
What difference does it make if I put the property in a class extension? That would hide the property from subclasses, and I'm guessing the instance variable, too. Is this documented anywhere?
A synthesized ivar is completely invisible to all code that cannot see the #synthesize line (which basically means anything outside of the .m file). It's not #protected, it's not #private, it's simply unknown. With a #private ivar, other code trying to access it will be told that it's private, but with a synthesized ivar, other code trying to access it will be told that the field simply doesn't exist.
As a thought experiment, try imagining a situation where the ivar acted like it was #protected. You make a subclass, and you muck about with the ivar there. Now you go back to the superclass and change #synthesize myProp to #synthesize myProp=foo. What happens in the subclass? When the compiler processes the subclass, it cannot see the #synthesize line, so it would have no idea that you just changed the name of the ivar. In fact, it cannot even tell if the property is backed by an ivar at all, or if it's implemented with custom-written accessor methods. I hope it's obvious why this means that the subclass cannot possibly access the ivar, and neither can any other class.
That said, I'm not quite sure what the compiler does if you write code in the same .m file that tries to access the ivar. I expect it will treat the ivar as #private (since the compiler can, in fact, see that the ivar exists).
Also, none of this has any bearing on the runtime methods. Other classes can still use the obj-c runtime methods to dynamically look up your class's ivar list and muck about with it.
If it is declared in your interface it is virtually public when using the #property declarative. If you want to use #property declaratives and keep them property truly private, you should create a private category in your implementation.
MyClass.h
#interface MyClass : NSObject {
#private
NSObject* foo;
}
#end
MyClass.m
#import "ClassWithPrivateProperty.h"
#interface MyClass ()
#property (nonatomic,retain) NSObject* foo;
#end
#implementation MyClass
#synthesize foo;
// class implementation...
#end
A synthesized variable acts as if declared #private:
#interface Garble : NSObject
#property (copy) NSString * s;
#end
#implementation Garble
#synthesize s;
#end
#interface Bargle : Garble
#end
#implementation Bargle
- (void) useS {
NSLog(#"%#", s); // error: instance variable 's' is private
}
#end
I swear I've seen this in the docs, but I can't find it right now. Will update if I track it down.
You can create a dynamic property and indicate it to the compiler that its instantiation would be at run time.
And then in your subclass write your own getter or synthesize the property.
#interface BaseClass : NSObject
#property (nonatomic, strong) NSString *ThisWillBeSynthesizedInRespectiveSubclasses;
#end
#implementation BaseClass
#dynamic ThisWillBeSynthesizedInRespectiveSubclasses;
#end
In Sub classes
#interface Subclass : BaseClass
#end
#implementation Subclass
#synthesize ThisWillBeSynthesizedInRespectiveSubclasses = _ThisWillBeSynthesizedInRespectiveSubclasses;
#end
or you write your own setter / getter methods.
Hope this helps !
Other classes have access to everything that they #include. In other words, to everything that is inside your header.
If something appears only in your implementation file, other classes (including subclasses) don't know it exists. A synthesized property is like that. Other classes know only about the property (a property means a getter and a setter method) but they don't know anything about the inner implementation of its methods.
Note, that the access specifiers (public/private/protected) in obj-c are only a hint to the compiler that even if something appears in the header file, it can't be accessed. The runtime does not check it in any way.
What happens if you put it into a class extension? Note that a property is a set of two methods. You just hide the methods from every class which includes your class main header but not the class extension header.
We use this for example to declare a property as readonly and in class continuation we declare it as readwrite. Then, we can use the setter only from inside of the class.

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

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.