Use of #synthesize/#property in Objective-C inheritance - objective-c

If you have Class A with an instance var "foo" which has a #property/#synthesize directive, and Class B inherits from Class A, does it also need to #property/#synthesize "foo"? The reason I ask is because when I try to use Class B's "foo", the calling class says that "foo" is not something of a structured union or a member, which makes me believe it needs to be explicitly synthesized.

No, you don't. Synthesized properties are added to class A and its subclasses automatically.

If you have Class A with an instance var "foo" which has a #property/#synthesize directive, and Class B inherits from Class A, does it also need to #property/#synthesize "foo"?
No.
The reason I ask is because when I try to use Class B's "foo", the calling class says …
No, the compiler says it.
… that "foo" is not something of a structured union or a member, which makes me believe it needs to be explicitly synthesized.
It is. In class A.
The compiler is giving you that warning because it doesn't know about the #property, which is because you have neither declared it nor imported a header that declares it. You say that class A's header declares the property, so import class A's header into class B's implementation, so that the compiler knows about the property when compiling class B.

Just in case this helps someone.
I came across this problem too and read these answers and still couldn't access super class variables directly. They were declared as properties and synthesized in the super class and and I had imported the header into my subclass. I was stuck until I discovered I needed to declare the member variables in the #interface section in the super class as well as a property of the superclass....! e.g.
#interface BuoyAnnotation : NSObject <MKAnnotation>
{
CLLocationCoordinate2D coordinate;
CLLocation* location;
int type;
}
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, retain) CLLocation* location;
#property (nonatomic, assign) int type;

WHen inheriting you should not need to redeclare any properties or variables.
Perhaps if you post your ClassB header file or a portion of then people can better pinpoint your problem.

Correct, you just declare a #property outside of the typical member variable declaration curly brackets and then #synthesize the property in the .m file. I did notice that in the child class you have use self.propertyName to reference it but in the parent class you can just use the instant variable name.

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.

Controlling access to instance variables in Objective-C

From all code I've seen, almost always is used something like this for property scope definition:
Class extension
/*We declare the class extension*/
#interface MyClass ()
#property (nonatomic, retain) Type *aPrivateProperty;
- (void)aPrivateMethod;
#end
/*
We can use the main implementation block to implement our properties
and methods declared in the class extension.
*/
#implementation MyClass
/*Therefore we can use synthesize ;-)*/
#synthesize aPrivateProperty;
- (void)aPrivateMethod {
//Some code there
}
#end
But this is (from what I've seen) rarely used:
#interface MyClass : NSObject {
iVar *aProtectedIVar;
#public
iVar *aPublicIVar;
iVar *aSecondPublicIVar;
#protected
iVar *aSecondProtectedIVar;
#private
iVar *aPrivateIVAr;
}
#end
Why modifiers like #private, #protected and #public are not used so much in Objective-C if they are available?
Access modifiers for instance variables are rarely used because they expose more information about the structure of your object than you may wish to allow others to see. An exposure of a public variable is binding on all future implementations to have the same variable. Property, on the other hand, hides the variable, letting you change your mind later on, and compute result instead of storing it.
Property access is highly optimized in Objective-C, so there is virtually no run-time hit for exposing a property instead of a variable. Since you gain flexibility for free by switching to property, exposing variables with #public is rarely used.
I was interested why class extension, (like from example above) is used more often than #private modifier
Because class extension lets you place private properties with your .m file, rather than your .h header file. Headers included from other .m files create compile-time dependencies, which are easily avoided by placing implementation details into class extensions.
You can declare a global variable in three places.
If you declare this in .h is public:
#property (nonatomic, strong) NSString *publicString;
Instead if you declare the same in .m is private there are no need for the second way.

Objective-c Differences

