I am reading: http://cocoacast.com/?q=node/103
I came across this method in the above page:
-(void)foo
{
self->iVar = 5; //legal because we are referencing a member variable
iVar = r; // illegal because we are referencing a readonly property
}
I then created a project in Xcode.
Test0.h
#import <Foundation/Foundation.h>
#interface Test0 : NSObject
{
#private int iVar;
}
#property (readonly, assign) int iVar;
- (void) foo;
#end
Test0.m
#import "Test0.h"
#implementation Test0
#synthesize iVar;
- (void) foo
{
iVar = 5;
}
#end
main.m
#import <Foundation/Foundation.h>
#import "Test0.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
Test0 *t1 = [[Test0 alloc] init];
[t1 foo];
NSLog(#"%d", t1.iVar);
}
return 0;
}
The result in Console is 5.
My questions:
The web page mentioned above uses
self->iVar = 5
I have used iVar = 5
What difference does it make?
The web page mentioned above says
iVar = r; // illegal because we are referencing a readonly property
Is iVar = 5 (which I have used) not same as iVar = r ?
How is it not illegal?
how does readonly property work?
The compiler simply does not generate or verify the existence of the setter. It will generate the getter, and that property may be backed by an ivar. As well, the setter is not declared in the class interface.
self->iVar = r;
vs
iVar = r;
What difference does it make?
None. They are identical. They are both direct assignment of the ivar. It's similar to other languages, when adding a superfluous scope resolution (e.g. this->).
The difference is when you attempt to use the setter method (e.g. self.prop = val or [self setProp:val];). In this case, the compiler will emit a warning and the runtime would throw an exception (unless you or a subclass defined the setter yourself).
The web page mentioned above says iVar = r; // illegal because we are referencing a readonly property.
That's wrong. Direct access to the ivar of a readonly property is fine if the ivar exists. You don't see an error in this case because you're accessing the ivar directly, rather than using the setter.
Other issues:
The article incorrectly states atomics are 'mutexed'.
The article incorrectly states atomic properties guarantee thread safety.
Related
Ever since starting to work on iOS apps and objective C I've been really puzzled by the different locations where one could be declaring and defining variables. On one hand we have the traditional C approach, on the other we have the new ObjectiveC directives that add OO on top of that. Could you folks helps me understand the best practice and situations where I'd want to use these locations for my variables and perhaps correct my present understanding?
Here's a sample class (.h and .m):
#import <Foundation/Foundation.h>
// 1) What do I declare here?
#interface SampleClass : NSObject
{
// 2) ivar declarations
// Pretty much never used?
}
// 3) class-specific method / property declarations
#end
and
#import "SampleClass.h"
// 4) what goes here?
#interface SampleClass()
// 5) private interface, can define private methods and properties here
#end
#implementation SampleClass
{
// 6) define ivars
}
// 7) define methods and synthesize properties from both public and private
// interfaces
#end
My understanding of 1 and 4 is that those are C-style file-based declarations and definitions that have no understanding whatsoever of the concept of class, and thus have to be used exactly how they would be used in C. I've seen them used for implementing static variable-based singletons before. Are there other convenient uses I'm missing?
My take from working with iOS is that ivars have been alost completely phased out outside of the #synthesize directive and thus can be mostly ignored. Is that the case?
Regarding 5: why would I ever want to declare methods in private interfaces? My private class methods seem to compile just fine without a declaration in the interface. Is it mostly for readability?
Thanks a bunch, folks!
I can understand your confusion. Especially since recent updates to Xcode and the new LLVM compiler changed the way ivars and properties can be declared.
Before "modern" Objective-C (in "old" Obj-C 2.0) you didn't have a lot of choices. Instance variables used to be declared in the header between the curly brackets { }:
// MyClass.h
#interface MyClass : NSObject {
int myVar;
}
#end
You were able to access these variables only in your implementation, but not from other classes. To do that, you had to declare accessor methods, that look something like this:
// MyClass.h
#interface MyClass : NSObject {
int myVar;
}
- (int)myVar;
- (void)setMyVar:(int)newVar;
#end
// MyClass.m
#implementation MyClass
- (int)myVar {
return myVar;
}
- (void)setMyVar:(int)newVar {
if (newVar != myVar) {
myVar = newVar;
}
}
#end
This way you were able to get and set this instance variable from other classes too, using the usual square bracket syntax to send messages (call methods):
// OtherClass.m
int v = [myClass myVar]; // assuming myClass is an object of type MyClass.
[myClass setMyVar:v+1];
Because manually declaring and implementing every accessor method was quite annoying, #property and #synthesize were introduced to automatically generate the accessor methods:
// MyClass.h
#interface MyClass : NSObject {
int myVar;
}
#property (nonatomic) int myVar;
#end
// MyClass.m
#implementation MyClass
#synthesize myVar;
#end
The result is much clearer and shorter code. The accessor methods will be implemented for you and you can still use the bracket syntax as before. But in addition, you can also use the dot syntax to access properties:
// OtherClass.m
int v = myClass.myVar; // assuming myClass is an object of type MyClass.
myClass.myVar = v+1;
Since Xcode 4.4 you don't have to declare an instance variable yourself anymore and you can skip #synthesize too. If you don't declare an ivar, the compiler will add it for you and it will also generate the accessor methods without you having to use #synthesize.
The default name for the automatically generated ivar is the name or your property starting with an underscore. You can change the generated ivar's name by using #synthesize myVar = iVarName;
// MyClass.h
#interface MyClass : NSObject
#property (nonatomic) int myVar;
#end
// MyClass.m
#implementation MyClass
#end
This will work exactly as the code above. For compatibility reasons you can still declare ivars in the header. But because the only reason why you would want to do that (and not declare a property) is to create a private variable, you can now do that in the implementation file as well and this is the preferred way.
An #interface block in the implementation file is actually an Extension and can be used to forward declare methods (not needed anymore) and to (re)declare properties. You could for instance declare a readonly property in your header.
#property (nonatomic, readonly) myReadOnlyVar;
and redeclare it in your implementation file as readwrite to be able to set it using the property syntax and not only via direct access to the ivar.
As for declaring variables completely outside of any #interface or #implementation block, yes those are plain C variables and work exactly the same.
First, read #DrummerB's answer. It a good overview of the whys and what you should generally do. With that in mind, to your specific questions:
#import <Foundation/Foundation.h>
// 1) What do I declare here?
No actual variable definitions go here (it's technically legal to do so if you know exactly what you're doing, but never do this). You may define several other kinds of things:
typdefs
enums
externs
Externs look like variable declarations, but they're just a promise to actually declare it somewhere else. In ObjC, they should only be used to declare constants, and generally only string constants. For instance:
extern NSString * const MYSomethingHappenedNotification;
You would then in your .m file declare the actual constant:
NSString * const MYSomethingHappenedNotification = #"MYSomethingHappenedNotification";
#interface SampleClass : NSObject
{
// 2) ivar declarations
// Pretty much never used?
}
As noted by DrummerB, this is legacy. Don't put anything here.
// 3) class-specific method / property declarations
#end
Yep.
#import "SampleClass.h"
// 4) what goes here?
External constants, as described above. Also file static variables can go here. These are the equivalent of class variables in other languages.
#interface SampleClass()
// 5) private interface, can define private methods and properties here
#end
Yep
#implementation SampleClass
{
// 6) define ivars
}
But very rarely. Almost always you should allow clang (Xcode) to create the variables for you. The exceptions are usually around non-ObjC ivars (like Core Foundation objects, and especially C++ objects if this is an ObjC++ class), or ivars that have weird storage semantics (like ivars that don't match with a property for some reason).
// 7) define methods and synthesize properties from both public and private
// interfaces
Generally you shouldn't #synthesize anymore. Clang (Xcode) will do it for you, and you should let it.
Over the last few years, things have gotten dramatically simpler. The side-effect is that there are now three different eras (Fragile ABI, Non-fragile ABI, Non-fragile ABI + auto-syntheisze). So when you see the older code, it can be a little confusing. Thus confusion arising from simplicity :D
I'm also pretty new, so hopefully I don't screw anything up.
1 & 4: C-style global variables: they have file wide scope. The difference between the two is that, since they're file wide, the first will be available to anyone importing the header while the second is not.
2: instance variables. Most instance variables are synthesized and retrieved/set through accessors using properties because it makes memory management nice and simple, as well as gives you easy-to-understand dot notation.
6: Implementation ivars are somewhat new. It's a good place to put private ivars, since you want to only expose what's needed in the public header, but subclasses don't inherit them AFAIK.
3 & 7: Public method and property declarations, then implementations.
5: Private interface. I always use private interfaces whenever I can to keep things clean and create a kind of black box effect. If they don't need to know about it, put it there. I also do it for readability, don't know if there are any other reasons.
This is an example of all kinds of variables declared in Objective-C. The variable name indicate its access.
File: Animal.h
#interface Animal : NSObject
{
NSObject *iProtected;
#package
NSObject *iPackage;
#private
NSObject *iPrivate;
#protected
NSObject *iProtected2; // default access. Only visible to subclasses.
#public
NSObject *iPublic;
}
#property (nonatomic,strong) NSObject *iPublic2;
#end
File: Animal.m
#import "Animal.h"
// Same behaviour for categories (x) than for class extensions ().
#interface Animal(){
#public
NSString *iNotVisible;
}
#property (nonatomic,strong) NSObject *iNotVisible2;
#end
#implementation Animal {
#public
NSString *iNotVisible3;
}
-(id) init {
self = [super init];
if (self){
iProtected = #"iProtected";
iPackage = #"iPackage";
iPrivate = #"iPrivate";
iProtected2 = #"iProtected2";
iPublic = #"iPublic";
_iPublic2 = #"iPublic2";
iNotVisible = #"iNotVisible";
_iNotVisible2 = #"iNotVisible2";
iNotVisible3 = #"iNotVisible3";
}
return self;
}
#end
Note that the iNotVisible variables are not visible from any other class. This is a visibility issue, so declaring them with #property or #public doesn't change it.
Inside a constructor it's good practice to access variables declared with #property using underscore instead self to avoid side effects.
Let's try to access the variables.
File: Cow.h
#import "Animal.h"
#interface Cow : Animal
#end
File: Cow.m
#import "Cow.h"
#include <objc/runtime.h>
#implementation Cow
-(id)init {
self=[super init];
if (self){
iProtected = #"iProtected";
iPackage = #"iPackage";
//iPrivate = #"iPrivate"; // compiler error: variable is private
iProtected2 = #"iProtected2";
iPublic = #"iPublic";
self.iPublic2 = #"iPublic2"; // using self because the backing ivar is private
//iNotVisible = #"iNotVisible"; // compiler error: undeclared identifier
//_iNotVisible2 = #"iNotVisible2"; // compiler error: undeclared identifier
//iNotVisible3 = #"iNotVisible3"; // compiler error: undeclared identifier
}
return self;
}
#end
We can still access the not visible variables using the runtime.
File: Cow.m (part 2)
#implementation Cow(blindAcess)
- (void) setIvar:(NSString*)name value:(id)value {
Ivar ivar = class_getInstanceVariable([self class], [name UTF8String]);
object_setIvar(self, ivar, value);
}
- (id) getIvar:(NSString*)name {
Ivar ivar = class_getInstanceVariable([self class], [name UTF8String]);
id thing = object_getIvar(self, ivar);
return thing;
}
-(void) blindAccess {
[self setIvar:#"iNotVisible" value:#"iMadeVisible"];
[self setIvar:#"_iNotVisible2" value:#"iMadeVisible2"];
[self setIvar:#"iNotVisible3" value:#"iMadeVisible3"];
NSLog(#"\n%# \n%# \n%#",
[self getIvar:#"iNotVisible"],
[self getIvar:#"_iNotVisible2"],
[self getIvar:#"iNotVisible3"]);
}
#end
Let's try to access the not visible variables.
File: main.m
#import "Cow.h"
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
#autoreleasepool {
Cow *cow = [Cow new];
[cow performSelector:#selector(blindAccess)];
}
}
This prints
iMadeVisible
iMadeVisible2
iMadeVisible3
Note that I was able to access the backing ivar _iNotVisible2 which is private to the subclass. In Objective-C all variables can be read or set, even those that are marked #private, no exceptions.
I didn't include associated objects or C variables as they are different birds. As for C variables, any variable defined outside #interface X{} or #implementation X{} is a C variable with file scope and static storage.
I didn't discuss memory management attributes, or readonly/readwrite, getter/setter attributes.
I am trying to figure out the original property name from the setter selector. For example I know that the setter is called setFoo: and would like to get foo. It should be a quite easy string processing task (remove set and change the first letter to lowercase) but I was wondering if there are any out of the box solution somewhere in the Objective-C runtime.
I would like to use it like this:
#interface MyClass : NSObject
#property (nonatomic, assign) BOOL foo;
#end
#implementation MyClass
#dynamic foo;
+(BOOL)resolveInstanceMethod:(SEL)sel
{
const char* selectorName = sel_getName(sel);
objc_property_t getterProperty = class_getProperty([self class], selectorName);
objc_property_t setterProperty = class_getProperty([self class], getPropertyNameFromSetterName(selectorName));
if (getterProperty) {
// now I know that the property was declared and I should provide
// the getter implementation
} else if (setterProperty) {
// I should provide the setter implementation
}
}
#end
I can't get rid of compiler warning when I define property inside protocol. Strange thing is that I have two properties defined, and I only get warnings for the second one (which is object type, while the first property is value type).
Here is screenshot:
Can anyone tell me how to get rid of this warning, and why it is generated? The code is working normally, it is just this warning that annoys me :)
In your program, the property is called view. There must be a getter called view and a setter called setView. If you do not use #synthesize you must supply these two methods, and this is the reason of the compiler warning.
The code is working normally because you do not reference the property using dot notation or call the getter and setter methods.
Your issue is that the compiler cannot find an implementation for the properties you defined in the protocol.
For this reason, it is not recommended to add properties to a protocol, instead, you would define just a simple method to access the property, and one to set it. That would give you the proper error messages, and while you couldn't use dot-notation, it keeps the warnings in the right place.
Alternatively, you could do something like this (not recommended, but for educational reasons):
#import <objc/runtime.h>
#protocol myProto
#property (assign) int myProperty;
#end
#implementation NSObject(myProto)
-(int) myProperty
{
return [objc_getAssociatedObject(self, "myProperty") intValue];
}
-(void) setMyProperty:(int) myProperty
{
objc_setAssociatedObject(self, "myProperty", [NSNumber numberWithInt:myProperty], OBJC_ASSOCIATION_RETAIN);
}
#end
#interface MyObj : NSObject<myProto>
#end
#implementation MyObj
#dynamic myProperty;
#end
int main(int argc, char *argv[])
{
#autoreleasepool
{
MyObj *myObj = [MyObj new];
myObj.myProperty = 10;
NSLog(#"%i", myObj.myProperty);
}
}
Please help with understanding how #import works without using inheritance.
So I have created a Class named Person and another Class named Body (both classes are inherited from NSObject).
The Body class has 3 ivars (set with properties)
int hands;
int feet;
int legs;
I then imported and created an instance of the Body class ( *body) into the Person class. My understanding is that I have now made a 'type' from the Body class. This ivar was then set with properties.
In main, I then created an instance from the Person class named person.
Main recognizes person.body.feet but I cannot get and set its value directly. The only way it can be done is passing its value into a new int variable and then print out the new variable.
Obviously I’m a struggling newbe but I really want to understand this problem -
#import <Foundation/Foundation.h>
#import "Person.h"
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Person *person = [[Person alloc]init];
// this works and NSLog prints out the value is 2
int feet = person.body.feet = 2;
NSLog(#"person.body = %i",feet);
// this does not work - NSLog prints out the value is 0;
[person.body setFeet:2];
NSLog(#"person.body = %i", person.body.feet );
[person release];
[pool drain];
return 0;
}
#import <Foundation/Foundation.h>
#import "Body.h"
#interface Person : NSObject {
Body *body;
}
#property (assign) Body *body;
#end
#import "Person.h"
#implementation Person
#synthesize body;
#end
#import <Foundation/Foundation.h>
#interface Body : NSObject {
int hands;
int feet;
int legs;
}
#property int hands;
#property int feet;
#property int legs;
#end
#import "Body.h"
#implementation Body
#synthesize hands;
#synthesize feet;
#synthesize legs;
#end
My guess is that you haven't assigned a Body object to person.body anywhere.
All objects in Objective-C are allocated on the heap. All those asterisks denote that the variables are pointers, which are mere numbers pointing to memory locations where the objects live. When you declare a property that holds an object, all you are really doing is creating a place to store a pointer to the object. You aren't creating the object itself.
So somewhere (most likely in Person's designated initialiser), you'll want to actually create a Body object and assign it to the body property.
If you don't do this, then the memory location will remain at 0, which is equivalent to nil. When you chain the assignment here:
int feet = person.body.feet = 2;
...you're assigning 2 to both feet and person.body.feet, but since person.body is nil, the setter message to it is ignored. When later you try to log person.body.feet, again, it will be nil and return nil/0.
Edit: Having looked at your update, yes, this is your problem.
This line does not create a Body object:
Body *body;
It creates an instance variable for a pointer to a Body object.
This line does not create a Body object:
#property (assign) Body *body;
It declares a property, which is syntactic sugar for getter and setter method declarations.
This line does not create a Body object:
#synthesize body;
It synthesises your previously declared property by creating the getter and setter methods.
You need to actually create and initialise a Body object and then assign it to your Person object's body property. For instance:
- (id)init {
if (self = [super init]) {
self.body = [[Body alloc] init];
}
return self;
}
Also, as you aren't using ARC, you should almost certainly declare that property to be retain not assign, and release it in your Person's dealloc method.
For my beginner's level independent study of Objective-C, I was asked to add a counter to a class, so that each time a method was used on it, it would ++. However, I misinterpreted this as "Each time the method the method is called, ++." After realizing how to do what was asked of me, I pondered how I could fashion a method that would return a counter in addition to what the method was called to return. If I were to use a static int in addition to variable++; on each call of the method, how can I extract that value of variable in my main program?
Example code from comment:
-(Fraction *) add: (Fraction *) f {
static int fractaddcount;
fractaddcount++;
Fraction *result = [[Fraction alloc] init];
result.numerator = numerator * f.denominator + denominator * f.numerator;
result.denominator = denominator * f.denominator;
return result;
}
Make fractaddcount an instance variable and initialize it to 0 in the init method. Then it can be accessed by other methods in the class.
Additionally if you make it a property other classes will be able to access it. You can even make the property readonly in the .h file and read/write in the .m file (class extension).
Example:
in .h:
#property (non atomic, readonly, assign) int fractaddcount;
in .m:
in class extension:
#Interface TheClassName ()
#property (non atomic, readwrite, assign) int fractaddcount;
#end
in the implementation:
#synthesize fractaddcount;
in init: This is somewhat optional since when the class is instantiated the ivars are cleared to nil (0).
fractaddcount = 0;
in your code:
self.fractaddcount = self.fractaddcount + 1;