PDA

View Full Version : Accessing a static variable from an instance method




nerak99
Sep 12, 2012, 04:42 AM
A kind person at cplusplus.com advised me that this was a good forum for Objective-C advice. For this reason, this is a cross post of my current position, but hopefully to a more appropriate audience. I am following the CS193P web course on YouTube.

I have some working code that regenerates a dictionary everytime a call is made and to be more efficient I want to create the dictionary as a static thing so that the generation only happens once.

The dictionary being immutable is fine.

This code is for me to learn rather than implement and so although I know the dictionary could be implemented as an array, I want to learn about dictionaries here.

My questions are, is this the right way to declare a static thing like a dictionary or can it only be used with primitives?

If it is not correct, what would be the correct way to do it?

I have done the following in code.

@implementation HP11Brain
@synthesize programStack = _programStack;

static NSDictionary *dictionaryOfOperators;


+(void) initialize {
if (self == [HP11Brain class])
{
dictionaryOfOperators = [NSDictionary dictionaryWithObjectsAndKeys:
@"/",[NSNumber numberWithInt:1]
, @"*",[NSNumber numberWithInt:2]
, @"-",[NSNumber numberWithInt:3]
, @"+",[NSNumber numberWithInt:4]
, nil];

}
}

// I am trying (within an instance method) to access the dictionary objects with things like


NSString *stringOfOperator = [self.class dictionaryOfOperators objectForKey:operation];

//objectForKey is not recognised by the compiler in this context.



jnoxx
Sep 12, 2012, 04:54 AM
Why make it static? Just create an ivar?

nerak99
Sep 12, 2012, 05:31 AM
Thank you for answering.

Well, an ivar seems to be C - speak for instance variable, which would seem to serve my purpose.

It would be very helpful to know why using a static variable was wrong and why this was so hopeless

NSString *stringOfOperator = [self.class dictionaryOfOperators objectForKey:operation];

Can an ivar be a class level thing as opposed to instance level?

KnightWRX
Sep 12, 2012, 05:42 AM
Why do you think the following line is wrong ?

[self.class dictionaryOfOperators objectForKey: operation];

Seems you're mixing up quite a few things in that line, most notably properties and instance methods, not to mention throwing in a global variable in there... Basically, you've got very wrong syntax here.

What do you understand of instance methods, properties, and global variables in the context of Objective-C ?

nerak99
Sep 12, 2012, 06:06 AM
Thank you for answering. In the following think might mean I am not sure but ...

Basically, you've got very wrong syntax here.

Well XCode agrees with you and I have to say, that is why I said something like

My work is progressing on Obj-C. I would say that I am reasonably clear on Obejcts and classes but only making progress on the use of [], ., and : in syntax for calling methods and referring to variables. But I am one hell of a lot further on than I was a month back.

In coding in java you are dealing with fewer flavours than seems to be the case with C and so I get confused in reading posts that are working in different environments.

In java instance variables are so far as I can tell, like properties in Objective C.

I think that properties have to be associated with an instance of a class and so cannot be static

Instance methods are methods associated with an instance whereas class methods do not need an instance to run. For this reason an instance method can not be called by a class method because there is no object (instance of the class) in existence.