What the difference between declaring an #property in .h or .m file
#property (nonatomic, readwrite, assign) BOOL notificationDidLaunch;
Is it to do with the scope of the variable?
Also in the .h file whats the difference between declaring a string with the brakets like so
#interface AppDelegate : NSObject < UIApplicationDelegate > {
NSString *hat;
}
and doing it outside of them like below
#property (nonatomic, strong) NSString *hat;
As Tiago says, putting an #property declaration inside a class extension in the .m (implementation) file, is a way to make the property private so only the class itself can access it. When declared in the .h (public interface file), it is visible to all code that imports that .h file. Keep in mind that #properties are really just a convenience for declaring and synthesizing accessor methods, and as with all methods in Objective-C, they're never truly private. The best you get is a compiler warning that no public interface declares the method in question if you try to use a non-public method in another class.
For the second part of your question, this declares an instance variable ("ivar") called myString:
#interface MyClass : NSObject
{
NSString *myString;
}
While this declares a property called myString:
#property NSString *myString;
The difference between an instance variable and an #property is more significant than just saying that an ivar is accessible only by your class's instances. Declaring an ivar adds a variable to a class's structure in memory. In contrast, #properties declare/define methods on a class. By default, these methods set/get the value of an associated, and similarly named ivar, but that's not a requirement, and it is perfectly acceptable and quite common to have methods for an #property that don't access an ivar directly. Say for example a class that has a firstName and lastName properties backed by _firstName and _lastName ivars, along with a third, fullName property that simply concatenates the value returned by the firstName and lastName getter methods together (and/or splits a two part name in its set method).
A summarized explanation
A #property inside the .m is private to the class and in the .h is public.
The difference between declaring inside brackets or without brackets is the meaning of the variable.
Inside the brackets you declare an instance variable (or ivar) that is meant to be acessible only by your classes' instances. A property (declared in the .h) is meant to be acessible by any class.
Properties
A #property essentially defines a set and a get that you can override. When you do:
AppDelegate myAppDelegate;
myAppDelegate.hat = #"A hat":
You are essencially doing:
[myAppDelegate setHat:#"A hat"]
And when you do
myAppDelegate.hat //so you can get the property's value
you are essencially doing
[myAppDelegate hat]
Overriding Sets and Gets
When you do #synthesize hat = _hat you are essentially creating a get and a set that has an instance variable _hat associated. This instance variable should only be accessed in your gets/sets and even inside your class you should use your sets/gets (using self.property)
You can override the set and get created by the #synthesize overriding the following methods:
- (void) setHat:(NSString*) aHat
- (NSString *) hat

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.

Objective C class reference as property

This should be easy as hell, but I can't figure out the syntax on my own.
Couldn't really formulate the question correctly so I couldn't Google the answer. (you can get why with keywords like objective c, property, class)
Anyhow. In one of my classes I want to save a property which references another class, NOT an instance of another class. Which you easily can accomplish with this code:
#property (nonatomic, assign) Class anotherClass;
Although, I don't want to use the generic Class. I want to use my own classes, but I can't figure how, guess I'd like to do something like #property (nonatomic, assign) #class(MyOwnClass) myClass;
Objective-C does not allow for stack based objects. I don't think you'll be able to do this. You'll have to store a pointer to an instance of a class. class is a method of NSObject, and returns a Class object, which is an instance of meta-class. This is why it works with just class, because you're saving the instance of the meta class object.
You can accomplish this using protocols. Declare your Class property to be a Class object conforming to your new protocol (it need't even have methods), e.g.
#protocol MyProtocol
#end
#property (nonatomic, assign) Class<MyProtocol> anotherClass;
Now simply declare conformance to MyProtocol in all base classes you wish to accept for anotherClass.
You can use a custom setter which raises an NSInvalidArgumentException exception if the value isn't the class you are looking for. You need to use Class.
Due to the fact that every object or class argument is id in Objective-C you can't raise a compile error, just document your code well.
Objective-C doesn't have anything like templates or covariant/contravariant return types. There's no way to say "I want to return a Class object which represents a class which is a subclass of MyOwnClass." You have to use the generic Class pointer.
Maybe I am confused, but couldn't you do this?
Temp.h
#interface Temp : NSObject
NSString *myString;
#end
#property(nonatomic,assign) NSString *myString;
Temp.m
#import "Temp.h"
#synthesize myString;
MyNewClass.h
#import "Temp.h"
#interface MyNewClass : NSObject
{
}
-(NSString) returnTemp;
#end
MyNewClass.m
#import "MyNewClass.h"
- (NSString) returnTemp
{
Temp *myTemp = [[Temp alloc] init];
[myTemp setMyString:#"hello"];
return myTemp;
}