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;
}
Related
I can build the following code for debug, but not for release for an OS X target in xcode:
myclass.h:
#interface myclass : NSObject
#property (nonatomic,copy) NSString *name;
#end
myclass.m:
#implementation myclass {
NSString *_name;
}
#synthesize name = _name;
#end
Any ideas why? On iOS it builds for both release and debug.
I understand that moving the instance variable declaration to the .h will work, but my intention is to hide the implementation details (of course the real class is more complex than this example). I've tried this on the latest xcode version (4.6, build 4H127) on Mountain Lion when building 64-bit apps.
One approach is to use a class extension. In your .m file, write
#interface myclass ()
{
NSString *_name;
}
#end
above your #implementation for myclass.
On the other hand, you don't actually need to declare the instance variable which is backing your property. If you just write
#property (nonatomic, copy) NSString *name;
in your class declaration (the code beginning with #interface myclass : NSObject and ending with #end), a backing NSString * ivar _name will be generated for you automatically, and you'll be able to access this ivar inside the instance methods of myclass. You don't even need to write #synthesize name = _name;. Furthermore, if you want to use a variable name other than _name to back your property name, you needn't declare the ivar; instead you can just use #synthesize
#synthesize name = m_Name;
inside your class' #implementation block.
Instance variables in the implementation block requires the modern Objective-C runtime. See Objective-C Feature Availability Index. It could be that the release is targeting a version of OS X which does not support the modern runtime.
you have not specified object type of the property "name" here:
#property (nonatomic,copy) name;
use this
#property (nonatomic,copy) NSString *name;
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.
I have a class called MyClass which has a small nested inner class called MyInnerClass. The implementation file looks like the following (and also contains an ivar of the nested inner class) :
#class MyInnerClass;
#interface MyClass
{
MyInnerClass *myInnerClassIvar;
}
#property(nonatomic, retain) MyInnerClass *myInnerClassIvar;
#end
Then in the implementation file, I implement both MyClass and MyInnerClass. Looks like the following:
#interface MyInnerClass
{
iVar *x;
}
#property(nonatomic, retain) iVar *x;
#end
#implementation MyInnerClass
#synthesize x;
...
#end
#implementation MyClass
#synthesize myInnerClassIvar;
...
#end
I am now creating a subclass for MyClass, and in it I'm trying to make a call like this:
self.myInnerClassIvar.x
And I'm getting the following message:
Property x cannot be found in in forward class object MyInnerClass *
Am I forgetting something? Haven't implemented an inner class before, see no reason why this shouldn't work.
UPDATED: I moved the interface of MyInnerClass to the .h of MyClass and everything works. Is this a good solution?
I believe that Objective-C does not have inner classes in the sense that you are trying to implement. See SO. But regarding your question...
in MyClass.h there is no mention of the iVars of MyInnerClass - it is a forward definition, i.e. #class MyInnerClass therefore MySubClass has no reference point for x.
If you define two classes MyClass & MyInnerClass (probably a bad thing to name it that considering...) - have them in two separate .h files and two separate .m files (ie. as normal). Make an #property in MyClass of type MyInnerClass. Then in MySubClass you need to import both MyClass & MyInnerClass.
I moved the interface of MyInnerClass into the .h file of MyClass like following:
MyClass.h
#class MyInnerClass;
#interface MyClass
{
MyInnerClass *myInnerClassIvar;
}
#property(nonatomic, retain) MyInnerClass *myInnerClassIvar;
#end
#interface MyInnerClass
{
iVar *x;
}
#property(nonatomic, retain) iVar *x;
#end
I'll wait before I check this off as the answer because based on the previous answer, I know there is some skepticism. The only reason I tried this is because I saw it in the Apple example SimpleTextInput, except in that one the entire inner class is in the .m file. Anyway, would be interested to hear what people have to say about this, if it might incur unwanted side effects later or if its ok.
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"];
I'd like to use properties for my instance variables, but in many cases, I only want the class itself to have access to the setter. I was hoping I could do something like this:
Foo.h:
#interface Foo {
NSString *bar;
}
#property (readonly) NSString *bar;
#end
Foo.m:
#import "Foo.h"
#interface Foo ()
#property (copy) NSString *bar;
#end
#implementation Foo
#synthesize bar;
#end
But this generates a warning:
Foo.m:4: warning: property ‘bar’ attribute in ‘Foo’ class continuation does not match class ‘Foo’ property
I can see what it's complaining about, but it still seems like a useful idiom. Is there some other way to accomplish this without writing my own setters?
Your approach is correct, but the redeclaration of #property bar in the class extension must match the original declaration except for readwrite vs. readonly. So this will work:
Foo.h
#interface Foo {
NSString *bar;
}
#property (copy,readonly) NSString *bar;
#end
Foo.m:
#import "Foo.h"
#interface Foo ()
#property (copy,readwrite) NSString *bar;
#end
#implementation Foo
#synthesize bar;
#end
(recall that the default is assign for properties, not copy).
When Barry says "the default is retain for properties" he means that retain should be specified like this:
#property (retain) NSDate *endDate;
If they are left like this:
#property NSDate *endDate;
assign is assumed by the compiler.