I think that a class method could be called by an instance method though. (Given the correct syntax,

I think I am after a class based instance of a NSDictionary which will exist once in my program and can be called on by any instance of my class. I do not know if you can have an instance of an object such as a String or Dictionary as a static object in the sense that I am trying to work.

I think what I have at the moment is a dictioanry that gets recreated every time I call the method


Basically, you've got very wrong syntax here.

So, if you could help me out there I would be very grateful.

KnightWRX
Sep 12, 2012, 09:54 AM
I think that properties have to be associated with an instance of a class and so cannot be static

I think that a class method could be called by an instance method though. (Given the correct syntax,

I think I am after a class based instance of a NSDictionary which will exist once in my program and can be called on by any instance of my class. I do not know if you can have an instance of an object such as a String or Dictionary as a static object in the sense that I am trying to work.


Let's break down your line :

[self.class dictionaryOfOperators objectForKey: operation];

First is self.class. What is this to you ? What does this mean ?

Next is dictionaryOfOperators, what is this to you ? What does it mean ?

Then there's objectForKey: operation. What is this to you ? What does it mean ?

You're encompassing this without 1 set of brackets, []. What are brackets and what are their use in Objective-C ?

nerak99
Sep 12, 2012, 10:18 AM
Both of the following work, one method from a person on cplusplus referred to above.

One uses a property and a getter whilst the other seems more standard C++

Neither uses a static and a class method as I thought I should be using.


// in the .m file interface
{
NSDictionary *dictionaryOfOperators;
}

and in the implementation

- (id) init
{
self = [super init];

if ( self != nil )
{
dictionaryOfOperators = [NSDictionary dictionaryWithObjectsAndKeys:
@"/",[NSNumber numberWithInt:1]
, @"*",[NSNumber numberWithInt:2]
, @"-",[NSNumber numberWithInt:3]
, @"+",[NSNumber numberWithInt:4]
, nil];
}

return self;
}

- (NSString *) getOperatorWithKey: (NSNumber) key
{
return [dictionaryOfOperators objectForKey:key];
}
@end


OR



//Alternatively

// in the interface
@property (nonatomic, weak) NSDictionary *dictionaryOfOperators;
@end

@implementation HP11Brain
@synthesize dictionaryOfOperators = _dictionaryOfOperators;

- (NSDictionary *)dictionaryOfOperators{
if (!_dictionaryOfOperators) {
self.dictionaryOfOperators = [NSDictionary dictionaryWithObjectsAndKeys:
@"/",[NSNumber numberWithInt:1]
, @"*",[NSNumber numberWithInt:2]
, @"-",[NSNumber numberWithInt:3]
, @"+",[NSNumber numberWithInt:4]
, nil];


}
return _dictionaryOfOperators;
}



The call being the same

KnightWRX
Sep 12, 2012, 10:26 AM
Both of the following work, one method from a person on cplusplus referred to above.

One uses a property and a getter whilst the other seems more standard C++

Neither uses a static and a class method as I thought I should be using.


Do you understand though what would happen between 2 instances of your class, as to your dictionaryOfOperators ?

Do you understand why the 2nd method and first are different and how they differ ?

And do you understand what is the difference between those 2 solutions and what you were initially trying ?

If you don't answer our questions and just change things without understanding what you're doing, you'll never achieve your goal, which seems to be a single dictionary shared amongst many instances of the same class. Am I wrong in believing that was your goal ?

chown33
Sep 12, 2012, 12:50 PM
In coding in java you are dealing with fewer flavours than seems to be the case with C and so I get confused in reading posts that are working in different environments.


I don't know what you mean by "flavours". Do you mean types? Classes? Keywords? Something else?


In java instance variables are so far as I can tell, like properties in Objective C.

This is wrong. Java instance variables are exactly the same as Objective-C instance variables. There's nothing in Java that's exactly like Objective-C properties.

See this language reference guide:
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/

For properties, I suggest reading the section named "Declared Properties".

You might want to read this reference, too:
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/OOP_ObjC/Introduction/Introduction.html%23//apple_ref/doc/uid/TP40005149

And check your knowledge with this:
http://developer.apple.com/library/ios/#documentation/General/Conceptual/DevPedia-CocoaCore/

Cocoa fundamentals, including design patterns:
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/CocoaFundamentals/

----------

Why make it static? Just create an ivar?

Since the dictionary is the same for all instances, and is immutable, it's not necessary to make an ivar for it. It's static so it can be shared by all instances of the class, but is not visible to any code outside the class implementation file.

Objective-C doesn't have class variables (i.e. static means exactly what it does in C, not what means in Java). The simplest way to make a variable that is accessible to all instances of a class, and is shared by them all, is with a static variable. There are other ways (see "Associative References" in the language guide linked above), but they are more complex, and they don't solve this specific problem any better than simply using a static variable.

nerak99
Sep 12, 2012, 02:49 PM
I am very grateful for all the help that I am getting in helping me grapple with my syntax issues with Objective C and C++.

In all my searches and questions I have improved my understanding of variables, classes etc in C++/Obj-C. I have still not been able to develop what I think I should be able to make and that is

1) A class method that returns a lookup in a static Dictionary.
2) A method of calling that class method from an instance method.

