Add a property without instance variable? - objective-c

I'm trying to add a property without creating an instance variable. Is it possible to do this? Or can you do something similar in a way that's not a property?
Example:
#interface RandomClass()
#property (nonatomic) int value;
#end
#implementation RandomClass
#synthesize value = _value;
// Here I override the default methods #synthesize
-(int)value
{
return 8; // Actually I'm returning something more complex, so a "define" won't work
}
-(void)setValue:(int)value
{
self.someOtherValue = value;
}
In the code above, I'm not using the instance variable _value! Is there a way to do this without creating the variable?

Remove the line
#synthesize value = _value;
Since you're implementing the getter/setter yourself, the #synthesize isn't helpful.
#synthesize serves two jobs. The first job is to connect the property to a backing ivar, synthesizing the ivar if it doesn't already exist. The second job is to synthesize the getter/setter. If you don't need the backing ivar, and if you're providing implementations for the getter/setter yourself, then you don't need the #synthesize at all.

Related

Objective-C: Overriding Getter & Setter with Instance Variable (using _) [duplicate]

This question already has answers here:
Error accessing generated ivars when I override setters and getters in Modern Objective-C
(3 answers)
Closed 5 years ago.
I'm learning the Swift programing language and during this I sometimes get in touch with the old Objective-C programming language and its code.
I'm an absolutely beginner and therefore I have some question for better understanding the Setter and Getter.
So, I know that I can create an instance variable through curly braces in the .h file but normally I use properties. These properties are backed by an instance variable and offer automatically a Getter and Setter Method.
Example:
Vehicle .h file:
#interface Vehicle : NSObject
#property int myProperty;
#end
Because I created this property I don't have to declare a Getter and Setter method in the vehicle.m file because they are automatically created by the compiler. So I can create a vehicle-object, set and get the value.
Example
main.m
Vehicle *myvehicle = [[vehicle alloc] init];
[myvehicle myProperty] // myvehicle.myProperty
[myvehicle setMyProperty : 10] // myvehicle.myProperty = 10;
Now I read that it is possible to override the automatically created Getter and Setter method of my created property "myProperty". When declaring my own version of the Getter and Setter I have to declare two methods in the vehicle.h and vehicle.m file. In the vehicle.m file I don't call the object by using the self keyword but by using it's automatically created instance variable (_myProperty). Is it right?
I tried it but alway get an error and I don't know why and what is the point.
Example
Vehicle .h file:
#interface Vehicle : NSObject
#property int myProperty;
-(int) myProperty; //my new Getter method
-(void) setMyProperty: (int)updatedMyProperty; //My new Setter method
#end
vehicle .m file:
#implementation Vehicle
-(int) myProperty {
if (! _myProperty) {
_myProperty = NO;
}
return _myProperty;
}
-(void) setMyProperty: (int)updatedMyProperty {
if (_myProperty == updatedMyProperty) return;
_myProperty = updatedMyProperty;
}
#end
I always get the error "Use of undeclared identifier" and I don't know why. If I understand right I don't have to declare the ivar or its name using #synthesize because the compiler automatically creates the ivar called _myProperty for me. I just have to use #synthesize when I want to change the ivar's name.
I'm not sure why I get stuck and what the point is. Could you explain it?
Thanks in advance!
If you implement all of the accessor methods, the compiler will no longer automatically synthesize the ivar for you. In this case, you have to explicitly do so yourself. E.g.
#synthesize myProperty = _myProperty;
This is only necessary when you have manually implemented all of the accessor methods. The reason is that the compiler is smart enough to know that if you're taking over the accessor methods, you may well not need the ivar, namely that you might be doing something radically different, e.g. computing values from some other property, setting/getting values from some different store, etc. You may want the compiler to synthesize the ivar (in which case you add the above #synthesize statement), but it's equally likely that you've implemented the accessor methods because no backing ivar is needed (in which case you'd omit the above #synthesize statement).
Anyway, staying with your simple example, you get something like:
#interface Vehicle : NSObject
#property (nonatomic) int myProperty; // if you don't write atomic accessor methods, you really should be explicit that this is nonatomic
// as an aside, even if you implement accessor methods, you don't have to declare them here
//
// -(int) myProperty; //my new Getter method
// -(void) setMyProperty: (int)updatedMyProperty; //My new Setter method
#end
And
#implementation Vehicle
// since you implemented all of the accessor properties, you have to manually synthesize the ivar
#synthesize myProperty = _myProperty;
- (int) myProperty {
// do whatever you want here; note, the following doesn't make sense
//
// if (! _myProperty) {
// _myProperty = NO;
// }
return _myProperty;
}
- (void)setMyProperty:(int)updatedMyProperty {
if (_myProperty == updatedMyProperty) return;
_myProperty = updatedMyProperty;
}
#end
Clearly, there's no point in writing these particular accessor methods in the above example, because you're not offering any new functionality, so you wouldn't. You'd just avail yourself of the auto-synthesized accessor methods.
But in those cases that you really need to write your own accessor methods, then you have to explicitly tell the compiler whether you need it to synthesize the ivar for you, too, or not.

#synthesize behind the scenes

