I have an Obj-C object with a bunch of methods inside of it. Sometimes a method needs to call another method inside the same object. I can't seem to figure out how to get a C method to call a Obj-C method...
WORKS: Obj-C method calling an Obj-C method:
[self objCMethod];
WORKS: Obj-C method calling a C method:
cMethod();
DOESN'T WORK: C method calling an Obj-C method:
[self objCMethod]; // <--- this does not work
The last example causes the compiler spits out this error:
error: 'self' undeclared (first use in this function)
Two questions. Why can't the C function see the "self" variable even though it's inside of the "self" object, and how do I call it without causing the error? Much thanks for any help! :)
In order for that to work, you should define the C method like this:
void cMethod(id param);
and when you call it, call it like this:
cMethod(self);
then, you would be able to write:
[param objcMethod];
In your cMethod.
This is because the self variable is a special parameter passed to Objective-C methods automatically. Since C methods don't enjoy this privilege, if you want to use self you have to send it yourself.
See more in the Method Implementation section of the programming guide.
I know your question is already answered by Aviad but just to add to the info since this is not unrelated:
In my case I needed to call an Objective-C method from a C function that I did not call myself (a Carbon Event function triggered by registering a global hotkey event) so passing self as a parameter was impossible. In this particular case you can do this:
Define a class variable in your implementation:
id thisClass;
Then in your init method, set it to self:
thisClass = self;
You can then call Objective-C methods from any C function in the class without the need to pass self as a parameter to the function:
void cMethod([some parameters]) {
[thisClass thisIsAnObjCMethod];
}
C function is not "inside of the self object". In fact, nothing is.
Objective-C methods effectively get self as an implicit argument, with magic done under the hood. For plain C functions, they aren't associated with any class or object, and there's no call magic, so no self. If you need it, you need to pass it to your C function explicitly as an argument.
To be totally truthful, there is no such thing as a C method. C has functions. To illustrate the difference, look at the following examples:
This is a working C program that defines a type and two functions that go along with it:
#include <stdio.h>
typedef struct foo_t {
int age;
char *name;
} Foo;
void multiply_age_by_factor(int factor, Foo *f) {
f->age = f->age * factor;
}
void print_foo_description(Foo f) {
printf("age: %i, name: %s\n", f.age, f.name);
}
int main() {
Foo jon;
jon.age = 17;
jon.name = "Jon Sterling";
print_foo_description(jon);
multiply_age_by_factor(2, &jon);
print_foo_description(jon);
return 0;
}
Here is an Objective-C implementation of that program:
#import <Foundation/Foundation.h>
#interface Foo : NSObject {
NSUInteger age;
NSString *name;
}
#property (nonatomic, readwrite) NSUInteger age;
#property (nonatomic, copy) NSString *name;
- (void)multiplyAgeByFactor:(NSUInteger)factor;
- (NSString *)description;
- (void)logDescription;
#end
#implementation Foo
#synthesize age;
#synthesize name;
- (void)multiplyAgeByFactor:(NSUInteger)factor {
[self setAge:([self age] * factor)];
}
- (NSString *)description {
return [NSString stringWithFormat:#"age: %i, name: %#\n", [self age], [self name]];
}
- (void)logDescription {
NSLog(#"%#",[self description]);
}
#end
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Foo *jon = [[[Foo alloc] init] autorelease];
[jon setAge:17];
[jon setName:#"Jon Sterling"];
[jon logDescription];
[jon multiplyAgeByFactor:2];
[jon logDescription];
[pool drain];
return 0;
}
The output of the pure C program was:
age: 17, name: Jon Sterling
age: 34, name: Jon Sterling
The output of the Objective-C program was:
2009-08-25 17:40:52.818 test[8963:613] age: 17, name: Jon Sterling
2009-08-25 17:40:52.828 test[8963:613] age: 34, name: Jon Sterling
The only difference is all the junk that NSLog puts before the text. The functionality is exactly the same. So, in C, you can use something sort of like methods, but they are really just functions that include a pointer to a struct.
I don't think this answered your original question, but it did clear up some terminology issues you appear to have been having.
Another option to the answers given thus far is to use the objc_msgSend() function provided by the Objective-C runtime.
Related
I have the definition:
#interface MyClass: NSObject
{
NSString *str;
id delegate;
}
-(id)initWithStr:(NSString *)str
delegate:(id)delegate;
#end
and when i send message to my object in the main.m like this:
int main(int argc, const char * argv[])
{
#autoreleasepool {
[[MyClass alloc] initWithStr:#"abc-xyz"
delegate:self];
}
}
There is the error "Use of undeclared identifier 'self' ". I m a newb of objective-c and I know that the 'self' indicates the receiver of the message, but i don't know how to use it in the main() function. Can anybody tell me what's wrong about it and how to fix it?
What happens is that self points to the executing object. main function is not in a class, so, YOU CAN`T call self on a function, only on a method of a class. What are you really trying to do? Use the AppDelegate. When you create a new project, Xcode already gives you some files. One of then is called (YOUR_PROJECT)AppDelegate. This is the starting point of your application.
If you have any customizations to do in the initialization of your app, find your AppDelegate.m file, look for - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions method, and place your code inside this method.
Never mess up with main.m file.
EDIT:
For Mac OS X here's what you should do:
Create a class to act as a delegate and add that class to the delegate.
MyDelegate * d;
MyClass * c;
int main(int argc, const char * argv[])
{
#autoreleasepool {
d = [[MyDelegate alloc] init];
c = [[MyClass alloc] initWithStr:#"abc-xyz"
delegate:d];
}
}
Then, on MyDelegate, implement the callbacks of the protocol.
If you want to have a callback on main, you will have to use a function pointer. You'll have to enter in the world of plain C. I don't recommend since you want to use object oriented stuff. Don't mix both, or you'll create a monster.
You do not use the main() function like this.
Do this in the AppDelegate, then it will just work.
In Objective-C, how to use 'self' in main() function?
This is impossible.
Because "self" can only be used by instances of objects.
main() is a function. Functions are not objects but code "on its own".
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];
I would like to add functions by creating a category for Objective-C Blocks.
__block int (^aBlock)(int) = ^int( int n ){
if( n <= 1 ) return n;
return aBlock( n - 1 ) + aBlock( n - 2 );
};
Instead of just allowing the normal [aBlock copy], [aBlock retain], [aBlock release], [aBlock autorelease]. I could do thing like:
[aBlock mapTo:anArray];
Possible Category
#interface UnknownBlockClass (map)
- (NSArray *)mapTo:(NSArray *)array_;
#end
#pwc is correct in that you can't create a category for a class that you can't see.
However...
WHAT I AM ABOUT TO TELL YOU SHOULD BE USED STRICTLY AS AN EXERCISE IN LEARNING, AND NEVER IN ANY SORT OF PRODUCTION SETTING.
Some runtime introspection reveals some interesting information. There are a number of classes that contain the word "Block". Some of them look promising: __NSStackBlock, __NSMallocBlock, __NSAutoBlock, and NSBlock.
Some more introspection shows that the promising classes inherit from NSBlock
So it looks like any block is going to be some instance or subclass of NSBlock.
You can create a method on an object, like so:
#implementation Foo
- (void) doFoo {
//do something awesome with self, a block
//however, you can't do "self()".
//You'll have to cast it to a block-type variable and use that
}
#end
Then at runtime, you can move that method to the NSBlock class:
Method m = class_getInstanceMethod([Foo class], #selector(doFoo));
IMP doFoo = method_getImplementation(m);
const char *type = method_getTypeEncoding(m);
Class nsblock = NSClassFromString(#"NSBlock");
class_addMethod(nsblock, #selector(doFoo), doFoo, type);
After this, blocks should respond to the doFoo message.
USE AT YOUR OWN RISK, AND ONLY FOR EXPERIMENTING.
A block winds up being an instance of type __NSGlobalBlock__, as seen in the following snippet:
void (^aBlock)(void) = ^(void) {
NSLog(#"Hello world");
};
// prints "type = __NSGlobalBlock__"
NSLog(#"type = %#", [aBlock class]);
In order to create a category of a class, the compiler needs to be able to see the original #interface declaration of the class. I can't find the declaration for __NSGlobalBlock__ and probably for good reason.
This article and this article contain some useful information about the implementation of blocks.
To your original point, why not just make a category of NSArray for your mapTo method? It seems like a better place for that sort of functionality.
Updated
Let's say you can add a category to the Block object. How would you invoke the block from the category's method? To the best of my understanding, the only way to invoke a block is via the () operator (e.g., aBlock()). I don't think there's a way to tell from the Block object the number and types of parameters. So, what arguments would you pass in to the block invocation?
I'm not recommending you do this, but the following works...
#interface NSObject (BlockExtension)
- (void)foo;
#end
#implementation NSObject (BlockExtension)
- (void)foo
{
// not sure how else to determine if self is a Block since neither
// __NSGlobalBlock__ nor any of its superclasses (except NSObject)
// are accessible to the compiler
if ([[[self class] description] isEqual:#"__NSGlobalBlock__"])
{
NSLog(#"foo");
// now what?
// can't call self(), it doesn't compile
// how else can I invoke this block?
}
}
#end
...
void (^aBlock)(void) = ^(void) {
NSLog(#"Hello world");
};
// prints "foo"
[aBlock foo];
Dave DeLong is right, you cannot add a category on a class that you cannot see, but as blocks are subclasses of NSBlock adding:
#interface NSBlock : NSObject
#end
Now you can 'see' NSBlock and add a category on it, e.g.:
#interface NSBlock (map)
- (NSArray *)mapTo:(NSArray *)array;
#end
#implementation NSBlock (map)
- (NSArray *)mapTo:(NSArray *)array
{
...
}
#end
Still probably not the best thing to do in code that is actually used in production...
WRONG: A block winds up being an instance of type __NSGlobalBlock__, as seen in the
following snippet:
int i = 0;
id o = [class self];
void (^aBlock)(void) = ^(void) {
[o setValue:0];
NSLog(#"Hello world %d", i);
};
// prints "type = __NSGlobalBlock__"
// Now it prints __NSStackBlock__
// and when moved into HEAP prints __NSMallocBlock__
NSLog(#"type = %#", [aBlock class]);
It is only OKAY to say that a block winds up being an instance of type "NSGlobalBlock" unless there are no captured variables in the scope, otherwise it will be created in the STACK and when it is copied that will move the block into HEAP and every reference will be retained!
The simple answer is no. A __block variable is a C level object not an Objective C object. You can call [aBlock copy] but this invokes a C function block_copy() not the nsobject copy method. So the __block type is a C type and therefore you can't add categories.
correction:__block is an identifier in the C compiler not a typedef.
I'm not sure if this will achieve what you think it will, infact I'm not even quite sure what it does:
__block int (^aBlock)(int) = ^int( int n ){
if( n <= 1 ) return n;
return fib( n - 1 ) + fib( n - 2 );
};
the __block identifier tells the complier that the variable should be mutable in referencing blocks and should be preserved if any referencing block is copied to the heap. what confuses me about your code is that __block is usually used to wrap a variable, not a block itself.
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.
I have to call an objective C method from a cpp Function.
I have a class C, whose object address is required in this function. I did come across another link which guided me on how to have a reference to the class C, and use it for invocation from the cpp function.
In my case, there is one small difference in that the Class C is already instantiated, and I would not want to allocate an object again. So how can I get its object address?
The code looks like this:
C.h
import Cocoa/Cocoa.h
id refToC
#interface C: NSObject
{
;
somemethod;
;
}
#end
C.m
#implementation C
- (void) somemethod
{
;
;
}
#end
B.mm
import C.h
void func()
{
//I need the address of object here, so as to invoke:
[refToC somemethod];
}
Thanks in Advance
~ps7
The id type is already a pointer to an object. Once you have created a valid object, e.g.:
refToC = [[C alloc] init]
The easiest way is to make use of the singleton design pattern. Here's a common way to make use of that pattern in Objective-C:
Widget.h
#interface Widget : NSObject {
// ...
}
// ...
- (void)someMethod;
+ (Widget *)sharedWidget;
#end
Widget.m
#implementation Widget
// ...
+ (Widget *)sharedWidget {
static Widget *instance;
#synchronized (self) {
if (!instance)
instance = [[Widget alloc] init];
}
return instance;
}
#end
CppWrapper.mm
void methodWrapper() {
[[Widget sharedWidget] someMethod];
}
Thanks a lot for your pointers. I had missed telling that the class C is a controller class. I tried assigning refToC to self in awakeFromNib, and the invocation in func() worked like a charm.
Thanks Matt and John for your pointers.
~ ps7