What is default variable access rights type in Objective-C? - objective-c

For example, I have some class A. And then I inherit another class from A.
#interface A : NSObject
{
int _nonHiddenProp;
#private
int _hiddenProp;
}
#property (nonatomic, assign) int property;
#property (nonatomic, assign) int nonHiddenProp;
#property (nonatomic, assign) int hiddenProp;
#end
#implementation A
- (id)init
{
if (self = [super init])
{
_property = 1000;
}
return self;
}
#end
#interface B : A
#end
#implementation TestCapabilitiesChild
- (id)init
{
if (self = [super init])
{
_nonHiddenProp = 1000;
//I cannot call _property and _hiddenProperty
}
return self;
}
#end
But:
A *a = [[[A alloc] init] autorelease];
B *b = [[[B alloc] init] autorelease];
NSLog(#"BClassProperties %d %d %d", b.nonHiddenProp, b.property, b.hiddenProp);
Shows: BClassProperties 1000 1000 0
Why? If I cannot call variable _property in init of B it still is 1000?

You have explicitly declared two instance variables _nonHiddenProp and _hiddenProp of which _nonHiddenProp has visibility to subclasses and _hiddenProp has visibility only to the class it is in. You have also declared three properties: property, nonHiddenProp and hiddenProp.
The first thing to note is that properties are not variables. Properties and instance variables are different things. A property is actually a pair of accessor methods, one to get its value and the other to set its value (the setter may be omitted for read only properties). Note that by "its value" I mean the property's value not the value of any particular instance variable. I might have mentioned this before but properties and instance variables are not the same thing.
As properties are really a pair of methods, the visibility rules for a property are the same as for methods, namely "all methods are public", therefore all properties are also public.
If you do not provide implementations for the property's two accessors and you do not explicitly synthesise the property, the compiler will automatically provide implementations. This it does by:
first inventing an instance variable name which is the same as the property name but with an underscore in front.
if the instance variable doesn't already exist, it declares one with private visibility.
create getter and setter to get/set the instance variable when the property is got/set.
You can't set the instance variable _property from within the subclass because the subclass does not have visibility of the instance variable. The NSLog works because it is using the property, not the instance variable.

You declared a property for the instance variable... this means, that a setter and getter was syntesized, which are methods... in Objective-C all methods are public (althrough you can "hide" them, or the compiler / IDE may prevent you from compiling)
But in reality and during runtime nothing prevents you from sending a message (calling a method) on that class

Related

I do not understand ways of declaring instance variable in the code

I do not quite understand the way of declaring instance variable and property. Can someone explain in detail the difference of the two codes below? In the second method, if I use _name for instance variable, is it the same function as the way declaring name in first code? Thanks!
First Code:
// OrderItem.h
#import <Foundation/Foundation.h>
#interface OrderItem : NSObject
{
#public NSString *name;
}
-(id) initWithItemName: (NSString *) itemName;
#end
// OrderItem.m
#import "OrderItem.h"
#implementation OrderItem
-(id) initWithItemName: (NSString *) itemName {
self = [super init];
if (self) {
name = itemName;
NSLog(#"Initializing OrderItem");
}
return self;
}
#end
Second Code:
// OrderItem.h
#import <Foundation/Foundation.h>
#interface OrderItem : NSObject
#property (strong,nonatomic) NSString *name;
-(id) initWithItemName: (NSString *) itemName;
#end
// OrderItem.m
#import "OrderItem.h"
#implementation OrderItem
-(id) initWithItemName: (NSString *) itemName {
self = [super init];
if (self) {
_name = itemName;
NSLog(#"Initializing OrderItem");
}
return self;
}
#end
In the first case you have declared an instance variable (usually called an ivar in Objective-C).
In the second case you have declared a property. A property is a set of two methods, a getter and a setter, usually accessed using dot notation, e.g. self.name. However, an ivar is automatically synthesized for the property with the name _name. That instance variable is what you are accessing in your init.
You can actually change the name of the ivar using #synthesize name = _myName or not have it at all (if you declare the getter and setter manually, no ivar will be synthesized).
Objective-C properties are a rather complicated topic so don't worry if you don't understand it immediately.
Properties are public which means that other classes can read and write them (even classes that aren't subclasses of the class that declares the property). In addition to that, properties provide a getter and a setter method (mutator methods). The getter of a property gets called every time you access the property
NSString *aName = self.name;
Whereas the setter is accessed every time you write or assign to a property.
self.name = #"Some name";
Instance variables (or ivars) are, by default, only visible for the class that declares it and its subclasses (also known as being encapsulated by their class). You can change this default behavior when you add the keyword #public to your ivar declaration though.

Sending property as a reference param to a function in iOS?

I want to do something like this:
#property (nonatomic, retain) NSObject *obj1;
#property (nonatomic, retain) NSObject *obj2;
- (id)init {
if ((self = [super init])) {
[SomeClass someFuncWithParam1:*(self.obj1) param2:*(self.obj2)];
}
}
#implementation SomeClass
+ (void)someFuncWithParam1:(NSObject **)param1 param2:(NSObject **)param2 {
//init obj1;
...
//init obj2;
...
}
#end
I haven't found any example how to pass objective-C properties into a function for initialization. I know that it is possible with usual variables but there are no examples about what to do with properties.
You cannot pass an argument by reference in (Objective-)C. What you probably mean is to
pass the address of a variable as an argument to the method, so that the method can
set the value of the variable via the pointer.
However, this does not work with properties.
self.obj1 is just a convenient notation for the method call [self obj1], which returns
the value of the property. And taking the address of a return value is not possible.
What you can do is
Pass the address of the corresponding instance variables:
[SomeClass someFuncWithParam1:&_obj1 param2:&_obj2];
The disadvantage is that the property accessor methods are bypassed. That may or may not be
relevant in your case.
Pass the address of temporary local variables:
NSObject *tmpObj1;
NSObject *tmpObj2;
[SomeClass someFuncWithParam1:&tmpObj1 param2:&tmpObj2];
self.obj1 = tmpObj1;
self.obj2 = tmpObj2;
Both solutions are not very nice. Alternatively, you could pass the entire object (self) to the helper method, which then initializes both properties.
Or you define a custom class with just the properties obj1 and obj2, and make the helper method return an instance of this custom class.

Initializing Objective-C property in child class

Apple recommends that you access the instance variables that back your properties directly, rather than using a getter/setter, when initializing a class:
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html
However, it seems that instance variables backing a property in a parent class are not accessible in the child class; why is this the case? I'm extending a class in a library (Cocos2d) where not all the instance variables are initialized in the parent class init function. For example:
---
#interface parentClass
#property (assign) int myProperty;
----
#interface childClass : parentClass
----
#implementation childClass
- (id) init {
// this doesn't work.
_myProperty = 0;
}
You can't access instance variables from your superclass in a subclass, so _variableName will also not work.
You init method will look something like this
- (instancetype)init {
if (self=[super init]) {
// subclass initialisation goes here
}
}
Once [super init] returned an object, the superclass part of your object is initialised, so it should be safe to access properties using their getters and setters:
- (instancetype)init {
if (self=[super init]) {
self.superClassProperty = aValue;
}
}
Have a look at "Don't message self in Objective-C init" on QualityCoding on when to use instance variables and when to call methods (e.g. property accessors). In short: Only call methods when your object is in a consistent state.
Why can't you access backing ivars?
A property declaration in a header declares a getter and setter for the property, a backing ivar is created when the property is synthesised, which happens in the implementation. (Automatic and manual synthesis doesn't make a difference). The ivar declaration is therefor only visible in the implementation. If you absolutely have to access ivars in subclasses, you have to make them public (or semi-public by putting them in a header for subclassing only).
You can do the following in your parentClass.h:
#interface parentClass {
#protected
int _myProperty;
}
#property (nonatomic) int myProperty;
Then, in your childClass.m
- (instancetype)init {
if (self=[super init]) {
_myProperty = aValue;
}
}
iVars are declared as protected by default, so your children can see them. There is no need to write #protected. And for your information you can also declare them as #private or #public.
But if you write the protected iVar in a private interface in your parentClass.m, this will not work and the children will not see it.

Objective-C : Need advice on setting instance variables in init method

I am using ARC.
This is my .h file
...
- (id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
...
This is my .m file
....
#synthesize coordinate, title;
- (id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t
{
self = [super init];
if (self) {
coordinate = c;
[self setTitle:t];
}
return self;
}
....
Is setting coordinate this way, the right way to do it? Given that I declare it as readonly, it seems like it is the only way to do it. What if I just use the default (i.e. readwrite), in this case, should I use the setter method [self setCoordinate] instead?
I could set the title by doing title = t as well. Compare to using the setter method, the result is the same, but what is the difference ?
Thanks! Wish I could accept all of your answers.
You're actually supposed to set ivars directly in an initializer method all the time. This is true whether or not you have a readonly or readwrite property. The documentation here even says so.
The reasoning behind this has to do with inheritance. If someone were to subclass your class and overwrite the setters for your properties such that they bypass the ivars you created (or do some other wacky thing), then suddenly your original implementation of your initializer method now no longer does what it is written to do. In particular, your initializer could end up creating an object with a weird state due to the subclass overriding your accessors. In the pre-ARC days, you could also end up with tricky (or just straight-up broken) memory situations when this sort of thing happens. The take-away message is: you should write initializers so that they will always create an object with a known valid state.
So (assuming you're using ARC) your initializer should actually be:
- (id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t
{
self = [super init];
if (self) {
coordinate = c;
title = [t copy];
}
return self;
}
Personally, I prefer to synthesize ivars with a starting underscore to clarify when I'm using the property and when I'm accessing the ivar directly (LLVM 4.0 now does this to automatically synthesized properties as well).
#synthesize coordinate = _coordinate;
#synthesize title = _title;
- (id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t
{
self = [super init];
if (self) {
_coordinate = c;
_title = [t copy];
}
return self;
}
1: As your code is now, yes, that is the right way to do it. If you weren't using ARC (assuming you are currently), you'd also want to retain the value to assert ownership. This will be done automatically under ARC. Keep in mind that that is not the only way of doing it; you could redeclare the property as readwrite in the class extension in the implementation file. This is a common practice which allows you to have the benefits of a readwrite property while having the property still be readonly to users of the class. Ex.
//MyClass.h
#interface MyClass : NSObject
#property (nonatomic, strong, readonly) NSNumber* number;
- (void) initWithNumber:(NSNumber*)number;
#end
//MyClass.m
#interface MyClass ()
#property (nonatomic, strong, readwrite) NSNumber* number;
#end
#implementation MyClass
//this changes the instance variable backing the property to _number.
#synthesize number = _number;
- (void) initWithNumber:(NSNumber*)number{
self = [super init];
if (self) {
self.number = number;
}
return self;
}
#end
At the end of the day, I'd say it's a good habit to use setters whenever you can to keep things KVO compliant and so that you always know when values change. For instance, if you have a custom UIView with a property that is reflected in its appearance, chances are you'd want to redisplay yourself when it changes. The easiest way to do this is to implement the setter yourself and call setNeedsDisplay after setting the value. You couldn't do that if you set the instance value backing the property directly; the user of the class would have to remember to call setneedsDisplay every time they set it, manually.
2: One goes through the setter method, giving you a way to know when a value is going to be set, while one sets a value to the instance variable backing the property. The setter method will always handle memory management in the way it was told to, while it's up to you to do things such as copying values for a copy setter if you assign directly to an instance variable, so that you maintain some consistent scheme. Going through setters sometimes, and not others can lead to some nasty bugs if you don't be careful. Never going through setters makes it hard to know when values change, making it near impossible to weed out invalid values. For instance, if you had an int property you wanted to limit to values in some range and someone passed in a value under the minimum limit, you'd probably want to set the property to the lowest possible value in the range. You can't do that without the value going through the setter first.
Yes, it is fine to set it like that. If you prefer to use a property all the time you can override the property to be read/write rather than read-only in a class extension. In Foo.m:
#interface Foo ()
#property (nonatomic) CLLocationCoordinate2D coordinate;
#end
#implementation Foo {
// ...
self.coordinate = c;
}
Setting the coordinate that way is correct, and is the only way to do it if you have declared the property readonly.
Setting the title using title = t is different than setting the title using [self setTitle:t]. If you directly assign to the instance variable, you will just retain the NSString instance that was passed as argument t. But if you using the accessor method, the accessor will ask the string to copy itself (because you declared the property copy). If the string you were given as argument t is actually an NSMutableString, then you will get an immutable copy of it. If the string you were given as argument t is already an immutable string, it will just return itself when asked for a copy.
self.coordinate = c;
is essentially compiled to be the same as calling
[self setCoordinate:c];
The difference between coordinate = c and [self setCoordinate:c]; is that the first is just setting a variable directly where as the second is calling a method.
The reason to be wary is that methods could potentially have side effects depending on how the implementation is written e.g. (stupid example)
- (void)setCoordinate:(CLLocationCoordinate2D)coordinate;
{
_coordinate = coordinate;
[self doSomethingCrazy];
}

#property and setters and getters

If I create a #property and synthesize it, and create a getter and setter as well like so:
#import <UIKit/UIKit.h>
{
NSString * property;
}
#property NSString * property;
--------------------------------
#implementation
#synthesize property = _property
-(void)setProperty(NSString *) property
{
_property = property;
}
-(NSString *)property
{
return _property = #"something";
}
Am I correct in assuming that this call
-(NSString *)returnValue
{
return self.property; // I know that this automatically calls the built in getter function that comes with synthesizing a property, but am I correct in assuming that I have overridden the getter with my getter? Or must I explicitly call my self-defined getter?
}
is the same as this call?
-(NSString *)returnValue
{
return property; // does this call the getter function or the instance variable?
}
is the same as this call?
-(NSString *)returnValue
{
return _property; // is this the same as the first example above?
}
There are a number of problems with your code, not least of which is that you've inadvertently defined two different instance variables: property and _property.
Objective-C property syntax is merely shorthand for plain old methods and instance variables. You should start by implementing your example without properties: just use regular instance variables and methods:
#interface MyClass {
NSString* _myProperty;
}
- (NSString*)myProperty;
- (void)setMyProperty:(NSString*)value;
- (NSString*)someOtherMethod;
#end
#implementation MyClass
- (NSString*)myProperty {
return [_myProperty stringByAppendingString:#" Tricky."];
}
- (void)setMyProperty:(NSString*)value {
_myProperty = value; // Assuming ARC is enabled.
}
- (NSString*)someOtherMethod {
return [self myProperty];
}
#end
To convert this code to use properties, you merely replace the myProperty method declarations with a property declaration.
#interface MyClass {
NSString* _myProperty;
}
#property (nonatomic, retain) NSString* myProperty
- (NSString*)someOtherMethod;
#end
...
The implementation remains the same, and works the same.
You have the option of synthesizing your property in your implementation, and this allows you to remove the _myProperty instance variable declaration, and the generic property setter:
#interface MyClass
#property (nonatomic, retain) NSString* myProperty;
- (NSString*)someOtherMethod;
#end
#implementation MyClass
#synthesize myProperty = _myProperty; // setter and ivar are created automatically
- (NSString*)myProperty {
return [_myProperty stringByAppendingString:#" Tricky."];
}
- (NSString*)someOtherMethod {
return [self myProperty];
}
Each of these examples are identical in how they operate, the property syntax merely shorthand that allows you to write less actual code.
return self.property – will call your overridden getter.
return _property; – accesses the property's instance variable directly, no call to the getter.
return property; – instance variable.
EDIT: I should emphasize that you will have two different NSString variables -- property and _property. I'm assuming you're testing the boundaries here and not providing actual production code.
above answer elaborate almost all the thing , i want to elaborate it little more.
// older way
#interface MyClass {
NSString* _myProperty; // instance variable
}
- (NSString*)myProperty; // getter method
- (void)setMyProperty:(NSString*)value;//setter method
#end
the instance variable can not be seen outside this class , for that we have to make getter and setter for it.
and latter on synthesis it in .m file
but now
we only used
#property(nonatomic) NSString *myProperty;
the #property is an Objective-C directive which declares the property
-> The "`nonatomic`" in the parenthesis specifies that the property is non-atomic in nature.
-> and then we define the type and name of our property.
-> prototyping of getter and setter method
now go to .m file
previously we have synthesis this property by using #synthesis , now it also not required it automatically done by IDE.
little addition : this `#synthesis` now generate the getter and setter(if not readonly) methods.