feasible to not declare ivar but use in synthesize? - iphone

I'm looking at some sample code and I'm puzzled over the lack of declaration of a specific ivar. Hoping someone can help me understand this better:
typedef NSUInteger (^NumberOfItemsInSection)(ViewClass *viewClass, NSUInteger section);
// class declaration
#interface SampleScrollView : UIScrollView
#property (nonatomic, copy) NumberOfItemsInSection itemsSectionBlock;
#end
// class implementation
#implementation SampleScrollView
#synthesize itemsSectionBlock = _itemsSectionBlock;
- (void)setItemsSectionBlock:(NumberOfItemsInSection)itemsSectionBlock
{
// _itemsSectionBlock is not declared any where in the class
// How does the compiler not complain?
_itemsSectionBlock = [itemsSectionBlock copy];
[self reloadData];
}
#end
The instance variable, "_itemsSectionBlock", is not declared any where and it can just be used in the property's setter override. How does that work?

It's part of the modern runtime, and cuts down on the duplication of code - declaring iVars and then declaring properties for those iVars.
It's handled for you by the #synthesize
The modern runtime lets you do other things that you thought you couldn't do before. For example, you can now declare iVars in the .m file as part of a class extension, which reduces the amount of information you expose in your public interface.
Update
The modern LLVM 4 compiler even lets you do away with the #sytnthesize line. If you declare a property it will auto-synthesize for you and it will even create a backing store with a leading underscore.

Related

Can we have retain property with no getter and setters on Obj C elements?

Ok, so I was reading some articles regarding Good Programming Practices and I came across a statement which said that making all your Elements public for your classes isn't a good idea.. aka The concept of Encapsulation.
Now in Objective C, When I create a element for my class, I do the following, consider an NSMutableArray
#property (nonatomic, retain) NSMutableArray* myArray;
WHY I DO THIS?
So as to give the Retain property to myArray and therefore, giving it a simpler Memory Management cycle. Later on, I initialize the myArray in viewDidLoad as
self.myArray = [NSMutableArray arrayWithCapacity:0];
Later in Dealloc...
self.myArray = nil;
WHAT ELSE HAPPENS
By giving this property and synthesizing myArray in .m file, what I am unknowingly doing is making Public Getters and Setters for all the elements of my class.
Also, the auto-generated UI Elements from Xib files, do have the same declarations applied.
That isn't a nice idea to keep creating public Getters and setters for each and every element of your class, right?
So, there's absolutely no kind of encapsulation applied! Please correct me if I am wrong here and help me with any solutions!
Thanks!
Simply use the principle of Class Extensions that allows you to put part of your declarations in your .m file, thus making it invisible in your header and invisible from other classes.
(This is Apple's recommended way to declare private methods and properties, by the way)
YourClass.h
#interface MyClass : MySuperclass
// public properties
// public methods
#end
YourClass.m
#interface MyClass()
// This is a class extension
// put here private properties
// and private methods too
#end
#implementation MyClass
// And your implementation of course here
#end
You can even declare a property as readonly in your public interface (in the header file) and redeclare it as readwrite in your private interface (in the class extension in the .m file) for example.
See the Apple documentation for more details.
Note that:
There is NO NEED to declare the instance variable if you declare the property: the compiler will generate it automatically for you so you don't have to bother and to declare it in the .h. In the latest version of the compiler (Modern Objective-C) there is even no need for the #synthesize directive as it now generate it automatically if not present (see doc)
If you prefer to declare instance variables anyway, you can also do this in the class extension in your .m the same way you would do in your .h. That's a way to hide instance variables from the public header too. In general I really rarely use instance variables (as declaring only the properties is sufficient) and if I really need an ivar I declare it in the class extension to make it not visibile in the public header.
You can declare the property in your class.m file, so the getter and setter methods are accessible only in that class. An example:
MyClass.h
#interface MyClass : NSObject {
NSMutableArray *_myArray;
}
#end
MyClass.m
#interface MyClass ()
#property(nonatomic, retain) NSMutableArray *myArray;
#end
#implementation MyClass
[... MyClass implementation ..]
#synthesize myArray = _myArray;
#end
So you can use "self.myArray" only in "MyClass.h" file.

Using class extensions in xcode 4.4

