I am trying to declare a UInt32 variable that can be accessed by any method in the class..
so its global to the classes methods but not to any other class...
I am trying to do it like this in the .h
#interface EngineRequests : NSObject {
UInt32 dataVersion;
}
#property (copy) UInt32 dataVersion;
but thats not working.. I'm getting an error on the line #property etc.. do I even need that or is it fine to just use the UInt32 at the top.
You could try
#interface EngineRequests : NSObject {
#protected
UInt32 dataVersion;
}
#property (assign) UInt32 dataVersion;
#end
#implementation EngineRequests
#synthesize dataVersion;
// methods can access self.dataVersion
#end
But you don't really need the property, unless you want to grant/control outside access. You could just declare UInt32 dataVersion in the class interface and then reference dataVersion in the implementation without self. Either way, #protected will prevent outside classes from accessing dataVersion directly.
Have you read up on Objective-C Properties?
Initialization
Your EngineRequests is a subclass of NSObject. As such, you can (usually should) override NSObject's -(id)init method, like such:
-(id)init {
self = [super init];
if (self != nil) {
self.dataVersion = 8675309; // omit 'self.' if you have no '#property'
}
return self;
}
Or create your own -(id)initWithVersion:(UInt32)version;.
You need to declare the variable only inside interface to make it visible to all classes methods. Creating the getter-setter using #property.... will make it class variable and it will be visible outside the class. you have to do just this.
#interface EngineRequests : NSObject {
UInt32 dataVersion;
}
nothing more.
Related
I have declared private variables in implementation file of cycles.
myclass.m
#interface myclass()
#property (nonatomic) unsigned int number;
#end
Well, when I put in main.m something like this:
myclass * some = [[myclass alloc] init];
[some setNumber:10]; // no visible #interface for 'myclass' declares the selector 'setNumber'.
unsigned int a=[some getNumber]; //no visible #interface ...
Every answer on StackOverflow.com points the same as I do. What is the problem?
You can use readonly/readwrite property definitions to achieve this.
In MyClass.h
#interface MyClass : NSObject
#property (nonatomic, readonly) NSNumber *number;
#end
In MyClass.m
#interface MyClass ()
#property (nonatomic, readwrite) NSNumber *number;
#end
You can now read the number property outside of the class, and you will only be able to change it inside of MyClass.m. You can set it's value like so, self.number = 5 inside of MyClass.m.
Objective-C does not have the same type of private variables that a language like Java has. What is it that you are trying to accomplish with a private variable?
The problem is that the property number is a private property because you declared it in the interface section in your .m file. Declare it in your header myclass.h files interface block instead.. A private property, ivar, or method is one which can only be accessed from within an instance of your myClass object by using the self keyword (which is basically a pointer to the myClass instance within which you are currently executing).
Moving your property declaration to the header file will make the property accessible from outside the class instance. In other words, it makes it public.
If you want to restrict access to the data the property points to, define the property in the header file as a readonly property:
MyClass.h
#interface MyClass : NSObject
#property (nonatomic, readonly) unsigned int number;
#end
Then in your .m file create a private ivar manually and override the getter for the number property as follows:
MyClass.m
#implementation MyClass {
//Instance variable (ivar)
unsigned int _number;
}
unsigned int number()
{
return _number;
}
#end
That way a subclass (or anyone else for that matter) can't muck with the value of number. You can then access number in your main function as follows:
MyClass* myClass = [[MyClass alloc] init];
unsigned int newNumber = myClass.number; //There is no such selector called getNumber BTW, only number.
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"];
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
I simply want to change a variable of an object from another class. I can compile without a problem, but my variable always is set to 'null'.
I used the following code:
Object.h:
#interface Object : NSObject {
//...
NSString *color;
//...
}
#property(nonatomic, retain) NSString* color;
+ (id)Object;
- (void)setColor:(NSString*)col;
- (NSString*)getColor;
#end
Object.m:
+(id)Object{
return [[[Object alloc] init] autorelease];
}
- (void)setColor:(NSString*)col {
self.color = col;
}
- (NSString*)getColor {
return self.color;
}
MyViewController.h
#import "Object.h"
#interface ClassesTestViewController : UIViewController {
Object *myObject;
UILabel *label1;
}
#property UILabel *label1;
#property (assign) Object *myObject;
#end
MyViewController.m:
#import "Object.h"
#implementation MyViewController
#synthesize myObject;
- (void)viewDidLoad {
[myObject setColor:#"red"];
NSLog(#"Color = %#", [myObject getColor]);
[super viewDidLoad];
}
The NSLog message is always Color = (null)
I tried many different ways to solve this problem, but no success.
Any help would be appreciated.
Thanks for the help so far.
I modified the code as follow, but it still doesn't work as it should.
MyViewController.h:
#import <UIKit/UIKit.h>
#import "Object.h"
#interface MyViewController : UIViewController {
Object *myObject;
}
#property (nonatomic, retain) Object *myObject;
#end
MyViewController.m:
#import "MyViewController.h"
#import "Object.h"
#implementation MyViewController
#synthesize myObject;
- (void)viewDidLoad {
Object *myObject = [Object new];
myObject = 0;
[myObject setColor:#"red"];
NSLog(#"color = %#", myObject.color);
[super viewDidLoad];
}
If I do it like this, NSLog returns color = null (and I think myObject is only visible in viewDidLoad). How can declare myObject and make it visible in MyViewController?
I stripped down my Object class to
Object.h:
#interface Object : NSObject {
NSString *color;
}
#property(nonatomic, retain) NSString *color;
#end
Object.m:
#import "Object.h"
#implementation Object
#synthesize color;
#end
I wasn't able to define an object myObject in ViewDidLoad so that I can access its properties from the whole ViewController class? What did I miss?
Side question: Why do I have to set myObject to 0?
You're declaring a property, then explicitly declaring the accessors in Object.h. You only need to do one or the other - they mean the same thing (well, almost - you'll have color instead of getColor)
To implement the property in Object.m you should use #synthesize color. The explicit implementations, again, are then redundant (unless they do anything extra).
The explicit setColor implementation in Object.m is calling the property - which you are implementing explicitly, so I would have expected you to get an infinite recursion here.
MyViewController.m should probably synthesize label1, since you declare the property in the header (although it's not being used in your snippet).
[myObject getColor] is calling the color property, which you declared but did not synthesize. If you had explicitly implemented it as color it would have picked that up - but it won't match getColor (which is fortunately as that would have led to an infinite recursion again.
I don't see anywhere where you create your myObject instance. If you don't it will be nil and methods called on it (including property accesses) will return 0 or nil.
I suspect (6) is the cause of your issue, but the others need to be addressed too. Make sure you read up on property syntax.
I am assigning protocols in a couple classes that follow an inheritance tree. Like so:
first class
#protocol LevelOne
- (void) functionA
#end
#interface BaseClass : NSObject <LevelOne> {
}
second class
#protocol LevelTwo <LevelOne>
- (void) functionB
#end
#interface SubClass : BaseClass <LevelTwo> {
}
Later I am assigning the class as delegate properties of other classes
base class
#interface AppClass : NSObject {
#protected
id<LevelOne> levelOneDelegate;
}
#property (assign) id<LevelOne> levelOneDelegate;
subclass
#interface AppClassesFriend : AppClass {
#protected
id<LevelTwo> levelTwoDelegate;
}
#property (assign) id<LevelTwo> levelTwoDelegate;
At the end of this journey, AppClassesFriend has 2 properties on it.
"levelOneDelegate" has access to "functionA", when it is assigned with a BaseClass object.
However, I am finding that "levelTwoDelegate" only has access to "functionB" (it is assigned with a SubClass object).
In order to have AppClassesFriend be able to use both functions, it seems I need to assign BOTH a levelOneDelegate AND levelTwoDelegate.
Is there any way to make "levelTwoDelegate" have access to both? Since, both functions are available on "SubClass".
So, what I would like to be able to do is :
SubClass *s = [SubClass alloc];
AppClassesFriend *a = [AppClassesFriend alloc];
a.levelTwoDelegate = s;
so inside AppClassesFriend (a) I could use :
[self.levelTwoDelegate functionA]; <---- this is never found
[self.levelTwoDelegate functionB];
but it seems I have to add
a.levelOneDelegate = s;
Thanks if anyone took the time to read all the way down this far. So in summary the question is, how do I get "levelTwoDelegate" to have access to both functionA and functionB?
Simply declare that your subclass's delegate property implements both level one and level two protocols (i.e. implements both functionA and functionB):
#interface AppClassesFriend : AppClass {
#protected
id<LevelOne,LevelTwo> levelOneAndTwoDelegate;
}
#property (assign) id<LevelOne,LevelTwo> levelOneAndTwoDelegate;