Do variables declared in methods get erased after the method call is done? Ie If i have the method "someMethod" and every time it is called i want to return a different NSString from a stack property will the method return the next object on the stack or will it keep returned the first index since x is erased at the end of the method call. I know if C that variables are erased after function calls, is it the same in objective c? Would using a seperate property for the variable x some this problem? Thanks
(Double) someMethod{
int x;
[self.stack objectAtIndex:x];
x++;
}
After reading the comments I tried creating a property to replace x and here is what I wrote but I get an error warning stating "local declaration of "_location" hides instance variable" What does this mean?
#property (nonatomic) int location;
#synthesize location=_location;
-(int) location{
if(!_location){
int _location = 0;
//warning is here
return _location;
}
_location++;
return _location;
}
(Double) someMethod{
int x;
[self.stack objectAtIndex:self.location];
x++;
}
Do variables declared in methods get erased after the method call is done?
Yes
Objective C methods are implemented "on top" of C functions, so the same rules apply. In particular, your code exhibits undefined behavior (reading of uninitialized variable).
To fix this issue, add an instance variable x in place of the automatic variable that your code snippet currently declares.
automatic is the "official" name of "stack" variables, i.e. variables that you declare inside your methods / functions.
Yes, the lifetime of local variables is limited to the time the enclosing function is executing (with exceptions for blocks, but you're not using those in this case).
Your counter x is probably best as an object property, if you want to maintain its value between calls to someMethod.
Answering to your question about the warning...
It is just saying that when you declare inside your if in method location()
int _location = 0;
this local variable has the same name as the property you created earlier
#syntenshize location = _location
Thus it gets confusing (for the programmer) to know which one he is using at the moment.
The compiler will understand that inside the if _location is an int ... and outside the if _location is your property.
Related
According to this comment:
C functions inside #implementation blocks have the unique property of
being able to access private and protected ivars directly. Thus, from
my own experience, it's become a strong idiom to place C functions
that "belong" to a class inside the corresponding implementation.
My code, defining a private instance variable in the implementation only as suggested by this answer:
With the brackets:
#implementation ViewController{
MyTest *tt;
}
void testf(){
NSLog(#"hello back from c++ into obj c land");
[tt testcf: 5];
}
...
Will not build; the compiler indicates that tt in testf is undeclared. If I remove the brackets, then the C function works fine.
But... if I remove the brackets, do I understand that actually this is no longer an instance variable, but sneakily it is a global variable, disconnected from the class, despites its placement in the #implementation? It would appear that this is indeed true, since I can do this as the end:
#end
void testf2(){
NSLog(#"hello back from c++ into obj c land");
[tt testcf: 5];
}
And the compiler does not contain about tt being out of scope. So -- how to declare a private instance variable in an implementation and have it truly be an instance variable, but also have a C function be able to access it? For the purposes of this question, I am trying to get this to work based on the linked comments/answers without using the id pointer of the object itself.
You will need to pass a reference to self to the C-function:
void testf(ViewController *vc){
NSLog(#"hello back from c++ into obj c land");
[vc->tt testcf: 5];
}
and call it like this:
- (void)someMethodInViewController
{
testf(self);
}
However it's not clear why you are using C-functions at all.
Can someone confirm that you cannot access instance variables defined in an Objective C #implementation block from within C style functions of the same class? The compiler is throwing errors saying "XXX undeclared' where XXX is the instance variable name.
Here's an example of what I am explaining:
#interface FontManager : NSObject {
CGFontRef fontRef;
}
static int CstyleFunction() {
NSUInteger emSize = CGFontGetUnitsPerEm(fontRef);
}
I want to verify that I cannot use "fontRef" from withing "CstyleFunction".
Any insight would be greatly appreciated.
A "C style method" doesn't really deserve the name "method", I'd call it a "function" instead as in C.
A C function has no self, so it cannot implicitly access ivars as a method can. If you pass an instance to the C function as a parameter, you can access ivars in the same manner you would access a field in a struct pointer.
#Anomie and #jlehr are correct, the C function has no concept of the FontManager object and its current state, it just happens to live in the same file.
However, if FontManager is a singleton and you make fontRef a property (or create an accessor for it), then it would be possible to access the value within your C class:
static int CstyleMethod() {
FontManager *fm = [FontManager sharedManager];
NSUInteger emSize = CGFontGetUnitsPerEm(fm.fontRef);
}
Bottom line, you can mix-and-match C and ObjC syntax within C functions & ObjC methods. But because C functions have no default reference to self (and the object's associated instance variables), you can only reference ObjC objects that are singletons, stored in a global variable, or passed in as parameters.
That's correct. You seem to be mixing up methods and functions though. Methods exist only in Objective-C. What you're referring to as a 'C style method' is really just a C function.
C is not an object-oriented programming language. Since there's no such thing as an object in C, there's also no such thing as an instance variable in C, so the fontRef instance variable would not be visible in the function you posted, nor for that matter in any other C function in your program.
I'm not sure how much use this question is but it seems interesting to me...
I thought that using property/synthesize statements was equivalent to me creating the getter/setter. Therefore
// .h
#property (nonatomic) BOOL on;
// .m
#synthesize on = _on;
// In my mind synthesizes the following methods
// - (BOOL)on;
// - (void)setOn:(BOOL)on;
However if I change the declarations to the following:
v
#property (nonatomic, getter=isOn) BOOL on;
#synthesize on = _on;
// In my mind synthesizes the following
// - (BOOL)isOn;
// - (void)setOn:(BOOL)on;
Then given the above I override the getter so I know when it is called:
- (BOOL)isOn;
{
NSLog(#"I was called");
return _on;
}
Now calling the following on an instance (myClass) results in:
NSLog(#"%d", [myClass isOn]);
//=> 2012-02-09 22:18:04.818 Untitled[1569:707] I was called
//=> 2012-02-09 22:18:04.820 Untitled[1569:707] 1
NSLog(#"%d", myClass.isOn);
//=> 2012-02-09 22:18:24.859 Untitled[1599:707] I was called
//=> 2012-02-09 22:18:24.861 Untitled[1599:707] 1
NSLog(#"%d", myClass.on); // This is the one I didn't expect to work
//=> 2012-02-09 22:18:55.568 Untitled[1629:707] I was called
//=> 2012-02-09 22:18:55.570 Untitled[1629:707] 1
I had always assumed that if I was using a property in this sense it was perfectly valid to use the getter/setter with dot syntax in the form
myClass.isOn;
myClass.on = on;
From another question it was suggested that when using dot syntax I should use the property name like this:
myClass.on // Correct
myClass.isOn // Incorrect
Although this works it seem slightly less logical because I know there is no underlying method - (BOOL)on it is instead mapped to - (BOOL)isOn
My questions are (using the latter example)
Is this a bug or should myClass.on really be silently changed to call - (BOOL)isOn
Semantically speaking I am accessing state not invoking behaviour so is my current use of dot syntax correct? (e.g. myClass.isOn)
Update
Although no one has explicitly said it I have reasoned that using .isOn is bad form because regardless of the fact that under the hood the same method is called, semantically isOn is asking a question, which is more behaviour rather than state.
However I am still unclear on where the "magic" wiring goes on that turns calls to myClass.on into [myClass isOn]
Update 2
After looking around the docs some more I found this section on Declared Properties. Using the following code I can inspect a class' properties:
id MyClass = objc_getClass("MyClass");
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList(MyClass, &outCount);
for (i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
NSLog(#"Name: %s, attributes: %s\n", property_getName(property), property_getAttributes(property));
}
//=> 2012-02-10 07:10:28.333 Untitled[934:707] Name: on, attributes: Tc,GisOn,V_on
So we have the following attributes:
name = on
type = char (Tc)
getter = isOn (GisOn)
variable = _on (V_on)
With all of this information available at runtime it kind of leaves the question is this lookup done at runtime or compile time like some answers suggest?
However I am still unclear on where the "magic" wiring goes on that turns calls to myClass.on into [myClass isOn]
The logic surely goes as follows, when compiling an obj.name in a getting context:
if(there is an accessible #property for name in scope)
{
if(there is a custom getter specified)
compile "[obj customGetter]"
else
compile "[obj name]"
}
else if (there is an an accessible instance method name in scope)
compile "[obj name]"
else
{
compile "[obj name]"
warn obj may not respond to name
}
There are other ways a language/execution environment can handle custom getter names, but given that Obj-C puts the declaration in the header (which is public) the above is a good guess as to where the custom getter logic is performed - when compiling the call site.
From your experiment we can infer that dot syntax is interpreted as follows:
is there a property with this name? If so, does it have a specified getter / setter name? if so, let's call that method.
otherwise, make up an appropriate method name (direct if we're getting, setXX if we're setting) and throw that at the receiver.
You can, for example, try to use .count against an NSArray instance. Before the abomination police kick in your doors, you may have time to see that it works.
To actually answer your question, in my mind dot notation should only be used to access properties, and in that case you should use the property name as declared in the interface. So .on for a UISwitch. I don't know why the getter name isn't given in the synthesize statement instead of the property declaration, it seems to belong in implementation rather than interface to me.
Well concerning dot notation, let me cite Aaron Hillegass (Cocoa Programming for Mac OSX, 3rd. Ed):
"Overall, I think that this is a rather silly addition to the language since we already had a syntax for sending messages."
When you have a member variable on, and your getter for this variable is called isOn then .on and .isOn are two very different kind of things. By using the getter (and probably a setter, too) you will adhere to the "information hiding" promise, whereas by using direct access to the member variables you won't. Cocoa won't enforce those things as it is relying on conventions. It's up to you to decide which way is right for you. Considering convention, you would have to stick to setters and getters - no matter what names you give them, though.
Property declarations are merely shorthand for regular method declarations. E.g.:
#property int color;
#property (getter=isOn) BOOL on;
becomes these method declarations:
- (int)color;
- (void)setColor:(int)value;
- (BOOL)isOn;
- (void)setOn:(BOOL)on;
You can call these methods just like any other method:
[foo color];
[foo isOn];
Likewise, dot notation is merely informal shorthand for calling plain old methods. For example:
x = #"Hello".length;
x = foo.on;
x = foo.isOn;
becomes
x = [#"Hello" length];
x = [foo isOn];
x = [foo isOn];
Note that #"Hello".length works even though NSString does not actually declare a property named "length". By default, foo.bar always expands to [foo bar] unless bar has been declared a property with a custom getter. If bar happens to be the name of a valid method then it will work without error.
Likewise, in your example foo.isOn works even though you don't actually declare a property named "isOn". Rather "isOn" is the name of a method that just happens to be the getter method for your "on" property.
So, while foo.isOn may work, it's considered bad form because isOn is not actually the name of the property.
What you cannot do is this:
x = [foo on]; // Error
because you never declare an on method.
I'm trying to get some code going that lets me display raw trackpad data from my macbook pro, like the app FingerMgmt. Unfortunately, no one seems to have the source for FingerMgmt. I did find some other source code that kind of works, however. I was able to NSLog the data I wanted to see like this:
int callback(int device, Finger *data, int nFingers, double timestamp, int frame) {
for (int i=0; i<nFingers; i++) {
Finger *f = &data[i];
NSLog(#"Frame %7d: Angle %6.2f, ellipse %6.3f x%6.3f; "
"position (%6.3f,%6.3f) vel (%6.3f,%6.3f) "
"ID %d, state %d [%d %d?] size %6.3f, %6.3f?\n",
f->frame,
f->angle * 90 / atan2(1,0),
f->majorAxis,
f->minorAxis,
f->normalized.pos.x,
f->normalized.pos.y,
f->normalized.vel.x,
f->normalized.vel.y,
f->identifier, f->state, f->foo3, f->foo4,
f->size, f->unk2);
//todo-get data from raw C to obj-C variable
}
return 0;
}
But whenever I try to store any of the data to an Obj-c string or variable, the C code does not see the variable as having been declared. Because of this, I cannot write to any text fields or graphical displays in Obj-C, and I cannot store the data to a variable that Obj-c can access.
Basically, I need a way to write to an Obj-C variable or object from within the callback.
On a side note, I had a very similar problem with an iPhone app a while back, and I ended up fixing it by somehow declaring the app delegate within the C code and writing to or reading from the variable like this-
me.delegate=(id <UIApplicationDelegate,UITabBarControllerDelegate>)[[UIApplication sharedApplication] delegate];//allows access to the delegate within C function
me.delegate.number0=5;//writes to this variable in the delegate
For some reason, I can not seem to adapt this to my current situation. I always get the error that "me" is undeclared.
A Objective-C method can access instance variables because it is automagically passed a hidden parameter with the public name self - any reference to an instance variable, say fred, is translated by the compiler into a field reference, say self->fred (and a similar translation for property references).
For your C function callback to access the fields of any object (or call an object's methods) you need to pass the function a reference to the object. Two simple ways:
Add an argument to the function. Many C callback protocols include a general "user defined" values which is passed around as void *, if you are calling one of these pass your object reference as this value and cast it within the C function back to the correct Objective-C type.
Pass the object via a global (or file static) variable, e.g. static NSSomeType *objectForCallback;. This method works when you're stuck with an existing C callback protocol which doesn't support a user defined value. However it is not thread or re-entrant safe as you are sharing a single static variable.
In both cases make sure the objected is retain'ed if you're not using garbage collection.
In response to comment
Case 1: You will see C functions declared which (a) take a callback function and (b) a user-defined value to pass to that function on every call. For example:
typedef T ...;
T findMatching(T *buffer, // an array of T to search
size_t count, // number of items in array
int (*matcher)(T item, void *user), // user function for match, 1st arg is item, 2nd user-supplied value
void *userValue); // user-supplied value to pass to matcher
If you are faced with C function like this you can pass a (retain'ed if needed) Objective-C object as userValue and cast it back to its Objective-C type inside matcher. For example:
int myMatcher(T item, void *user)
{
NSMutableDictionary *myDictionary = (NSMutableDictionary *)user;
...
}
- (void) someMethod
{
NSMutableDictionary *sharedWithC = ...;
...
T found = findMatching(buffer, count, myMatcher, (void *)sharedWithC);
...
}
Case 2: Objective-C is (a superset of) C. You declare a global just as you would in C. For example (little checking, not thread safe):
static NSMutableDictionary *myGlobalDictionary = nil; // "static" makes the variable only visible to code in the same file
- (void) setupTheSharedDictionary
{
myGlobalDictionary = [[[NSMutableDictionary alloc] init] retain];
}
- (void) releaseTheSharedDictionary
{
if(myGlobalDictionary != nil)
{
[myGlobalDictionary release];
myGlobalDictionary = nil;
}
}
In response to second comment
I'm guessing you are trying to use some third party (Google?) code. That code defines a callback protocol - a C function type. You cannot just redefine that C function type adding an extra argument and expect the third party code to magically cope!
So unless you intend to change the C you can use the second approach - store the reference to Objective-C object in a global. In your case this will be something like:
static MT2AppDelegate *sharedWithCAppDelegateReference;
int callback(...)
{
...
[sharedWithCAppDelegateReference->L1 setStringValue:#"Hellofff"];
...
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
sharedWithCAppDelegateReference = self; // store so C can pick it up
...
MTRegisterContactFrameCallback(dev, callback);
...
}
But remember this is not thread or re-entrant safe - you are effectively passing a function parameter via a global variable. If you need it to be thread/re-entrant safe you need to get a bit more involved.
Can someone confirm that you cannot access instance variables defined in an Objective C #implementation block from within C style functions of the same class? The compiler is throwing errors saying "XXX undeclared' where XXX is the instance variable name.
Here's an example of what I am explaining:
#interface FontManager : NSObject {
CGFontRef fontRef;
}
static int CstyleFunction() {
NSUInteger emSize = CGFontGetUnitsPerEm(fontRef);
}
I want to verify that I cannot use "fontRef" from withing "CstyleFunction".
Any insight would be greatly appreciated.
A "C style method" doesn't really deserve the name "method", I'd call it a "function" instead as in C.
A C function has no self, so it cannot implicitly access ivars as a method can. If you pass an instance to the C function as a parameter, you can access ivars in the same manner you would access a field in a struct pointer.
#Anomie and #jlehr are correct, the C function has no concept of the FontManager object and its current state, it just happens to live in the same file.
However, if FontManager is a singleton and you make fontRef a property (or create an accessor for it), then it would be possible to access the value within your C class:
static int CstyleMethod() {
FontManager *fm = [FontManager sharedManager];
NSUInteger emSize = CGFontGetUnitsPerEm(fm.fontRef);
}
Bottom line, you can mix-and-match C and ObjC syntax within C functions & ObjC methods. But because C functions have no default reference to self (and the object's associated instance variables), you can only reference ObjC objects that are singletons, stored in a global variable, or passed in as parameters.
That's correct. You seem to be mixing up methods and functions though. Methods exist only in Objective-C. What you're referring to as a 'C style method' is really just a C function.
C is not an object-oriented programming language. Since there's no such thing as an object in C, there's also no such thing as an instance variable in C, so the fontRef instance variable would not be visible in the function you posted, nor for that matter in any other C function in your program.