Since xcode 4.4 you don't need to #synthesize properties anymore (see here), the compiler does it for you. So, why does the compiler complain
use of the undeclared identifier _aVar
in my viewDidLoad method of ViewControllerSubclass:
#interface ViewController : UIViewController
#property (assign, nonatomic) int aVar;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.aVar = 5;
NSLog(#"Super value: %d", _aVar);
}
#end
#interface ViewControllerSubclass : ViewController
#end
#interface ViewControllerSubclass ()
#property (assign, nonatomic) int aVar;
#end
#implementation ViewControllerSubclass
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"Subclass value: %d", _aVar);
}
#end
If I move everything to the one file instead of 4 separate files for the respective interfaces and implementations, the compiler instead complains that _aVar is private. But _aVar should have been automatically synthesized in my ViewControllerSubclass.
Still keeping everything in 1 file, if I move the initial property declaration to a class extension:
#interface ViewController ()
#property (assign, nonatomic) int aVar;
#end
The build still fails saying that _aVar is private.
If I go back to the 4 file setup for the respective interfaces and implementations xcode builds without even a warning.
If I then run the code:
[[[ViewControllerSubclass alloc] init] view];
the log statements in the above examples print out the following:
Super value: 0
Subclass value: 5
It makes sense that NSLog(#"Super value: %d", _aVar); produced a result of 0 because this variable is supposed to be private to the superclass. But then, why does NSLog(#"Subclass value: %d", _aVar); produce a result of 5??
This is all very odd.
You are confusing several different issues, and I'm somewhat confused when you talk about jumping between files and you don't specify where your errors are happening.
Anyway, there is the issue of instance variable visibility. If you declare your iVars within the interface scope, they are, by default, protected.
#interface Foo : NSObject {
int protectedInt;
#private
int privateInt;
#public
int publicInt;
}
#end
When you synthesize iVars, the instance variables themselves are private, unless you explicitly specify them.
Methods will always fire on the most derived implementation.
Now, when you call this...
[[[ViewControllerSubclass alloc] init] view];
You will allocate a subclass, initialize, and cause the view to be loaded. This code will execute...
#implementation ViewControllerSubclass
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"Subclass value: %d", _aVar);
}
#end
The first thing it does is call the base class implementation...
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.aVar = 5;
NSLog(#"Super value: %d", _aVar);
}
#end
Of course, it calls super, but that part's not important here. The next line assigns 5 to self.iVar. But, which iVar? It calls the property setter method on this object. What type is this instance? It's a ViewControllerSubclass. Since you have given both your base class and its subclass the same name (and declared the property as part of the class extension), they each have their own private-scope instance variable .
However, a method is called on the most derived implementation. Thus, self.iVar will set the instance variable of the subclass. The instance variable for the base class remains unchanged.
When you NSLog the value, you are accessing the private instance variable of the base class, which has not been changed.
Now, after the base class viewDidLoad finishes, we get the code running for the subclass. It logs the value of its private instance variable, which was changed as a result of the base class calling the property setter. So, it will now print it's value, which is 5.
When you make the superclass declaration public, the compiler won't attempt to re-synthesize the property; it assumes that's been taken care of in the superclass. Thus, _aVar is not in scope anywhere in the subclass. It's private anyway, so even when you put them all in the same file that's why you see those errors.
However when you make the superclass property declaration inside the class extension, the compiler will auto-synthesize the property for both the superclass and the subclass. This ends up with both classes having private instance variables _aVar (with two distinct addresses). However, when the superclass viewDidLoad method sets the property, the method invokes the subclass's accessors, which set the value of the subclass's private _aVar variable, and not the superclass's. So that explains why you see the superclass value not changing.
Hope this helps!
I just tested your setup and could replicate your error. I came to the following conclusion:
You need to declare your #property in a .h file. If you want a private variable, declare it in .m in the category #interface (the one with the parentheses).

Why should we declare variables for #property

I am newbie in Objective. As I read many tutorial, #property has a variable for a type, the same variable is declared in #inferface too. Is this needed?
Example
#interface MyInterface : NSObject
{
NSInteger myVaribale;
}
#property(retain) NSInteger myVariable;
Here myVariable is declared in both place.
since iOS 4, you can write
#interface MyInterface : NSObject {
}
#property(assign) NSInteger myVariable;
#implementation MyInterface
#synthesize myVariable;
#end
Meaning you can omit the NSInteger myVaribale in your interface declaration as long as you synthesize it in the .m (the synthesize will create setter, getter and instance variable)
A drawback is that you won't see the value of myVariable in Xcode's debugger.
As a note, the redeclaration of the ivar's type in the #property statement can also be useful if you want to declare the property as the immutable type of the ivar's, for instance:
#interface MyClass : NSObject
{
NSMutableArray *myArray;
}
#property (retain) NSArray *myArray;
In this instance, the ivar is actually stored as an NSMutableArray, so it can be altered during the object's lifecycle.
However this is an internal detail and if you don't want to "advertise" is as being mutable (changeable), you can make the type of the property the immutable type – in this case an NSArray.
Although this won't actually stop other code using the returned array as mutable, it is good convention and notifies other code that it shouldn't treat it in this way.
It's not an inconvenience but more a basic concept of objc: A class can have member variables. In OOP you normally define getter and setters for member variables which should be available to the outside. In objective-c you are encouraged to define getters/setters at any time (if they should be private, put their declarations into a private interface). To simplify this task, objective-c uses properties which are not more than a abbreviation. Additionally there are things like key-value-coding and -observing which are enabled by properties, but basically, they are just abbreviations for getters and setters.
Conclusion: Inside of #interface you declare members, outside methods including getters/setters (properties).