But I am getting there.

Some kind people have let me have example code to illustrate points and I am grateful to them. I am not an expert in this field but I do not need patronising with questions.

So far as developing code is concerned I know what I want to do and for the most part how to do it. I have a physics thesis on my shelf (somewhere) that includes multigridding methods to solve the Navier Stokes equations for fluids over rough surfaces. The code beat the standard libraries at the time for my particular application by a factor of 400 and was cutting edge at the time. The syntax however is considerably simpler than in the most trivial iOS App.

Most of the sources in C insist on taking you through endless repetition of well trodden algorithm implementations that I know very very well and they do not illustrate the points that I am after.

Where I have problems is mainly with syntax and examples help me see how this works.
Your answers (@knightwrx) are almost entirely questions which doesn't help and can be viewed as a put down and little more.

Where I have tentatively put my head above the parapet to offer a glimpse of where I think I just might be understanding something (@chown33) is also ready with a put down.

For example I said
In java instance variables are so far as I can tell, like properties in Objective C.
you said,
This is wrong

Now I am sure you are an expert but the Internet is a wild west of opinions and at least a few people seem to imply that they are pretty closely related in the sense that a property encompasses more than an instance variable but on the other hand you rarely write an instance variable in Java without writing a getter and setter to access them. If you have an idea to help then providing an example would improve the quaility of your answers.

These two links (for example) seem, like you, to be authoratative and are a bit more nuanced than 'WRONG.'

http://stackoverflow.com/questions/10122507/what-exactly-is-a-property-in-objective-c-what-is-the-difference-between-a-property-and-an-instance-variable

AND

http://shinydevelopment.com/blog/automatic-property-instance-variables-with-objective-c/

Where you say (@chown33), (with authority) Objective-C doesn't have class variables

From Cplusplus we get (in Tutorial 2) (also with authority)
A class can contain static members, either data or functions.

Static data members of a class are also known as "class variables", because there is only one unique value for all the objects of that same class. Their content is not different from one object of this class to another.

So C++ does have the concept and so a bit more explanation would help the reader see the difference between these two flavours of C++.

And here http://jongampark.wordpress.com/2009/04/25/class-variable-for-objective-c-and-c/ we have a real authority who says that there is something like the concept of the class variable in Objective C.

By Flavours, I mean that we have a number of languages that seem (to me) to be based on or descended from C++. For example Obj-C. That is just my perception but in searching for answers to questions I get comments like.

(In answer to Objective C being substantially the same as C++)

Functionally and conceptually, maybe. Syntactically, not really. To be honest, I think MacRumors may have been a better place for it....

Now it is a fair point to say that there is only one C++ standard but the fact of the matter is that different compilers and institutions vary in their adherence to the standard. For example MS compilers have had a poor reputation in the past if you look for complaints of poor adherence. In fact MS themselves have been accused of deliberatley bending the C++ standards to their own version.

http://en.wikipedia.org/wiki/Criticism_of_Microsoft

As an objective measure, if you google "C++ API" the first 5 or 6 finds are all from different people whereas for java, the first 5 are all from oracle.

I am no java fanboy nor for that matter do I like centralisation particularly but Apple seem to be keen on supporting a well documented API for Obj-C that is as good as the one Oracle publishes for Java. Of course one could argue that Googles "embrace and extend" efforts (regardless of their motive) do not help consistency.

dejo
Sep 12, 2012, 04:13 PM
What resources are you using to learn about Objective-C? (Please be as specific as you can.) What has lead you to believe that Objective-C is based on or descended from C++?

nerak99
Sep 12, 2012, 04:36 PM
My main resources are the CS193P course and apple.dev documentation.