When we create a property and defined a synthesize for it, the compiler automatically creates getters and setters methods, right?
Now, If I execute this command:
#property(nonatomic) int value;
#synthesize value;
value = 50;
What happens:
The compiler saves the value '50' in the property?
property (nonatomic) int value; // Here is the stored value 50!
or the compiler creates a variable behind the scenes with the same name of the property like this:
interface myClass: NSObject {
int value; // Here is the stored value 50!
}
What actually happens and what the alternatives listed above is correct?
It's probably semantics, but #synthesize is no longer required for properties. The compiler does it automatically.
But to answer your question, the compiler creates an instance variable to store the value for the property.
#property (nonatomic, assign) NSInteger value;
// an instance variable NSInteger _value; will be created in the interface.
You can use the instance variable in your own code if you need to access it without going through the property. This is common when overriding a setter, like so:
- (void)setValue:(NSInteger)value {
_value = value;
// custom code
}

Can the ivar variable created automatically by properties accessible by the child class? [duplicate]

Since recent runtimes in iOS, we are able to define properties that will generate accessors for instance variables. From what I understand, it is not mandatory to declare the instance variable used since it will be automatically done for us.
For example, if I write:
#interface MyFirstClass
#property (readonly, nonatomic) int size;
#end
and in the .m
#implementation MyFirstClass
#synthesize size;
#end
Then an instance variable named "size" will be added for me and a method called "-(int)size" will be implemented.
The problem is that when I create a second class MySecondClass which is a subclass of MyFirstClass, it seems that I can't access the instance variable size within this subclass:
#interface MySecondClass : MyFirstClass
#end
#implementation MySecondClass
- (id)init {
if (self = [super init]) {
size = 10; // this yields and error
}
return self;
}
#end
Are the automatically created instance variables private? Is there a possibility to set them as protected so I can access them in subclasses?
I know there is the possibility to declare the instance variable myself, but I'm just wondering...
With a superclass like this it works: (Is it because it's expressly declared as protected?)
#interface MyFirstClass {
int size; // defined expressly and used as #protected
}
#property (readonly, nonatomic) int size;
#end
Thank you for your help!!
Nicolas.
Any instance variable not declared in the main interface is automatically private, and this cannot be overridden. If you try to use a scope modifier when defining instance variables in the implementation, you will get an error that the specification is inconsistent.
The reason for this is that there is usually only one class per implementation file, which means the compiler doesn't know about the instance variable when compiling other classes. If you have multiple classes in the same file, the compiler could know about it, but you still aren't allowed to override the scope. Possible reasons in this case could be for consistency, or just so the compiler doesn't have to look in so many places for instance variables.
Use:
self.size = 10;
That will map to setSize method.

Why can't I set this to a string?

I've just starting out with obj-c and I created 2 files, a .h and a .m file. The .h file is..
#import <Foundation/Foundation.h>
#interface CardUnit : NSObject
{
#property (assign) NSString *name;
#property (assign) NSString *gold;
#end
and the .m file is
#import "CardUnit.h"
#implementation CardUnit
#synthesize gold = #"gold";
#synthesize name = _name;
#end
But it's giving me an error on
#synthesize gold = #"gold";
Saying "expected ; after synthesize"
Why can't I set that to a string?
#synthesize is not used for giving variables a value, but is rather a shorthand for defining basic getters and setters for the variable. The
#synthesize var = _var
syntax is used to say, "I want you to use the instance variable _var as the internal variable for the property var".
If you want to assign a default string to a property, put it in your init method:
-(id)initWithName:(NSString*)name
{
self = [super init];
if(self)
{
self.gold = #"gold";
self.name = name
}
return self;
}
Or you can set the default value in the getter (per #Mario's comment bellow):
-(NSString*)gold
{
_gold ? return _gold : return #"gold";
}
You got synthesize wrong. It is not for assigning values, it is for generating default setter/getter methods in case you do not provide them. You can use property = ivar to specify which ivar should be used for the property, but a constant value is NOT ivar. So you can't assign string value in this way. Please check The Obj-C Programming Language (Property Implementation Directives) for the details.
You can not assign a value in the #synthesize declaration.
The #synthesize is a declaration that sets getters and setters for variables. and it is not for assigning vales.
You should do later on in a method that will set the value to your "gold" var.
You are not suppose to set value to the variable in synthesize. They are just for synthesize accessor methods.
The #synthesize generates a getter and setter for the property, but the compiler takes care of generating those.
I think it would be a good idea to read a good tutorial on iOS development, maybe start with the Start developing iOS apps today on the Apple Developer connection website.

Creating Properties in Obj-C, how do I write the default Getter?

I'm just starting to learn Objective-C, one thing I'm trying to learn is good Property use. I'm currently trying to create some properties with custom setters. This is how far I've gotten:
#interface MyClass : NSObject
#property (nonatomic, assign) int myNumber;
#end
#implementation MyClass
#dynamic myNumber;
- (int)myNumber {
return ???;
}
- (void)setMyNumber:newNumber {
myNumber = newNumber;
// custom stuff here
}
I really just want to implement a custom setter, I'm fine with the getter being default. However, how do I access the variable directly? If I put "return self.myNumber", won't that just call the getter method and infinite loop?
Property access functions are only called when using the x.p notation. You can access the instance variable backing the property with just p (in Objective C, all members have the class instance variables in scope). You can, if you really want, also access via the pointer deference notation ->. So, any of these two:
return p;
return self->p;
However, you needn't use #dynamic here. #synthesize is smart, and will only create defaults if you've not provided them. So feel free to just
#synthesize p;
Which will create the getter, but not the setter in this case.
- (int)myNumber {
return myNumber;
}