Can I boost::bind() to an Objective C function? - objective-c

I have no idea if this is possible, but if it is, what would the syntax look like?
If not possible, why not?

You should be able to bind to a message implementation (IMP), which are just plain C functions with two hidden parameters, self and _cmd of types id and SEL respectively.
EDIT: Just tested the following complete example, and it appears to work.
#include <stdio.h>
#include <boost/bind.hpp>
#include <Foundation/NSObject.h>
#interface MyClass : NSObject
{
}
-(int) doSomething:(int)arg;
#end
#implementation MyClass
-(int) doSomething:(int)arg
{
printf("doSomething: self=0x%08x _cmd=0x%08x\n", self, _cmd);
return arg + 1;
}
#end
int main(void)
{
MyClass *myObj = [[MyClass alloc] init], *otherObj = [[MyClass alloc] init];
typedef int (*MyFunc)(id, SEL, int);
SEL doSomething_sel = #selector(doSomething:);
MyFunc doSomething_impl = (MyFunc)[myObj methodForSelector:doSomething_sel];
// bind self & _cmd arguments:
// calls [myObj doSomething:x]
int result = boost::bind(doSomething_impl, myObj, doSomething_sel, _1)(14);
printf("result1: %d\n", result);
// bind _cmd & arg:
// calls [otherObj doSomething:3]
result = boost::bind(doSomething_impl, _1, doSomething_sel, 42)(otherObj);
printf("result2: %d\n", result);
return 0;
}
With GNUstep, compile as:
gcc objcbind.mm -o objcbind -I/usr/include/GNUstep -lobjc -lstdc++ -lgnustep-base
On Mac OS X, compile as:
gcc objcbind.mm -o objcbind -framework Foundation -lstdc++
Output:
doSomething: self=0x01a85f70 _cmd=0x00602220
result1: 15
doSomething: self=0x01a83d70 _cmd=0x00602220
result2: 43

Related

Are argument types optional for methods?

I came across this unusual bit of Objective-C today which, to my suprise, compiles without fail and outputs "hi":
#include <Foundation/Foundation.h>
#interface MyObject : NSObject
- (NSString *)method:param;
#end
#implementation MyObject
- (NSString *)method:param
{
return param;
}
#end
int main() {
MyObject * m = [MyObject new];
NSLog(#"%#", [m method:#"hi"]);
return 0;
}
Compile command:
# clang version: clang-900.0.37
clang test.m -fobjc-arc -o test
method has a single argument, param, but I did not explicitly give a type. I can't seem to find any documentation on this? What's going on?
I've been unable to find any official docs on this, but in my testing this is indistinguishable from the param being a generic id type.

GCC Undefined Reference to xxx

I'm making a simple test to see if I can run Objective-C on Linux without GNUStep, so I followed an example here on SO to get it running, here's my code:
//WSObject.h
#include <objc/runtime.h>
#include <stdio.h>
#interface WSObject
+ (id) alloc;
- (void) dealloc;
- (void) hello;
#end
//WSObject.m
#include "WSObject.h"
#implementation WSObject
+ (id) alloc {
return class_createInstance(self, 0);
}
+ (void) dealloc {
object_dispose(self);
}
+ (void) hello {
puts("Hello, world");
}
#end
//test.m
#include "WSObject.h"
int main(int argc, const char *argv[]) {
WSObject *obj = [WSObject alloc];
[obj hello];
[obj dealloc];
return 0;
}
When I then try to compile it with gcc test.m -o test -lobjc
I get the following error:
/tmp/ccDzvsol.o:(.data+0x80): undefined reference to `__objc_class_name_WSObject'
collect2: error: ld returned 1 exit status
Any help?

GNU runtime: class_createInstance return makes pointer from integer without a cast

I am trying to make a new Objective-C root class on the GNU runtime. Here is what I have so far:
foo.h:
#include <objc/objc.h>
#interface Foo {
Class isa;
int bar;
}
+ (id) alloc;
+ (id) newWithBar: (int) bar;
- (id) initWithBar: (int) bar;
- (void) p;
- (void) dispose;
#end
foo.m:
#import <foo.h>
#include <stdio.h>
#implementation Foo
+ (id) alloc {
return class_createInstance(self, 0);
}
+ (id) newWithBar: (int) bar {
return [[self alloc] initWithBar: bar];
}
- (id) initWithBar: (int) bar_ {
bar = bar_;
}
- (void) p {
printf ("bar=%d\n", self->bar);
}
- (void) dispose {
object_dispose(self);
}
#end
and a little test program, main.m:
#import <foo.h>
int main(int argc, char *argv[]) {
Foo *foo = [Foo newWithBar: 3];
[foo p];
[foo dispose];
return 0;
}
When I compile foo.m, I get the following warning:
foo.m: In function ‘+[Foo alloc]’:
foo.m:7:3: warning: return makes pointer from integer without a cast [enabled by default]
Why? When I dive into the header files, I can see that class_createInstance returns id. What am I doing wrong here?
You need to include the header for the objective C runtime. The default behaviour of the compiler is to assume undeclared functions return an int.
#include <objc-auto.h>
Sorry - answer above is for OS X/iOS. For GNU you need to include runtime.h as well as objc.h
#include <objc/runtime.h>

How to run a simple objective-c in linux

EDITED
I have been trying to start coding in Objective-c. Its just a simple program to try getter and setter methods. Also print Hello World. THe following is my code:
#import <objc/Object.h>
#interface Car:Object{
int wheel: 5;
}
- (int)wheel;
- (void)setWheel: (int)newWheel;
#end
#include <stdio.h>
#implementation Car
- (int)wheel{
return wheel;
}
- (void)setWheel: (int)newWheel{
wheel = newWheel;
}
#end
#include <stdlib.h>
int main(void){
printf("Hello World");
}
I now get garbage
/tmp/cc3UC6jY.o: In function `__objc_gnu_init':
hello.m:(.text+0x6d): undefined reference to `__objc_exec_class'
/tmp/cc3UC6jY.o:(.data+0x1c0): undefined reference to `__objc_class_name_Object'
collect2: error: ld returned 1 exit status
I used the the command gcc -o hello hello.m -lobjc
I have spent hours googling this answer.
The following variation of your code compiled and ran for me:
#import <objc/Object.h>
#interface Car : Object {
int wheel;
}
- (int)wheel;
- (void)setWheel: (int)newWheel;
#end
#implementation Car
- init {
wheel = 5;
return self;
}
- (int)wheel {
return wheel;
}
- (void)setWheel: (int) newWheel {
wheel = newWheel;
}
#end
#include <stdio.h>
int main(void){
printf("Hello World\n");
id myCar = [[Car alloc] init];
printf("Wheel value is %d\n", [myCar wheel]);
return 0;
}