OMG I do not want to paint myself into a corner of being a C++ expert. I have never claimed to be. Only that the syntax is similar because they both derived from C at about the same time and people program the same devices in either language (and sometimes both languages at the same time).

I am merely a Java person trying to program Apple devices and in fact the only thing I have said about the two languages was where I confessed to having formed the impression that they were substabtially the same and someone politely told me that they weren't.

The fact that I now know that they merely came from the same stable, as it were, will enable me to look out for the differences.

chown33
Sep 12, 2012, 04:41 PM
I pointed you at the language guide specifically so you could read what properties are, in the most authoritative way, and with all the necessary nuance. I could have written a more nuanced response, but it's much better that you read it from the actual language reference, where you can see the whole thing described.

Quoting from the first line of the Declared Properties section:
The Objective-C declared properties feature provides a simple way to declare and implement an object’s accessor methods.

It doesn't say anything about "instance variables", because they are different things.

If you had originally written, "In Java, accessor methods are, so far as I can tell, like properties in Objective C." I would have said that's mostly correct [1]. But that's not what you wrote.

Both Java and Objective-C have instance variables, and they work the same in both languages. They are not only "like" one another, they are identical.


If your instance variables often have accessor methods written for them in Java, then that is your design choice. It is by no means a requirement of either instance variables or accessor methods. A proliferation of accessor methods in Java may be a sign of a poorly encapsulated design (http://www.codinghorror.com/blog/2006/08/properties-vs-public-variables.html). I frequently write Java classes where instance variables are entirely encapsulated, and there are no accessors that directly expose that variable. Same thing in Objective-C. If I write accessors (or properties), I do it intentionally, not because there's a fundamental one-to-one principle between instance variables and accessor methods.

In any case, accessor methods need not be backed by instance variables, and instance variables need not have accessor methods. They are separate things, to be treated separately in the design. Imagine a Rectangle class where area is a property (accessor method). But area depends on dimensions, and doesn't have separate instance variables, but is calculated from width and height. Thinking that properties and instance variables always go together is a fundamental mistake.


Regarding class variables, I disagree with those who call them that. They are simply static variables. Their presence in the class implementation file doesn't change that fact. For example, a static variable need not be defined between @implementation and @end, yet it will still be visible to the rest of the code in that file.

I feel confident in calling them "static variables" rather than "class variables" because Objective-C is a strict superset of C. C++ is not. "Strict superset" means that every keyword in C means exactly the same thing in Objective-C, and every valid C program is also a valid Objective-C program with identical semantics.

When you define a static variable in Objective-C, it means exactly the same thing it does in C. There is no difference at all. To understand the semantics, all you need to understand is how C uses the keyword "static", and you'll then know everything necessary to understand how Objective-C uses that keyword.

One might argue that static variables are similar to class variables, but there's a big distinction: static variables aren't part of the class implementation. Static variables also don't have a classname qualifier as part of their reference syntax.

So when you were apparently trying to reference the static variable dictionaryOfOperators in this code fragment:
NSString *stringOfOperator = [self.class dictionaryOfOperators objectForKey:operation];

you were doing it wrong, because you seem to believe that it requires a class or classname (self.class) preceding the variable name. This is mistaken. A static variable is referenced in Objective-C exactly the same way it's referenced in C: simply by giving its name.


Again, I refer you to the previously linked language reference guide. I strongly recommend using it as the authoritative reference.


Regarding "flavours", both C++ and Objective-C (and Java) are derived from C. They diverge from that point, and don't have a strict lineal ancestry, though there are influences. Look up each language on Wikipedia and note the appearance date of each.


[1] Only "mostly correct" because declaring something as a property also gives the ability to synthesize accessors, which can automatically create code for different attributes, such as atomic, read-only, copied, or retained. Java has nothing like that for its accessor methods, because it has no specific property syntax. If you want atomic access in an accessor method, you have to manually write your accessor methods that way, using the keyword synchronized in the right place. A synthesized property accessor does all that for you (if you want).

Java also doesn't support using accessor methods as lvalues, while Objective-C properties are valid as lvalues (i.e. assignable using =).

So while Java's accessor methods may be similar in purpose (encapsulation, access control) to properties, they are quite different in how they are used in actual code.

nerak99
Sep 12, 2012, 04:58 PM
Well as I said before

I am very grateful for all the help that I am getting in helping me. My original question (which I have pared down as my understanding has improved) was

how do I declare and use a class method that returns a lookup in a static Dictionary and a way of calling that class method from an instance method?

I am am still working on finding an answer to that.

I have had a bewildering array of advice, some of which is helpful, some not so helpful and some just saying RTFM (which I am doing but there is a lot there).

But I am getting there.

My original question still stands and I and still writing code that the XCode compiler won't use and I get confused. I am writing a lot more code that the compiler doesn't object to and that's good.

Finally, I still maintain that if someone is prepared to go to the effort of telling me that I have the wrong syntax it would be really helpful if they could suggest the right syntax if they actually have an idea of what it might be.

chown33
Sep 12, 2012, 05:13 PM
how do I declare and use a class method that returns a lookup in a static Dictionary and a way of calling that class method from an instance method?

One of the links I posted discusses design patterns. Look at the Singleton pattern.

I point you at it instead of paraphrasing it because it's better if you read the whole thing.


Finally, I still maintain that if someone is prepared to go to the effort of telling me that I have the wrong syntax it would be really helpful if they could suggest the right syntax if they actually have an idea of what it might be.
You have the wrong syntax.

I already stated what the right syntax would be: simply giving the name of the static variable. So if this is your static variable definition:
static NSDictionary *dictionaryOfOperators;

And this is the code that doesn't work:
NSString *stringOfOperator = [self.class dictionaryOfOperators objectForKey:operation];

then simply giving the name of the static variable looks like this:
NSString *stringOfOperator = [dictionaryOfOperators objectForKey:operation];

The reason is as I said: it's a simple static variable, in precisely the way that C defines the term; it's not a "class variable" in any sense.


If that code doesn't work, then please post again, including the code that fails along with the complete text of any compiler error messages.

KnightWRX
Sep 12, 2012, 05:35 PM
Finally, I still maintain that if someone is prepared to go to the effort of telling me that I have the wrong syntax it would be really helpful if they could suggest the right syntax if they actually have an idea of what it might be.

If we tell you what the right syntax is, you've not learned anything, you've just copy/pasted the right syntax. You still don't understand what [] means, what is the difference between a class method or an instance method, what a property is, etc..

So basically, it's not helpful at all to give you the right syntax, no matter how much you think it is. Giving you references to the documentation about the Objective-C language is the best advice we can give you right now. Go back to square 1 and learn the language. A lot of what you're confused about now is simply a lack of knowledge of Objective-C itself.

PhoneyDeveloper
Sep 12, 2012, 06:01 PM
I usually do it like this:

- (NSDictionary *)dictionaryOfOperators{
static NSDictionary * _dictionaryOfOperators = nil;
if (!_dictionaryOfOperators) {
_dictionaryOfOperators = [NSDictionary dictionaryWithObjectsAndKeys:
@"/", [NSNumber numberWithInt:1],
@"*", [NSNumber numberWithInt:2],
@"-", [NSNumber numberWithInt:3],
@"+", [NSNumber numberWithInt:4],
nil];
}
return _dictionaryOfOperators;
}

Not an ivar. Not a file scope static.

Apparently in iOS 6 the new dev tools have static dictionaries so this can be done in a more direct way.

dejo
Sep 12, 2012, 06:03 PM
how do I declare and use a class method that returns a lookup in a static Dictionary and a way of calling that class method from an instance method?

You should clarify: do you want to access this static dictionary instance variable from within the same class (in which case, a class method is unnecessary) or from within an instance of an entirely different class (which is a whole different ball-of-wax)?

nerak99
Sep 12, 2012, 06:08 PM
To answer dejo. Just within this class. but I would still like to see it work as a class method, just out of interest.

OK, thanks that seems to work.

Just to clarify my understanding,

I have populated the dictionary in an init method as here after decalring it in the header as a static
- (id) init
{
self = [super init];

if ( self != nil )
{
dictionaryOfOperators = [NSDictionary dictionaryWithObjectsAndKeys:
@"/",[NSNumber numberWithInt:1]
, @"*",[NSNumber numberWithInt:2]
, @"-",[NSNumber numberWithInt:3]
, @"+",[NSNumber numberWithInt:4]
, nil];
}

return self;
}

And called it as you described (but I am not making more than one dictionary in the life of the instance?).

I think that I have to still have an instance of my class to see the Dictionary members because I populated it in the init method which is acting a bit like a constructor in java. (Hides from baying mob of C programmers!)

Can I fully define the Dictionary as a static so that I can use it from a class method?

chown33
Sep 12, 2012, 06:34 PM
- (NSDictionary *)dictionaryOfOperators{
static NSDictionary * _dictionaryOfOperators = nil;
if (!_dictionaryOfOperators) {
_dictionaryOfOperators = [NSDictionary dictionaryWithObjectsAndKeys:
@"/", [NSNumber numberWithInt:1],
@"*", [NSNumber numberWithInt:2],
@"-", [NSNumber numberWithInt:3],
@"+", [NSNumber numberWithInt:4],
nil];
}
return _dictionaryOfOperators;
}
This is missing a retain, unless it's using ARC.

Also, it's an instance-method, not the asked-for class-method.

----------

- (id) init
{
self = [super init];

if ( self != nil )
{
dictionaryOfOperators = [NSDictionary dictionaryWithObjectsAndKeys:
@"/",[NSNumber numberWithInt:1]
, @"*",[NSNumber numberWithInt:2]
, @"-",[NSNumber numberWithInt:3]
, @"+",[NSNumber numberWithInt:4]
, nil];
}

return self;
}

Think about what happens each time -init is called.

Is dictionaryWithObjectsAndKeys: creating and returning a new dictionary each time? What happens to the value previously stored in dictionaryOfOperators, from the last time -init was invoked?

Why did you change the creation of the dictionary? Did anyone say your previous code with +initialize was wrong? It compiled, didn't it, so that part was at least syntactically correct. The problem was with your reference to the static variable.

nerak99
Sep 12, 2012, 06:37 PM
I am using ARC. It is like garbage collector only better.

Anyway, yes it is an instance method which brings us full circle, because I had an instnace method (but not an init) all along.

So how fo I fill my Dictionary in a class method because I can't work that out.

chown33
Sep 12, 2012, 06:43 PM
So how fo I fill my Dictionary in a class method because I can't work that out.

See your first post. The code in +initialize was correct as posted. FWIW, +initialize is a class-method, not an instance-method.

The definition of the static variable was also correct.

The only incorrect part was this:
NSString *stringOfOperator = [self.class dictionaryOfOperators objectForKey:operation];

and I have already posted exactly what to change (see post #15).

nerak99
Sep 12, 2012, 06:53 PM
That is exactly what I started out wanting to do, Thanks. I tried +(void) but forgot to change init to initialize.

When the compiler throws back a command, I end up trying to feed it anything it will eat. Which I know is the wrong way about it but I am just human.

Thanks very much. I have learned a lot.

dejo
Sep 12, 2012, 07:08 PM
When the compiler throws back a command, I end up trying to feed it anything it will eat. Which I know is the wrong way about it but I am just human.

Granted, but it's a bad habit that a good programmer should avoid.

PhoneyDeveloper
Sep 13, 2012, 07:14 AM
Also, it's an instance-method, not the asked-for class-method.

Right. Change it to this if you like:

+ (NSDictionary *)dictionaryOfOperators{
// etc.


Same Same.

(And the Stanford course only teaches ARC, not managed memory.)

firewood
Sep 13, 2012, 11:26 AM
In Objective C, a static variable is just a C global variable restricted to file scope. Using C global variables does not work very cleanly for containing object pointers under ARC.

A better methodology might be to contain your static object as an ivar inside singleton object in a helper class. Then the property setter will handle the retain count correctly.