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.
Related
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.
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
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.
I need to move the same method from 4 different classes to the superclass.
Such methods are exactly the same except for the type of a variable declared in them:
For example, in the method in the first class I have
FirstClass var = [[FirstClass alloc] init]
in the second class
SecondClass var = [[SecondClass alloc] init]
and so on.
What's the best way to implement this variation in the superclass ?
Should I use NSClassFromString in the superclass and get each string from each method in the subclasses?
thanks
I'm not 100% sure I get what you mean. So I could be answering the wrong question
If inside your class you need to use an object (I've called it worker below) to do your work, but the class of this object is not known til later, you can use dependency injection (DI).
MyClass.h
#interface MyClass : NSObject
#property (nonatomic, retain) id<WorkerInterface> worker;
#end
MyClass.m
#implementation MyClass
#synthesize worker = _worker;
- (void)myMethod;
{
[self.worker doSomething];
}
// You could also provide a default class to use if one is not passed in
//
// - (id<WorkerInterface)worker;
// {
// if (!_worker) {
// _worker = [[DefaultWorker alloc] init];
// }
// return _worker;
// }
#end
Now whenever I instantiate this class I can simply pass in the appropriate object to be used e.g:
MyWorkerClass *worker = [[MyWorkerClass alloc] init]; // <- Conforms to #protocol(WorkerInterface)
MyClass *instance = [[MyClass alloc] init];
instance.worker = worker;
[instance doSomething];
If all the different types of iVar's you intend on initializing in the subclasses are descended from a common class, then I'd store that class in the super, or else just store it as an id. Then, setup a property accessor in each of your subclasses the casts the iVar as you need it.
#interface superClass : NSObject{
id _superIvar;
}
#end
#implementation superClass : NSObject
....super's code....
#end
Now in the implementation of the subclass declare a property in a category, shown below (or in the interface, if you want it public)
#interface subClass (private)
#property (strong) ClassType *superIvar;
#end;
#implementation
- (void) setSuperIvar:(ClassType *)superIvar{
_superIvar = superIvar;
}
- (ClassType *) superIvar{
return (ClassType *) _superIvar;
}
- (void) someMethodThatUsesSuperIvar{
[self.superIvar doSomething];
}
#end
Alternatively, if you don't want to open your _superIvar to direct access, you can set a property on the superclass and access through the property on the subclass. But in this way you can easily access super's ivars cast to the appropriate type.
I`m new to the Objective-C world, so I have a couple of questions about class member declarations. Please notice the comments in the code below:
In header file I have code such
#interface MyClass : NSObject {
//what we points here ? Object or something else ?
NSString *myString;
}
// In interface we declare NSTring *myString in #property declaration is (NSString *) myString.
// What is the difference here ? Why we don`t use the same declaration as above ?
#property(nonatomic, retain) (NSString *) myString;
#end
The thing you're missing is that instance variables (defined between curly braces) are not accessed from the outside (i.e. other objects). To do that - you have to define a property for the instance var (by using #property keyword) to know how outside objects can access a value of given instance var. Also in implementation file (.m) you have to #synthesize instance variable accessor methods for it's appropriate property. Please note that #property declaration not only defines what it holds (NSString *myString), but also how it's being accessed and set. You can define property as read only (#property (readonly)...) or accessible from few threads at a time (#property (nonatomic)).
Also - if your instance var is named differently from the property it represents to other objects - you must show that in implementation file (#synthesize propertyName=instanveVariableName)
update
MyClass *myInstance = [[MyClass alloc] init];
[myInstance myString]; // returns myString property
Try running above 2 lines of code without #property and you'll see the difference.
Actually you are defining a Property of yar class.#interface MyClass : NSObject {
//public object
#public
NSString *myString;
//private object
NSString *myString2;
}
class structure for obj-c
.h file
#interface MyClass : NSObject {
//Your member variable;
// you member objects;
}
//property declarations
//function declarations
#end
so it should look like
#interface MyClass : NSObject {
NSString *str;
}
#property(nanatomic,retain) NSString *str;
-(void)method;
#end