Compiling objective-c programs without gnustep on ubuntu

is there any way to compile objective c programs on ubuntu without the use of GNUStep? I want to use the default C standard libraries and all but with Objective-C's OOB syntax. The problem I am having now is once I have all the methods up, I need a way to call them. In Mac I would just alloc and init it but on Linux when I try to compile this, clang just gives me an error.
#include <stdio.h> // C standard IO library (for printf)
#include <stdlib.h> // C standard library
// Interface
#interface test
-(void)sayHello :(char *)message;
#end
// Implementation
#implementation test
-(void)sayHello :(char *)message {
printf("%s", message);
}
int main(int argc, char *argv[]) {
test *test = [[test alloc] init];
[test sayHello:"Hello world"];
}
You can compile objective-c with gcc, but remember to use the -lobjc switch so the compiler knows what language you're using.
You'll also need to include the following header:
#import <objc/Object.h>
...and extend Object from your interface. See the hello world example for objective-c here:
http://en.m.wikipedia.org/wiki/List_of_Hello_world_program_examples#O
Good question - it got me to dig into the matters myself, since I want to rewrite several old Python projects in a normal language (C/ObjC), so I aim both to stay away from Crap++ and avoid GNUstep overhead. Here goes my try-and-test solution:
Foo.h:
#import <objc/Object.h>
#interface Foo: Object
{
#private
int
bar;
}
+ (id) alloc;
+ (id) new;
- (id) init;
- (id) set_bar: (int)value;
- (int) get_bar;
#end
Foo.m:
#import <stdio.h>
#import <objc/runtime.h>
#import "Foo.h"
#implementation Foo
+ (id) alloc
{
puts(__func__);
return class_createInstance(self, 0);
}
+ (id) new
{
return [[self alloc] init];
}
- (id) init
{
puts(__func__);
bar = 31;
return self;
}
- (id) set_bar: (int)value
{
puts(__func__);
bar = value;
return self;
}
- (int) get_bar
{
puts(__func__);
return bar;
}
#end
main.m:
#import <stdio.h>
#import "Foo.h"
int
main
()
{
id
foo = [Foo new];
printf("old bar: %i\n", [foo get_bar]);
[foo set_bar: 10];
printf("new bar: %i\n", [foo get_bar]);
return 0;
}
Makefile:
run: main.o Foo.o
gcc $^ -o $# -lobjc
main.o: main.m Foo.h
gcc -c $< -o $#
Foo.o: Foo.m Foo.h
gcc -c $< -o $#
The output I've got:
+[Foo alloc]
-[Foo init]
-[Foo get_bar]
old bar: 31
-[Foo set:bar:]
-[Foo get_bar]
new bar: 10
Looks like it works!