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.
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.
Are there any Objective-C runtime functions that will allow me to get a function (or block) pointer from a string identifying the function? I need some way to dynamically find and invoke a function or static method based on some form of string identifying it.
Ideally this function should be able to exist in any dynamically loaded library.
Looking at Objective-C Runtime Reference, the best bet looks like class_getClassMethod, but there don't appear to be any function-related functions in this reference. Are there other raw C ways of getting a pointer to a function by name?
if you want to invoke some static objc method, you can make it as a class method of a class
#interface MyClas : NSObject
+ (int)doWork;
#end
and call the method by
[[MyClass class] performSelector:NSSelectorFromString(#"doWork")];
if you real want to work with C-style function pointer, you can check dlsym()
dlsym() returns the address of the code or data location specified by
the null-terminated character
string symbol. Which libraries and bundles are searched depends on the handle
parameter If dlsym() is called with the special handle RTLD_DEFAULT,
then all mach-o images in the process
(except those loaded with dlopen(xxx, RTLD_LOCAL)) are searched in the order they were loaded. This
can be a costly search and should be avoided.
so you can use it to find the function pointer base on asymbol name
not sure why you want to do this, sometimes use function table can do
typedef struct {
char *name,
void *fptr // function pointer
} FuncEntry;
FuncEntry table[] = {
{"method", method},
{"method2", method2},
}
// search the table and compare the name to locate function, you get the idea
If you know method signature you can create selector to it with NSSelectorFromString function, e.g.:
SEL selector = NSSelectorFromString(#"doWork");
[worker performSelector:selector];
You may be able to do what you want with libffi. But unless you are doing something like create your own scripting language or something like that where you need to do this sort of thing a lot. It is probable overkill
I've wondered the SAME thing.. and I guess, after having researched it a bit.. there is NOT a "standard C" way to do such a thing.. (gasp).. but to the rescue? Objective C blocks!
An anonymous function.. that can be OUTSIDE any #implementation, etc...
void doCFunction() { printf("You called me by Name!"); }
Then, in your objective-C method… you can somehow "get" the name, and "call" the function...
NSDictionary *functionDict = #{ #"aName" : ^{ doCFunction(); } };
NSString *theName = #"aName";
((void (^)()) functionDict[theName] )();
Result: You called me by Name!
Loves it! 👓 ⌘ 🐻
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.
Just when I think I'm getting comfortable with Objective-c the mentioned symbols totally throw me down a rabbit hole...
** a double pointer??
& what sort of things can I do with &reference, is a #property? a full on object? weird pointer razzledazzle?
± I see both a + or a - before method declarations; I've seen Java annotate some datatype declarations by manually typing the + and the magic of compiling in Eclipse would change them to a -
I'm likely asking repetitious questions and/or way outta the ballpark on my guesses; thanks for answers/edits.
You're getting into the C portion that objective-c is built on top of.
** is a pointer to a pointer. Since functions in C take arguments by value, it means you can't change the value of the argument in that function. But, by providing a level of indirection and passing a pointer to the pointer, you can change the value.
& means it's a reference. If an argument takes a ** and you have a * variable, pass a reference to it.
Foo *foo;
[self changeFoo: &foo];
- (BOOL)changeFoo: (Foo **)foo
{
// dereference the double pointer and assign a val = alloc init returns a *
*foo = [[Foo alloc] init];
return YES;
}
A common usage in objective-c / cocoa is NSError. It's essentially an out argument.
NSError *err;
BOOL success = [self doSomething:#"Foo" error:&err];
- (BOOL)doSomething:(NSString*)withData error:(NSError**)error
{
}
As you might know, a pointer points to the address of an object and is the way you reference an object. A double pointer is sometimes used in Objective-C, mainly for returning NSErrors, where you want to get back the address, i.e. a pointer, to an error object (NSError) if an error occurred, thus you pass in a pointer assigned to null and the caller can change that pointer so that it points to the address of another pointer which in turn points to an NSError object.
The ampersand (&) is mostly used by the lower level C APIs, e.g. Core Graphics. They are used to reference things, like the current context. As long as most of your code uses square brackets around its method calls you won't see these very often.
Using a + or a - before a method declarations is used to differentiate between class (+) and instance (-) methods. A class methods is called on the class itself (such as alloc), while a instance method is called on an instance of that object (such as init).
- and + before a method declaration designate an instance method and a static class method. To use an instance method you have to create an object of your class before you can call its method, a static method can be called directly from a class type
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.