I am having some issue about naming overridings of static variables in objective-c.
My .h file is:
#import <Foundation/Foundation.h>
#interface FetchClass : NSObject
+ (void)initWithNSManagedObjectContext:(NSManagedObjectContext *) managedObjectContext;
#end
And my .m file is:
static NSManagedObjectContext * managedObjectContext;
#implementation FetchClass
+ (void)initWithNSManagedObjectContext: (NSManagedObjectContext *) managedObjectContext{
FetchClass.managedObjectContext = managedObjectContext;
}
However, I get the error
"Property managedObjectContext not found on object of type FetchTasks"
So, the problem is, function argument managedObjectContext is of course overriding the static variable of the same name. That is why I have to get the static variable through Class.staticVariableName. But this time I get error as I mentioned above.
However If I change the static variable name to some other name , like:
static NSManagedObjectContext * managedObjectContextOtherName;
#implementation FetchClass
+ (void)initWithNSManagedObjectContext: (NSManagedObjectContext *) managedObjectContext{
managedObjectContextOtherName = managedObjectContext;
}
It works perfectly. My question is that, how to use these variables (static variable and function argument variable) if they have same name?
A static variable, like your managedObjectContext, is the closest thing to a class variable that Objective-C provides but it is not the same thing and this is why you get errors doing what you are trying - you cannot resolve your reference by qualifying it with the class name.
In (Objective-)C a static variable declared outside of any function/method has global lifetime and file scope - i.e. the variable always exists but is only visible from within the same source file as its declaration. There is no "file scope" qualifier you can use to resolve ambiguity/hiding when reference a static, any variable with the same name in an inner scope will hide the static.
In your case you can just use:
+ (void)initWithNSManagedObjectContext:(NSManagedObjectContext *)_managedObjectContext
{
managedObjectContext = _managedObjectContext;
}
(And there is no need to change your declaration of initWithNSManagedObjectContext: in the interface - parameter names are not required to match - so your "public" declaration doesn't require _'s in the names if you don't wish it to.)
Method arguments and instance variable should have different names. When they are the same, the compiler should warn you that it using the method variable.
Related
Upon receiving an NSString, I would like to call a specific code block. I figured an NSDictionary would be best for associating these. Simplified, I'm using something like:
MyProtocol.h:
#protocol MyProtocol <NSObject>
typedef void (^Handler)(id<MyProtocol> obj, id data);
#end
MyClass.h:
#interface MyClass : NSObject <MyProtocol>
- (void)aMethodWithString:(NSString *)string andData:(id)data;
#end
MyClass.m:
#interface MyClass ()
void myCommandHandler(id<MyProtocol> obj, id data); // matches signature defined in protocol
#end
#implementation MyClass
void myCommandHandler(id<MyProtocol> obj, id data)
{
// ...
}
- (void)aMethodWithString:(NSString *)string andData:(id)data
{
static NSDictionary<NSString *, Handler> *handler;
static dispatch_once_t onceToken;
// don't allocate this dictionary every time the function is called
dispatch_once(&onceToken,
^{
handler =
#{
#"MyCommand":myCommandHandler,
};
});
// ... error checking, blah blah ...
Handler block;
if ((block = handler[string]))
{ block(self, data); }
}
#end
Using this, I get an error in the dictionary literal construction:
Collection element of type 'void (__strong id<MyProtocol>, __strong id)' is not an Objective-C object`
So how can I include a C function or block reference in the dictionary? There will be quite a few larger complex functions to be defined, so it would be very much preferred to not have all of them defined inside the dictionary literal itself (a technique I know will work).
--
Also, I'm not sure what's considered proper style here: (1) I originally had the dictionary declaration outside of any method body at the file scope (without the dispatch_once(...)) which generates the same error, but I thought maybe it would be easier for others to see what's going on by (2) including it in the only method that uses that dictionary. Is one style preferred over the other for any reason?
Your Handler type is a block type, not a function pointer type. If you had declared it using * instead of ^, it would be a function pointer type.
Your myCommandHandler function is, of course, a function, not a block. Your comment is wrong. It does not match type Handler.
Function pointers are not Objective-C object pointers. Functions are not objects. Blocks are Objective-C objects, but you're not actually using any blocks here. (You've just declared a typedef for one, but you're not actually using it.)
You could use blocks and store them in your dictionary. The blocks could either contain the desired code or call a function or method which does.
A C function address is not an Objective-C object, and an NSDictionary can only store the latter.
A C function address is just a pointer, to wrap a C pointer as an object you use NSValue and its class method valueWithPointer.
To get the pointer value back from the NSValue object you use the instance method pointerValue. Before you can use the extracted pointer you must cast it to your function type.
HTH
I'm trying to use class property following this example. But I'm getting the following error:"Use of undecleared identifier '_myProperty'".
Here is my implementation:
#interface myClass()
#property (class,strong,nonatomic) NSString *myProperty;
#end
+ (NSString*)myProperty
{
if (!_myProperty) {
}
return [NSString new];
}
Why I'm getting this error? or any of you knows a work around this?
I'll really appreciate your help
Class properties don't get synthesized in Objective-C. You have to provide your own backing variable and your own getter/setter:
static NSString *_myProperty = nil;
+ (NSString *)myProperty {
if (!_myProperty) {
_myProperty = [NSString new];
}
return _myProperty;
}
+ (void)setMyProperty:(NSString *)myProperty {
_myProperty = myProperty;
}
Class properties and never auto-synthesised, the getter and/or setter must be implemented, and no backing variable is automatically created for them.
If your property needs a variable you must declare one, use a static global in the implementation file - that is effectively a "class variable" in Objective-C. Alternatively if you only require a getter you can declare a static variable local to the getter itself, further reducing its visibility and keeping the getter and variable together as a package.
HTH
In fact, class property is not a member of a class. So it will be created at once and all instances will use this one. So there is nothing to synthesize.
My code invokes a C library function:
#implementation Store
...
-(void) doWork {
// this is a C function from a library
int data = getData();
...
}
end
I am unit testing the above function, I want to mock the C function getData() in my test, here is my test case:
#interface StoreTests : XCTestCase {
int mData;
Store *store;
}
#end
#implementation StoreTests
-(void) setUp {
[super setUp];
mData = 0;
store = [[Store alloc] init];
}
-(void) testDoWork {
// this call will use the mocked getData(), no problem here.
[store doWork];
}
// mocked getData()
int getData() {
mData = 10; // Use of undeclared identifier 'mData', why?
return mData;
}
...
#end
Why I get complier error:
Use of undeclared identifier 'mData' inside mocked getData() function?
You are misunderstanding how instance methods and variables work.
Every instance method has a variable self which references the current instance (or "current object") and a use of an instance variable, such as mData, is shorthand for accessing that variable using self, e.g self->mData, where -> is the (Objective-)C operator for field access. So your setup method written "long hand" is:
-(void) setUp {
[super setUp];
self->mData = 0;
self->store = [[Store alloc] init];
}
But where does self, the reference to the instance, itself come from? Well it's not magical, just hidden, it is passed to an instance method automatically as a hidden extra argument. At this point which switch to pseudo-code to show this. Your setup method is effectively compiled as:
-(void) setUp withSelf:(StoreTest *)self {
[super setUp];
self->mData = 0;
self->store = [[Store alloc] init];
}
and a call such as:
StoreTests *myStoreTests = ...
[myStoreTests setup];
is effectively compiled as something like:
[myStoreTests setup withSelf:myStoreTests];
automatically adding the extra self argument.
Now all the above only applies to methods, and enables them to access instance variables and methods, it does not apply to plain C functions - they have no hidden self argument and cannot access instance variables.
The solution you mention in the answer you added of declaring mData outside of the interface:
int mData;
#interface StoreTests : XCTestCase {
Store *store;
}
#end
changes mData into a global variable, instead of being an instance variable. C functions can access global variables. However this does mean that every instance of the class shares the same mData, there is only one mData in this case rather than one for every instance.
Making an instance variable into a global is therefore not a general solution to to issues like this, however as it is unlikely that you will have more than one instance of your StoreTests class it is a suitable solution in this case.
You should however make one change: you can only have one global variable with a given name with a program, so your mData must be unique and is accessible by any code within your program, not just the code of StoreTests. You can mitigate this my declaring the variable as static:
static int mData;
this keeps the variable as global but only makes it visible to code within the same file as the declaration, which is probably just the code of StoreTests.
HTH
I found one solution for my question, that is declare mData above #interface StoreTests : XCTestCase, something like this:
int mData;
#interface StoreTests : XCTestCase {
Store *store;
}
#end
...
Example .h file:
#interface MyClass : NSObject
typedef NS_ENUM(int, myType) {
Something,
SomethingElse,
SomethingElseElse,
YetAnotherSomethingElse
};
{ //Error On This Line: Expected Identifier or '('
int aInstanceVariable;
}
//Some Methods go here
#end
Why am I getting that error (see the comment in the code above)? It works fine when below the class instance variable declaration, but I would like to use it as the type for one of my instance variables.
Thanks to #CarlVeazey, I discovered that the answer was simple: Move the typedef declaration to above #interface. The reason for this is that types cannot be owned by a class or an instance of a class, and therefore cannot be in the interface for a class.
Is is possible to create getters and setters for constants? I want to refer to a constant directly, and have it instantiate itself if it's value is nil. A constant declared like this:
// Prefs.h
extern MyClass * const kThing;
// Prefs.m
MyClass * const kThing = nil;
and the getter/setter would look like:
// getter
+ (MyClass *)kThing
{
_kThing = _kThing ? : [MyClass new];
return _kThing;
}
// setter
+ (void)setKThing:(MyClass *)myClass
{
_kThing = myClass
}
And then I could use it like:
[kThing doSomething];
Is this possible?
edit edited the methods to class methods
What you describe are not constants, they are global variables. You cannot define getters and setters for them, but you can use their values to back class methods, which is precisely what you have done.
However, when you send message like this
[kThing doSomething];
the global variable is used directly, bypassing your getter. If you want to go through a getter, you can write
[[MyClass kThing] doSomething];
or inside methods of MyClass you can write
[[[self class] kThing] doSomething];
Another note is that when yo implement accessor methods like that, you should make the backing variables static, rather than extern. This will ensure that other modules cannot access these variables bypassing your getters.
Global variable declaration in other file is very dangerous in objective C. Ideally we use sharedInstance. Try like this:
In MyGame.h
#interface MyGame : NSObject
{
int mScore;
}
#property(nonatomic,assign) int score;
+(MyGame*)sharedObject;
-(void)someFunction;
#end
In MyGame.m
static MyGame *gGame = nil;
#implementation MyGame
#synthesize score = mScore;
+(MyGame*)sharedObject
{
if(!gGame)
{
gGame = [[MyGame alloc] init];
}
return gGame;
}
-(void)someFunction
{
}
#end
To access anywhere in project:
#import "MyGame.h"
[MyGame sharedObject].score;
[MyGame sharedObject] someFunction];
The short answer is that this is not possible.
MyClass * const kThing = nil;
means that kThing is a constant pointer, which means that the address in memory that it points to cannot be changed. So once it's set to nil, it can't later be set to a new object.