This question already has answers here:
Objective-C Static Class Level variables
(9 answers)
Closed 8 years ago.
Does someone know how to pass static object in objective c ?
In java its something like :
class A {
static int x;
...
}
class B {
...
A.x = 4;
}
something alike.
Someone know how to achieve the same result using Objective C NSString ?
thanks.
In Objective-C, there are no class (static) variables. One thing you can do is to use global variables, but that's generally discouraged:
// A.h
extern int x;
// A.m
int x;
// B.m
#import "A.h"
x = 4;
However, you should instead rethink your code design, you should be able to get away without using globals.
You'll have to declare your variable on the top of your .m and create a getter and setter for the static variable and work with that
static int x;
+ (int)getX {
return x;
}
+ (void)setX:(int)newX {
x = newX;
}
Objective-C doesn't have static/class variables (note that the difference between static and class methods is subtle but significant).
Instead you can create accessors on the class object and use a global static to store the value:
#interface MyClass : NSObject
+(NSString *)thing;
+(void)setThing:(NSString *)aThing;
#end
#implementation MyClass
//static ivars can be placed inside the #implementation or outside it.
static NSString *_class_thing = nil;
+(void)setThing:(NSString *)aThing {
_class_thing = [aThing copy];
}
+(NSString *)thing {
return _class_thing;
}
//...
#end
There is no direct way to do in Obj-C.
You need to create a class-method, that will access the static property.
// class.h
#interface Foo {
}
+(NSString *) string;
// class.m
+(NSString *) string
{
static NSString *string = nil;
if (string == nil)
{
// do your stuff
}
return string;
}
Related
I know that you can declare a C function outside of a class, but is it possible to declare a Objective-C method outside of a class?
Example:
// Works
void printHelloC()
{
NSLog(#"Hello.");
}
// Error
-(void) printHelloOC
{
NSLog(#"Hello.");
}
int main (int argc, const char * argv[])
{
#autoreleasepool {
printHelloC();
[self printHelloOC];// 'self' obviously would not work but you get the idea
}
return 0;
}
It depends. You can do something similar with method adding at runtime:
#import <objc/runtime.h>
void myCustomMethod(id self, SEL _cmd, id arg1, id arg2)
{
NSLog(#"This is a test, arg1: %#, arg2: %#", arg1, arg2);
}
int main(int argc, char *argv[])
{
Class NSObjClass = [NSObject class];
class_addMethod(NSObjClass, #selector(myNewMethod::), (IMP) myCustomMethod, "v#:##");
NSObject myObject = [NSObject new];
[myObject myNewMethod:#"Hi" :#"There"];
[myObject release];
return 0;
}
But that is about it outside of a #class construct, and it really just covers up what happens with a category.
You can use a category for this.
As an instance method:
#interface NSObject (MONStuff)
- (void)printHelloOC;
#end
#implementation NSObject (MONStuff)
- (void)printHelloOC
{
NSLog(#"Hello.");
}
#end
// in use:
NSObject * obj = ...;
[obj printHelloOC];
As a Class method:
#interface NSObject (MONStuff)
+ (void)printHelloOC;
#end
#implementation NSObject (MONStuff)
+ (void)printHelloOC
{
NSLog(#"Hello.");
}
#end
// in use:
[NSObject printHelloOC];
Of course, you must associate that with a class - so it's not exactly the same as you posted, but it's a close definition + declaration separate from the formal class declaration.
A method without an associated class is a meaningless concept. Functions, as you've noted, are just fine.
No, it is not possible - you will need to either use global C functions or class (+) methods.
Objective c functions are always associated with a class. If you mean you want to use an objective-c function without instantiating a class, you can of course write a class method (notice the plus sign instead of the usual hyphen)
#interface Test
+ (void)aClassMethod;
#end
then you can call it by calling
[Test aClassMethod];
c++ code
--------
#include "stdafx.h"
#include <iostream>
using namespace std;
class A
{
public:
static int a;
void set(int s)
{
a=s;
cout<<a<<endl;
}
void setData(int f)
{
cout<<"I am "<<f<<" years old!!!"<<endl;
}
};
int A::a=0;
int main()
{
A* ab=new A();
ab->set(10);
ab->setData(ab->a);
return 0;
}
I am trying to get the same output for
this equivalent Objective C code.
main.m
---------
#import <Foundation/Foundation.h>
#import "A.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
A* ab = [[A alloc]init];
[ab set:10];
[ab setData:ab.a]; //getting error when passed ab->a or ab.a as an argument
[pool drain];
return 0;
}
A.h
---
#import <Foundation/Foundation.h>
#interface A : NSObject {
}
-(void)set:(int)s;
-(void)setData:(int)f;
#end
A.m
----
#import "A.h"
#implementation A
static int a;
-(void)set:(int)s
{
a=s;
NSLog(#"%d\n",a);
}
-(void)setData:(int)f
{
NSLog(#"%d",f);
}
#end
Error:Request for member 'a' in something not a structure or union.
There are no static instance variables or methods in Objective C. What you want can be done with class methods and static file scope variables. Class methods are those methods sent to class objects rather than instances.
#interface AClass
{
}
+(int) a;
+(void) setA: (int) newValue;
#end
// A.m
static int aStorage = 0;
#implementation AClass
+(int) a
{
return aStorage;
}
+(void) setA: (int) newValue
{
aStorage = newValue;
}
#end
// To use:
int something = [AClass a];
[AClass setA: something * 2];
// Or dot syntax if you prefer
AClass.a = AClass.a * 2;
First, declaring a static int in your implementation file doesn't magically make it a member of class A; your ObjC class A has no member variables.
Second, ab->a isn't how you would access the member of a class in ObjC. Once you have a member, write a getter for a, and use a method call to access it. (Or if you really want it to be static, don't add a member, and just add a getter that returns the static variable.)
I have a very simple java code like this. I don't have any idea how to do this in Objective C. Especially, the static part which calls the getLocalAddress() method and assign it into the static string variable. I know how to set a static variable and a static method in Objective but I dont know how to implement that static { } part in java.
Thanks in advance...
public class Address {
public static String localIpAddress;
static {
localIpAddress = getLocalIpAddress();
}
public Address() {
}
static String getLocalIpAddress() {
//do something to get local ip address
}
}
I added this in my .h file
#import <Foundation/Foundation.h>
extern NSString *localIpAddress;
#class WifiAddrss;
#interface Address : NSObject {
}
#end
And my .m file looks like
#import "Address.h"
#import "WifiAddress.h"
#implementation Address
+(void)initialize{
if(self == [Address class]){
localIpAddress = [self getLocalIpAddress];
}
}
+(NSString *)getLocalIpAddress{
return address here
}
-(id)init{
self = [super init];
if (self == nil){
NSLog(#"init error");
}
return self;
}
#end
And Now I am getting a linking error and it complains about "extern NSString *localIpAddress" part. If I change the extern to static, it works fine. But what I wanted to do is that I want make the scope of "localIpAddress" variable as grobal. Since if I put "static" in front of a variable in Objective-C then the variable is only visible in the class. But this time, I want to make that as a grobal variable. So my question is how to make "localIpAddress" variable as a grobal variable which is initialized once when the first time Address class is created.. Thanks in advance...
You have declared the variable in your .h file (told the compiler that it exists and of which type it is), now you need to define it in your .m file (actually make it exist).
Just add NSString *localIpAddress; to your .m file, or better yet:
NSString *localIpAddress = nil;
(That is, give it a sane default value)
The extern keyword means: there is a variable of the given name and type, but actually lives in an "external" file that needs to be linked. So for each extern declaration, you need to actually define the variable in one of your implementation files (.c, .cxx/.c++/.cpp, .m ; this mechanism is part of the C standard on which Objective-C is standing).
Unless you want other modules to access localIpAddress directly without using your class, declare it as static inside your implementation (.m) file.
extern should be used in the following scenario:
A module defines the variable as global. That particular translation unit must not use extern
Other modules need to access that variable directly. Those particular translation units must use extern
Since this is not your case, do the following in your implementation (.m) file:
static NSString *localIpAddress;
// …
+(NSString *)getLocalIpAddress{
return localIpAddress;
}
and remove
extern NSString *localIpAddress;
from your header (.h) file.
Whenever you need to get that address, use
NSString *addr = [Address getLocalIpAddress];
By the way, the convention is that getter methods do not start with get. For instance, you could’ve named that method localIpAddress.
A quick fix would be to move the localIpAddress variable into your implementation file. Then you wouldn't need to use the extern keyword. Really, if you think about it, you have a static accessor, so there's no reason to have the variable declaration itself in the header.
Let me clarify:
Interface:
#import <Foundation/Foundation.h>
#interface Address : NSObject {
}
+(void) initializeLocalIpAddress;
+(NSString *) localIpAddress;
#end
Implementation:
#import "Address.h"
#import "WifiAddress.h"
NSString *localIpAddress;
#implementation Address
+(void) initializeLocalIpAddress
{
//get the local ip address here
localIpAddress = ...;
}
+(NSString *) localIpAddress
{
return localIpAddress;
}
-(id)init {
if ((self = [super init])) {
NSLog(#"init error");
}
return self;
}
#end
How do you initialise a constant in a header file?
For example:
#interface MyClass : NSObject {
const int foo;
}
#implementation MyClass
-(id)init:{?????;}
For "public" constants, you declare it as extern in your header file (.h) and initialize it in your implementation file (.m).
// File.h
extern int const foo;
then
// File.m
int const foo = 42;
Consider using enum if it's not just one, but multiple constants belonging together
Objective C classes do not support constants as members. You can't create a constant the way you want.
The closest way to declare a constant associated with a class is to define a class method that returns it. You can also use extern to access constants directly. Both are demonstrated below:
// header
extern const int MY_CONSTANT;
#interface Foo
{
}
+(int) fooConstant;
#end
// implementation
const int MY_CONSTANT = 23;
static const int FOO_CONST = 34;
#implementation Foo
+(int) fooConstant
{
return FOO_CONST; // You could also return 34 directly with no static constant
}
#end
An advantage of the class method version is that it can be extended to provide constant objects quite easily. You can use extern objects, nut you have to initialise them in an initialize method (unless they are strings). So you will often see the following pattern:
// header
#interface Foo
{
}
+(Foo*) fooConstant;
#end
// implementation
#implementation Foo
+(Foo*) fooConstant
{
static Foo* theConstant = nil;
if (theConstant == nil)
{
theConstant = [[Foo alloc] initWithStuff];
}
return theConstant;
}
#end
A simple way for value type constants like integers is to use the enum hack as hinted by unbeli.
// File.h
enum {
SKFoo = 1,
SKBar = 42,
};
One advantage to this over using extern is that it's all resolved at compile time so there no memory is needed to hold the variables.
Another method is to use static const which is what was to replace the enum hack in C/C++.
// File.h
static const int SKFoo = 1;
static const int SKBar = 42;
A quick scan through Apple's headers shows that the enum hack method appears to be the preferred way of doing this in Objective-C and I actually find it cleaner and use it myself.
Also, if you are creating groups of options you should consider using NS_ENUM to create a typesafe constants.
// File.h
typedef NS_ENUM(NSInteger, SKContants) {
SKFoo = 1,
SKBar = 42,
};
More info on NS_ENUM and it's cousin NS_OPTIONS is available at NSHipster.
I have a class Film, each of which stores a unique ID. In C#, Java etc I can define a static int currentID and each time i set the ID i can increase the currentID and the change occurs at the class level not object level. Can this be done in Objective-C? I've found it very hard to find an answer for this.
Issue Description:
You want your ClassA to have a ClassB class variable.
You are using Objective-C as programming language.
Objective-C does not support class variables as C++ does.
One Alternative:
Simulate a class variable behavior using Objective-C features
Declare/Define an static variable within the classA.m so it will be only accessible for the classA methods (and everything you put inside classA.m).
Overwrite the NSObject initialize class method to initialize just once the static variable with an instance of ClassB.
You will be wondering, why should I overwrite the NSObject initialize method. Apple documentation about this method has the answer: "The runtime sends initialize to each class in a program exactly one time just before the class, or any class that inherits from it, is sent its first message from within the program. (Thus the method may never be invoked if the class is not used.)".
Feel free to use the static variable within any ClassA class/instance method.
Code sample:
file: classA.m
static ClassB *classVariableName = nil;
#implementation ClassA
...
+(void) initialize
{
if (! classVariableName)
classVariableName = [[ClassB alloc] init];
}
+(void) classMethodName
{
[classVariableName doSomething];
}
-(void) instanceMethodName
{
[classVariableName doSomething];
}
...
#end
References:
Class variables explained comparing Objective-C and C++ approaches
As of Xcode 8, you can define class properties in Obj-C. This has been added to interoperate with Swift's static properties.
Objective-C now supports class properties, which interoperate with Swift type properties. They are declared as: #property (class) NSString *someStringProperty;. They are never synthesized. (23891898)
Here is an example
#interface YourClass : NSObject
#property (class, nonatomic, assign) NSInteger currentId;
#end
#implementation YourClass
static NSInteger _currentId = 0;
+ (NSInteger)currentId {
return _currentId;
}
+ (void)setCurrentId:(NSInteger)newValue {
_currentId = newValue;
}
#end
Then you can access it like this:
YourClass.currentId = 1;
val = YourClass.currentId;
Here is a very interesting explanatory post I used as a reference to edit this old answer.
2011 Answer: (don't use this, it's terrible)
If you really really don't want to declare a global variable, there another option, maybe not very orthodox :-), but works... You can declare a "get&set" method like this, with an static variable inside:
+ (NSString*)testHolder:(NSString*)_test {
static NSString *test;
if(_test != nil) {
if(test != nil)
[test release];
test = [_test retain];
}
// if(test == nil)
// test = #"Initialize the var here if you need to";
return test;
}
So, if you need to get the value, just call:
NSString *testVal = [MyClass testHolder:nil]
And then, when you want to set it:
[MyClass testHolder:testVal]
In the case you want to be able to set this pseudo-static-var to nil, you can declare testHolder as this:
+ (NSString*)testHolderSet:(BOOL)shouldSet newValue:(NSString*)_test {
static NSString *test;
if(shouldSet) {
if(test != nil)
[test release];
test = [_test retain];
}
return test;
}
And two handy methods:
+ (NSString*)test {
return [MyClass testHolderSet:NO newValue:nil];
}
+ (void)setTest:(NSString*)_test {
[MyClass testHolderSet:YES newValue:_test];
}
Hope it helps! Good luck.
On your .m file, you can declare a variable as static:
static ClassName *variableName = nil;
Then you can initialize it on your +(void)initialize method.
Please note that this is a plain C static variable and is not static in the sense Java or C# consider it, but will yield similar results.
In your .m file, declare a file global variable:
static int currentID = 1;
then in your init routine, refernce that:
- (id) init
{
self = [super init];
if (self != nil) {
_myID = currentID++; // not thread safe
}
return self;
}
or if it needs to change at some other time (eg in your openConnection method), then increment it there. Remember it is not thread safe as is, you'll need to do syncronization (or better yet, use an atomic add) if there may be any threading issues.
As pgb said, there are no "class variables," only "instance variables." The objective-c way of doing class variables is a static global variable inside the .m file of the class. The "static" ensures that the variable can not be used outside of that file (i.e. it can't be extern).
Here would be an option:
+(int)getId{
static int id;
//Do anything you need to update the ID here
return id;
}
Note that this method will be the only method to access id, so you will have to update it somehow in this code.
(Strictly speaking not an answer to the question, but in my experience likely to be useful when looking for class variables)
A class method can often play many of the roles a class variable would in other languages (e.g. changed configuration during tests):
#interface MyCls: NSObject
+ (NSString*)theNameThing;
- (void)doTheThing;
#end
#implementation
+ (NSString*)theNameThing { return #"Something general"; }
- (void)doTheThing {
[SomeResource changeSomething:[self.class theNameThing]];
}
#end
#interface MySpecialCase: MyCls
#end
#implementation
+ (NSString*)theNameThing { return #"Something specific"; }
#end
Now, an object of class MyCls calls Resource:changeSomething: with the string #"Something general" upon a call to doTheThing:, but an object derived from MySpecialCase with the string #"Something specific".
u can rename the class as classA.mm and add C++ features in it.
Another possibility would be to have a little NSNumber subclass singleton.