Objective c: i want the automatic memory management of properties, but no access from other classes - iphone

I've kind of been confused about properties. Some people say to always use setters and getters for ivars, even within the ivar's class. So if "name" is an ivar, when referring to it, one should always use "self.name". Always. Even if you're in the same class that "name" is declared in.
First, is that correct advice?
Second, what if I wish to reap the automatic memory management that comes with declaring "name" as a property and synthesizing it, but I don't want to give other classes access to change "name"? I guess it would be sort of a private property?
Thanks!

Yes, you should always try to use the property accessors when possible. Using ARC alleviates these concerns somewhat, but it's still good style. As for your second question, you can declare the property as readonly in the public header file and redefine it in a class extension:
In MyClass.h:
#interface MyClass : NSObject
#property (strong, readonly, nonatomic) id foo;
#end
In MyClass.m:
#interface MyClass()
#property (strong, readwrite, nonatomic) id foo;
#end
#implementation MyClass
#synthesize foo = _foo;
// The rest of your code goes here.
#end
This will allow you to call [self setFoo:foo] all day inside of MyClass’s implementation, but not other classes.

For ivars which are accessed externally, I generally use properties to access the ivar from within the class, for ivars which are only used internally (usually BOOL, NSUInteger, NSInteger, etc), I use the ivar directly. I do however access an consistently within the class (i.e. if I'm using a property to access it, I always use a property).
For the second part of your question. You can create a readonly property in the class's interface definition and within the same file as the implementation create a category with the read-write property. For example:
MyClass.h
#interface MyClass : NSObject
{
NSString * name;
}
#property (nonatomic, readonly) NSString * name;
#end
MyClass.m
#interface MyClass()
#property (nonatomic, retain) NSString * name;
#end
#implementation MyClass
#synthesize name;
-(void)dealloc
{
[name release];
[super dealloc];
return;
}
#end
Keep in mind, that although another class accessing the method -setName: may cause compile warnings or errors, another class may still call -(id)performSelector:withObject: with without an error.
For instance:
MyClass * test = [[MyClass alloc] init];
test.name = #"David";
is functionally the same as:
MyClass * test = [[MyClass alloc] init];
[test performSelector:#selector(setName:) withObject:#"David"];

Related

Instance variable with property & synthesize and one without them - ARC

You can declare a variable like this.
Case1:
#interface MyClass : NSObject
{
NSString *str;
}
#end
Also, if you want to set its property, you can do
Case2:
#interface MyClass : NSObject
{
NSString *str;
}
#property (nonatomic, strong) NSString *str;
#end
And in the .m,
#synthesize str;
My understanding with the difference between Case 1 and Case 2 is that synthesized and propertied variables in Case 2 can be accessed from another class when this another class instantiates this class.
What are other differences between Case 1 and 2? Say when these variables are just used only in its .m file. The fact that you are setting 'str' properties probably makes a difference, but how? If you don't set property, how are they going to be released with ARC?
The differences are fairly confusing in this case because of the way it is set up.
Also it is using what is now old practises.
The new suggested way of doing this (suggested by Apple) is to do this...
MyClass.h
#interface MyClass : NSObject
#property (nonatomic, strong) NSString *str;
#end
MyClass.m
#import "MyClass.h"
#implementation MyClass
#end
You no longer need the #synthesize as Xcode (since 4.5) will auto generate these for you.
Doing this sets up the property called str and an iVar called _str.
You now no longer need to worry about defining multiple ivars and properties etc... Just use the property and that's it done.
An example setter method for the property str would look like this...
- (void)setStr:(NSString*)str
{
_str = str;
}

nonatomic and readonly property in Objective-C

A few times already I wanted to make a property, which is nonatomic and readonly at the same time.
This has the advantage that I can override the getter and check if an instance has already been created or not. And if not I can simply create it.
At the same time I can protect it from being overwritten.
.h
#property (strong, readonly, nonatomic) Foo *bar;
.m
- (Foo *)bar {
if (!_bar) {
_bar = [[Foo alloc] init];
}
return _bar;
}
Whenever I do this, the compiler doesn't create an instance variable for me, so _bar doesn't exist.
Why? How can I create a readonly nonatomic property?
Your property declaration is correct. I believe the problem here is that, because your property was declared as readonly, the compiler didn't automatically synthesize an underlying instance variable. The solution in this case is to synthesize one yourself using...
#synthesize bar = _bar;
You could create a private setter:
#interface YourClass() // In the .m file
#property (strong, readwrite, nonatomic) Foo *bar;
#end
Then when assigning the variable:
self.bar = [[Foo alloc] init];
EDIT
Mark Adam's answer is also correct.
In the implementation add #synthesize bar = _bar.

clarifying on properties in objective C

Sorry for the simple question.
When I see a definition of a property inside the h file, but outside of the class #interface scope, what does it mean ?
#property (nonatomic, readonly) RMMapContents *mapContents;
Here is the code:
#class RootViewController;
#class RMMapContents;
#interface MapTestbedAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
//MAIN VIEW
//==============
RootViewController *rootViewController;
// NETWORK DATA
// =============
NSMutableArray *photoTitles; // Titles of images
NSMutableArray *photoSmallImageData; // Image data (thumbnail)
NSMutableArray *photoURLsLargeImage; // URL to larger image
NSMutableData *receivedData;
NSURLConnection *theConnection;
NSURLRequest *request;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet RootViewController *rootViewController;
#property (nonatomic, readonly) RMMapContents *mapContents;
#end
Inside a function I see this line:
- (void)foo:(xyz *)abc{
..
RMMapContents *mapContents = [self mapContents];
..
}
So, taking it from C++, the mapContents seem like it is not a global scope var (after all, that's why they call them properties, right?), but isn't defining the same name again inside the function weird a bit?
I hope someone can clarify a little here.
Thanks!
The scope of the #interface block extends upto the #end keyword and is not restricted to the braces {}.
So the #property declaration lies very much inside the scope of the #interface and like cli_hlt rightly answered, it acts like a substitute to setter and getter methods for the mapContents property.
so a property named mapContents, would have setters and getters which look like this :
- (void)setMapContents; //setter
- (RMMapContents *)mapContents; //getter
and would can be accessed from within the class using these methods:
[self setMapContents:newContents];
AND
RMMapContents *contents = [self mapContents];
Well, a property is not just a variable. A property is a variable plus its setter and getter methods. A property is usually said to be backed by a variable, which usually(but not always) has the same name as the property itself.
So there are basically three scenarios:
The developer has redefined the backing variable, look for something like:#synthesize mapContents=mapContents_, at the beginning of the implementation -> no problem here.
The compiler defined the variable to be something you don't now but not equal to mapContents - > no problem.
The property backing variable is indeed called "mapContents", so then the local definition hides the global definition (look for a compiler warning here). But by calling [self mapContents] you will not access the global variable but call the getter, which in turn will access the class variable (because then the local mapContents is out of scope)
Hope this helps.
global var mapContents is readonly,in foo function , create a new pointer,then you can change the value of inner var.
Look for a method in your class with a name mapContents that will return a initialization to your RMMapContents class.
Basically this line RMMapContents *mapContents = [self mapContents]; says that initializing an instance of RMMapContents called mapContens using the method mapContents.

Access modifier visibility in objective c

There are 3 modifiers: #private, #protected (default) and #public. So if i define a instance variable as private then that should not be accessible from anywhere.
For E.g. -
#interface A {
#private
NSString *a;
}
#property(nonatomic, retain) NSString *a;
Now inside implementation of some other interface/class B-
-(void)getSomeValue {
A *object = [[A alloc] init];
NSString *value = object.a;
.........
}
Here i am able to access instance variable, although i defined that as private.
It is a bit confusing, although when i look into details of this statement, then it is clear that it is calling the getter of a, but then also it seems confusing and it is against the concept of OOPS.
Anyone having any thought on this?
It's not the instance variable you're accessing but the property you declared. Don't declare the property if you do not want the instance variable to be visible outside the class.
#import <Foundation/Foundation.h>
#interface Visibility : NSObject {
#public
BOOL boolPublic;
#protected
BOOL boolProtected;
#private
BOOL boolPrivate;
}
#property (nonatomic, assign) BOOL boolPublic;
#property (nonatomic, assign) BOOL boolProtected;
#property (nonatomic, assign) BOOL boolPrivate;
#end
#implementation Visibility
#synthesize boolPublic;
#synthesize boolProtected;
#synthesize boolPrivate;
#end
int main(int argc, char *argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Visibility *visibility = [[Visibility alloc] init];
visibility.boolPublic = YES;
visibility.boolProtected = YES;
visibility.boolPrivate = YES;
// Place following NSLog()'s here
[pool release];
}
Let's try this out
Using the methods you define with #property/#synthesize
NSLog(#"Accessors %d %d %d", visibility.boolPublic, visibility.boolProtected, visibility.boolPrivate);
=> 2012-01-08 17:46:40.226 Untitled[2592:707] Accessors 1 1 1
Accessing #public ivar directly
NSLog(#"Public %d", visibility->boolPublic);
=> 2012-01-08 17:46:40.228 Untitled[2592:707] Public 1
Accessing #protected ivar directly
NSLog(#"Protected %d", visibility->boolProtected);
=> error: instance variable 'boolProtected' is protected
=> NSLog(#"Protected %d", visibility->boolProtected);
=> ^
Accessing #private ivar directly
NSLog(#"Private %d", visibility->boolPrivate);
=> error: instance variable 'boolPrivate' is private
=> NSLog(#"Private %d", visibility->boolPrivate);
=> ^
When you are accessing using dot notation this:
visibility.boolPublic
is equivalent to:
[visibility boolPublic]; // <- This is a method call
Because you set it as a #property and you claim it in header file. The variable you set as a #property will auto generate getter and setter for this variable and they are both public method to get or set it(variable is still private). If you really want to make the property as an private method, you should claim it in .m file and it will become private. You can only use this variable in the .m file.
For example, in your .h file
#interface ClassWithPrivateProperty : NSObject {
#private
NSString* member;
}
- (void) trySettingPrivateProperty;
#end
in your .m file
#import "ClassWithPrivateProperty.h"
#interface ClassWithPrivateProperty ()
#property (nonatomic,retain) NSString* member;
#end
#implementation ClassWithPrivateProperty
#synthesize member;
- (void) trySettingPrivateProperty {
self.member = #"A Value";
NSLog(#"myClass.member = %#", self.member);
}
#end
You can check more detail in Private properties for iPhone Objective-C
Edit:
Thanks for Abizern and Paul's comment, but in fact I got nothing compile error for this program.
I think RIP's question is "Why I set the variable in #private but I can still modify the variable like instance.variable"
The answer is although he set the variable as #private, but claim #property for variable in .h file also provide public methods getter and setter. So he can still get the instance variable use instance.variable. For OOP design pattern you should not expose your internals publicly. So if you want to use a variable privately only in its class and no one know it. And you still want to use getter and setter to access this variable in its class. you should claim #property in .m file like I did above. I claim the #property in .m file, it's a #interface extension(unnamed category). So you can make it "like" private. Because you cannot access this variable from anywhere outside this class. So it's just like a "private #property" that I mention about.
Two useful articles for you Public Properties with Private Setters and Private properties for iPhone Objective-C

What is the point of #property and #synthesize?

I haven't been able to figure it out, and there are no websites which explain it clearly enough... what exactly are the purposes of #property and #synthesize?
Thanks in advance!
Objective-C Runtime Programming Guide: Declared Properties
#property declares the getter and the setter methods for the public property you want to implement. For example this property declaration:
#property float value;
is equivalent to:
- (float)value;
- (void)setValue:(float)newValue;
#synthesize provides default implementation for these two accessors.
Update: The above explains what these two do. It does not explain what their purpose is. :-)
#property adds a member to the public interface that acts as a data variable to your class clients, but is read and written using methods. This gives you better control over the data that is exchanged between the client and your code, for example you can do extended validation on the values your code is given.
#synthesize allows you to not explicitly write the code that will be called by the client and actually treat the property as a data variable yourself.
The "#" symbol is interpreted by the compiler as a directive. This is one of the Objective-C 'additions' to the C language. When you declare #property and then #synthesize you are instructing the compiler to create the instructions and corresponding symbols for getters and setters for you. Remember that in the C language, the "=" operator means "assign". Most of the time in the OO context that the Objective-C extensions provide, we are working with pointers (aka references) to isa data structures (Classes in Objective-C).
Prior to Objective-C 2.0, all of the getter and setter methods had to be coded by the developer for every attribute which for most cases was copy/paste code. To be completely KVC/KVO compliant requires a lot of very tedious code... willAccessValueForKey, didUpdateValueForKey statements etc. that the new compiler adds for you automatically when you use the #property/#synthesize syntax. This is a huge productivity boost for developers. The dot syntax additions to the language are a little more contentious in the community as this hides the magic the compiler is doing on you behalf to interpret the object.property = anotherObject.property; statement as [object setProperty:[anotherObject property]];
From the Apple documentation referenced in other answers
Property Declaration Attributes
You can decorate a property with attributes by using the form #property(attribute [, attribute2, ...]). Like methods, properties are scoped to their enclosing interface declaration. For property declarations that use a comma delimited list of variable names, the property attributes apply to all of the named properties.
If you use the #synthesize directive to tell the compiler to create the accessor method(s), the code it generates matches the specification given by the keywords. If you implement the accessor method(s) yourself, you should ensure that it matches the specification (for example, if you specify copy you must make sure that you do copy the input value in the setter method).
I hope this will help you.
#property and #synthesize is Use to Access Object Or Variable into Another Class.
Here is a Small Example:
This is First Class
#import <UIKit/UIKit.h>
#import "ClassB.h"
#interface ViewController : UIViewController
#property(nonatomic, retain) NSString *FirstName;
#property(nonatomic, retain) NSString *LastName;
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize FirstName, LastName;
- (void)viewDidLoad
{
[super viewDidLoad];
self.FirstName = #"Ashvin";
self.LastName = #"Ajadiya";
ClassB *ClassBOb = [[ClassB alloc] init];
ClassBOb.ViewCntrlrOb = self;
[ClassBOb CallMe];
}
#end
And This is Another Class:
#import <UIKit/UIKit.h>
#class ViewController;
#interface ClassB : UIViewController
#property(nonatomic, retain) ViewController *ViewCntrlrOb;
-(void) CallMe;
#end
#import "ClassB.h"
#import "ViewController.h"
#interface ClassB ()
#end
#implementation ClassB
#synthesize ViewCntrlrOb;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
-(void) CallMe
{
NSLog(#"FirstName = %#",ViewCntrlrOb.FirstName);
NSLog(#"LastName = %#",ViewCntrlrOb.LastName);
}
So You can Access FirstName And LastName into ClassB.
And They Print:
2012-05-25 14:38:10.766 MyExample[8751:c07] FirstName = Ashvin
2012-05-25 14:38:10.768 MyExample[8751:c07] LastName = Ajadiya
Just a quick example of why you might not want to do just "variable = 0":
Say you have this property:
#property (nonatomic, retain) id <MyDelegate> theDelegate;
Whenever you replace that delegate with a new one, your synthesized setters and getters will handle the release/retain for you every time you set it like so:
self.theDelegate = newObject;
Really what happened was this:
[self setTheDelegate:newObject];
- (void)setTheDelegate:(id <MyDelegate>)anObject {
[theDelegate release];
theDelegate = [anObject retain];
}
(This is simplified of course)
You can do very powerful things in your own setters and getters, synthesize is for those that happen over and over like retained properties, etc. When compiling it looks at your #property and builds the methods accordingly.