Object as a data member in Objective C

From what I have experienced it seems as if objects cannot be shared data members in objective c. I know you can init a pointer and alloc the object in each method but I cannot seem to figure out how one can say define a NSMutableString as a data member and allow all of the methods to use and modify its data as in c++. Is this true or am I missing something?
To define an instance variable (member), edit your .h file:
#interface MyClass : NSObject {
// ivars go here
NSObject *member;
}
// methods go here
#end
Then, in your .m file, from any instance method (one which begins with -), you can access this variable.
- (void)doThingWithIvar {
[member doThing];
}
If you want to access the variable from outside the object itself, you'll need accessors. You can do this easily with Obj-C properties:
#interface MyClass : NSObject {
// ivars go here
NSObject *member;
}
// methods go here
#property (nonatomic, retain) NSObject *member;
#end
And in the .m:
#implementation MyClass
#synthesize member;
// ...
#end
The #synthesize line creates getter/setter methods for the ivar. Then you can use property syntax:
MyClass *thing = ...;
NSLog(#"%#", thing.member); // getting
thing.member = obj; // setting
(Note that I specified (retain) for the #property; if your member isn't an Objective-C object you won't want that. And if your property's class has a mutable counterpart, you'll want (copy) instead.)
It sounds like you want to synthesize (create getter/setter methods) a property for a member variable. I just found this cheat sheet, go down to the section called, "Properties", should give a quick overview.
Other than that Apple's documentation should give you more info.

#property #synthesize

What do #synthesize and #property do in Xcode? Please provide an explanation in really simple terms?
You asked for simple terms:
#property declares a property in your
class header
#property (nonatomic, retain) NSString *myString;
#synthesize creates your setter and
getter for your property (accessor
methods)
Without synthesize you have to write
your own setter and getter
implemention, like getMyString or
setMyString (capitalize the first
character of your property)
Sam: Just an advice: http://www.cocoadevcentral.com/d/learn_objectivec/ is a pretty solid resource to learn about basics like properties.
Good Luck!
Properties and synthesized accessors are new features in Objective-C 2.0.
When you declare a #property you declare somewhat an instance var. Then you #synthesize accessor methods (i.e. getter and setter) for that property.
There are also #dynamic accessors if you're interested.
You should really do your homework on this. Apple has nifty pdf for that.
Think of all objective-c magic as just a "smarter macro", like a "smarter #define statement"
#property if you notice is always in the h file,
#synthesize is always in the m file.
So in the background
#property (whatever) NSString *myString;
becomes a declaration of 2 methods and a private variable;
void set_myString:(NSString *) str;
(NSString*) get_myString;
declarations in the header file
to make them do something their implementation is added into m file when you type in
#synthesize myString;
which becomes something like
void set_myString:(NSString *)str
{
myString = str;
}
(NSString *) get_myString
{
return (myString);
}
But it's smarter than this
depending on if you say "retain" "strong" or "weak"
it will either just return the pointer to the myString or it will copy the myString into a new object
So all of this is done automatically by a compiler just by reading your declarations.
Which is quite useful and saves a lot of time
By default all our variables are Private so we can't acess out of the class.
if we want to use our instance variable in out of the class.
When you declare a #property you declare somewhat an instance var. Then you #synthesize accessor methods (i.e. getter and setter) for that property.
There are also #dynamic accessors if you're interested.
it simply sets the property's setter variable name in it's own class.
For example lets say I have this: #property (nonatomic, copy) NSArray* viewControllers;
Well if i want to access the setter _viewController i wouldn't set a synthesize variable.
but if i want to access the viewController variable by the name viewController instead of _viewController, I would do #synthesize viewController;.
If I wanted to use it as a completely different name I could do this #synthesize viewControllers = viewControlololer; but that's only setter. As you will notice [self viewControllers] only works and not [self viewControlololer];
So I don't understant why everyone writes sets the "setter and getter" of a property. It doesn't change the getter variable at all... unless that means [self viewController] is aware of viewControlololer (obviously).
Actually properties are synthesized, either implicitly or explicitly. Properties are implicitly synthesized. So there's no need to use synthesized unless you wanna change the name of the variable to something different than _property_name.
There are other use cases, for example if you don't want an instance variable to back your property.
Properties are explicitly synthesized by using the #synthesized directive.
(Answer extracted from the Big Nerd Ranch guide)