Objective C - Call Method defined from a Macro - objective-c

I'm trying to call a Method from Objective-C that has been defined using a Macro which wraps a Swift function. I'm getting the compilation error No visible #interface for 'NearbyMessages' declares the selector '__rct_export__disconnect' in Xcode when I try to call my Method though.
My Swift function looks like this:
// SomeInterface.swift
#objc
func disconnect() -> Void {
// (disconnect logic here)
}
The Objective-C code looks like this:
// SomeInterface.m
#interface RCT_EXTERN_REMAP_MODULE(SomeInterfaceNameJS, SomeInterfaceNamePrivate, NSObject)
RCT_EXTERN_METHOD(disconnect);
-(void) invalidate {
[self __rct_export__disconnect]; // No visible #interface for 'NearbyMessages' declares the selector '__rct_export__disconnect'
NSLog(#"GNM_BLE: invalidate!");
}
#end
The macro RCT_EXTERN_METHOD (from React's RCTBridgeModule.h) is defined as:
#define RCT_EXTERN_METHOD(method) \
_RCT_EXTERN_REMAP_METHOD(, method, NO)
#define _RCT_EXTERN_REMAP_METHOD(js_name, method, is_blocking_synchronous_method) \
+ (const RCTMethodInfo *)RCT_CONCAT(__rct_export__, RCT_CONCAT(js_name, RCT_CONCAT(__LINE__, __COUNTER__))) { \
static RCTMethodInfo config = {#js_name, #method, is_blocking_synchronous_method}; \
return &config; \
}
By reading this, upon compilation the Method should be called __rct_export__disconnect, right?
So why is it not possible to use [self __rct_export__disconnect] - How else can I call this method?

TL;DR: To answer the question, call [self.class __rct_export__disconnect];. But it is better (and an only future-proof way in case the __rct_export__ prefix changes in the next versions of React Native) is to call the disconnect() function directly.
Objective-C allows having two main types of methods.
First type is the instance method, which operates on an instance of the Objective-C class. In the body of this method, self is a pointer to the instance of the object on the heap, hence the name. Through the self pointer you can access other instance methods, instance variables etc. It is declared/defined with a minus (-) sign in the beginning.
Second type is the class method, which operates on class objects (a specific Obj-C construct). It is most commonly used when you'd use a static function in other languages (with some caveats and quirks related to inheritance of course). In the body of this method, self is a pointer to the class object. Through it you can call other class methods, but you don't have access to any concrete instances of the object.
The difference is explained well here.
In your case, this macro defines a class method:
#define _RCT_EXTERN_REMAP_METHOD(js_name, method, is_blocking_synchronous_method) \
+ (const RCTMethodInfo *)RCT_CONCAT(__rct_export__, RCT_CONCAT(js_name, RCT_CONCAT(__LINE__, __COUNTER__))) { \
static RCTMethodInfo config = {#js_name, #method, is_blocking_synchronous_method}; \
return &config; \
}
And this method is an instance method:
- (void)invalidate {
[self __rct_export__disconnect]; // No visible #interface for 'NearbyMessages' declares the selector '__rct_export__disconnect'
NSLog(#"GNM_BLE: invalidate!");
}
When you call [self __rct_export__disconnect];] from the instance method, the self points to the instance of your class. The __rct_export__disconnect is defined as a class method (see macro), and thus it is not defined on the instances of the object.

Related

Is it possible for a class to have a member function?

I've currently got some code as follows:
static void callback(several parameters)
{
...
}
#implementation SomeClass
- (id) init
{
self = [super init];
if (self)
{
id ct = CTTelephonyCenterGetDefault();
CTTelephonyCenterAddObserver((__bridge CFNotificationCenterRef)(ct), NULL, callback, NULL, NULL, CFNotificationSuspensionBehaviorHold);
....
Within the callback function's body I want to update some values, and I'd rather add them as properties of SomeClass rather than be global variables.
So is it possible to make the callback function a member function of SomeClass?
If you're using a C API that takes a callback and you want one of your class's instance methods to be called, you have to use a C function as a trampoline. Along with the callback function, most such C APIs allow you to specify a user value that gets passed back as an argument to callback. You should pass the instance pointer as that user value. Then, your trampoline will just call an instance method on the object.
For example:
static void callback(void* userValue, /* other parameters... */)
{
MyClass* myObject = (__bridge MyClass*)userValue;
[myObject myMethod:/* other parameters passed along */];
}
You'll have to figure out if CTTelephonyCenterAddObserver() can take such a user value argument and which it is.
It doesn't much matter if callback() is declared inside or outside of the #implementation.
So is it possible to make the callback function a member function of
SomeClass
Not really. A method requires an object to act on. What you normally can do, depending on the API you're using, is to store a pointer to your SomeClass instance, and pass it as an additional parameter for the addObserver function.
Presumably one of the NULL arguments in your call to CTTelephonyCenterAddObserver is supposed to be additional context for the callback routine. You can convert a pointer to an object to a (void *) pointer when passing it to the CTTelephonyCenterAddObserver, and then convert it back to a (SomeClass *) inside the callback function.
UPDATE
See my comment below. My answer should not be the accepted answer.
Move callback inside your #implementation, like this:
#implementation
- (void)callback:(SomeType)parameter1 parameter2:(SomeOtherType)parameter2 {
// do stuff
}
...
#end
If you want your method to be public, you need to add it to your interface:
#interface
- (void)callback:(SomeType)parameter1 parameter2:(SomeOtherType)parameter2;
#end
Apple's Objective-C intro may help.

Pass instance method as function pointer to C Library

I am writing an Objective-C application that uses a C Library. The issue which i am currently facing is that the C Library has a structure where some field are function pointers later used as callbacks. How can i convert an Objective-C instance method to a function pointer and pass it to the library?
You will need to provide the C callback function within the Objective-C class implementation file, and this will only work if the callback is able to use a context pointer of some sort.
So imagine the C callback signature is like this:
void myCallback(void *context, int someOtherInfo);
Then within the Objective-C class implementation file you need to use that callback to trampoline back into your Objective-C class (using the context pointer as the instance of the class to invoke):
// Forward declaration of C callback function
static void theCallbackFunction(void *context, int someOtherInfo);
// Private Methods
#interface MyClass ()
- (void)_callbackWithInfo:(int)someOtherInfo;
#end
#implementation MyClass
- (void)methodToSetupCallback
{
// Call function to set the callback function, passing it a "context"
setCallbackFunction(theCallbackFunction, self);
...
}
- (void)_callbackWithInfo:(int)someOtherInfo
{
NSLog(#"Some info: %d", someOtherInfo);
}
#end
static void theCallbackFunction(void *context, int someOtherInfo)
{
MyClass *object = (MyClass *)context;
[object _callbackWithInfo:someOtherInfo];
}
If your C callback function does not accept some sort of context info, then:
It's broken and this should be fixed/reported as a bug.
You will need to rely on storing a pointer-to-self at global, static, scope to be used by the C callback function. This will limit the number of instances of MyClass to one!

How do I provide a default implementation for an Objective-C protocol?

I'd like to specify an Objective-C protocol with an optional routine. When the routine is not implemented by a class conforming to the protocol I'd like to use a default implementation in its place. Is there a place in the protocol itself where I can define this default implementation? If not, what is the best practice to reduce copying and pasting this default implementation all over the place?
Objective-C protocols have no affordance for default implementations. They are purely collections of method declarations that can be implemented by other classes. The standard practice in Objective-C is to test an object at runtime to see if it responds to the given selector before calling that method on it, using -[NSObject respondsToSelector:]. If e object does not respond to the given selector, the method isn't called.
One way you could achieve the result you're looking for would be to define a method encapsulating the default behavior you're looking for in the calling class, and call that method if the object doesn't pass the test.
Another approach would be to make the method be required in the protocol, and provide default implementations in the superclasses of any classes wherein you may not want to provide a specific implementation.
There are probably other options as well, but generally speaking there isn't a particular standard practice in Objective-C, except perhaps to just not call the given method if it hasn't been implement by the object, per my first paragraph, above.
There is no standard way for doing that as protocols should not define any implementations.
Since Objective-C comes with a neat runtime, you can of course add such a behavior if you really think you need to do it that way (and there's no possibility by achieving the same with inheritance).
Say you declared MyProtocol, then just add an interface with the same name in the .h file under your protocol declaration:
#interface MyProtocol : NSObject <MyProtocol>
+ (void)addDefaultImplementationForClass:(Class)conformingClass;
#end
And create a corresponding implementation file (using MAObjCRuntime for readability here, but the standard runtime functions wouldn't be much more code):
#implementation MyProtocol
+ (void)addDefaultImplementationForClass:(Class)conformingClass {
RTProtocol *protocol = [RTProtocol protocolWithName:#"MyProtocol"];
// get all optional instance methods
NSArray *optionalMethods = [protocol methodsRequired:NO instance:YES];
for (RTMethod *method in optionalMethods) {
if (![conformingClass rt_methodForSelector:[method selector]]) {
RTMethod *myMethod = [self rt_methodForSelector:[method selector]];
// add the default implementation from this class
[conformingClass rt_addMethod:myMethod];
}
}
}
- (void)someOptionalProtocolMethod {
// default implementation
// will be added to any class that calls addDefault...: on itself
}
Then you just have to call
[MyProtocol addDefaultImplementationForClass:[self class]];
in the initializer of your class conforming to the protocol and all default methods will be added.
A truly fascinating way is to use the runtime. At the start-up, very early in the program execution, do the following:
Enumerate all the classes, find classes which implement the protocol
Check if the class implements a method
If not, add to the class the default implementation
It can be achieved without that much trouble.
I agree with "w.m." A very nice solution is to put all the default implementations into an interface (with the same name as the protocol). In the "+initialize" method of any subclass it can simply copy any unimplemented methods from the default interface into itself.
The following helper functions worked for me
#import <objc/runtime.h>
// Get the type string of a method, such as "v#:".
// Caller must allocate sufficent space. Result is null terminated.
void getMethodTypes(Method method, char*result, int maxResultLen)
{
method_getReturnType(method, result, maxResultLen - 1);
int na = method_getNumberOfArguments(method);
for (int i = 0; i < na; ++i)
{
unsigned long x = strlen(result);
method_getArgumentType(method, i, result + x, maxResultLen - 1 - x);
}
}
// This copies all the instance methods from one class to another
// that are not already defined in the destination class.
void copyMissingMethods(Class fromClass, Class toClass)
{
// This gets the INSTANCE methods only
unsigned int numMethods;
Method* methodList = class_copyMethodList(fromClass, &numMethods);
for (int i = 0; i < numMethods; ++i)
{
Method method = methodList[i];
SEL selector = method_getName(method);
char methodTypes[50];
getMethodTypes(method, methodTypes, sizeof methodTypes);
if (![toClass respondsToSelector:selector])
{
IMP methodImplementation = class_getMethodImplementation(fromClass, selector);
class_addMethod(toClass, selector, methodImplementation, methodTypes);
}
}
free(methodList);
}
Then you call it in your class initializer such as...
#interface Foobar : NSObject<MyProtocol>
#end
#implementation Foobar
+(void)initialize
{
// Copy methods from the default
copyMissingMethods([MyProtocol class], self);
}
#end
Xcode will give you warnings about Foobar missing methods, but you can ignore them.
This technique only copies methods, not ivars. If the methods are accessing data members that do not exist, you could get strange bugs. You must ensure that the data is compatible with the code. It is as if you did a reinterpret_cast from Foobar to MyProtocol.
As Ryan mention there are no default implementations for protocols, another option to implementing in the superclass would be is to implement a "Handler" kind of class that can be contained in any class that want to provide the default implementation, the appropriate method then calls the default handlers implementation.
I ended up creating a macro that has a default implementation of the method.
I've defined it in the protocol's header file, and then it's just a one-liner in each implementation.
This way, I do not have to change the implementation several places, and it's done on compile time, so no run-time magic is necessary.

ivars when mixing C and Objective-C

I'm writing an Objective-C wrapper for a C library and having problems accessing the references of my ivars.
The C library requires that I specify a function pointer that handles events, I specify it during the initialization of my Objective-C class.
- (id) init {
[super init];
RegisterClient(&handleEvent);
return self;
}
The C library is able to start searching for something and will then call the handleEvent function in case anything happened during the search. The function (basically) looks like this.
int handleEvent(void *Event) {
[delegate didFinishSearching];
return 0;
}
At least I'd wish it looked like this. The problem is that the code won't build because 'delegate' undeclared (first use in function) (of course I have declared it, I can call [delegate didFinishSearching] from any Objective-C method but not from a C function). Older questions from stackoverflow suggest to define an additional variable (e.g. theDelegate) in the header file:
id theDelegate;
#interface Controller : NSObject {
id delegate;
}
#property (assign) id delegate;
#end
Then, whenever I change the value of delegate to a new one, I have to assign this value to theDelegate, too.
Since my C is somewhat rusty, here are my questions:
1) Can I pass the RegisterClient C function a pointer to an Objective-C method instead of a pointer to a function as an argument in order to avoid the C function handleEvent completely?
2) If not: When I create multiple instances of this Objective-C class, will theDelegate be the same for all instances? (After all, it's not declared as an instance variable...)
Objective-C methods are C functions, but they have two hidden parameters at the front, so they won't have the int f(void *) signature.
What you probably want to do is use an libffi closure. That allows you to create a function with exactly the signature that you want, but that also has a pointer to your object passed along with it. See the example in the ffi_prep_closure man page. Your handleEvent function would probably then change to look something like this:
static void handleEventClosure(ffi_cif * cif, void * result, void ** args, void * userdata)
{
// Arguments.
void * Event = *args[0];
// Closed-over data.
id delegate = (id)userdata;
// Execute the method.
[delegate didFinishSearching];
// Smaller than sizeof(long), so use ffi_arg or ffi_sarg (unsigned or signed).
*(ffi_sarg *)result = (ffi_sarg)0;
}
Most of the time C Libraries like the one you describe accept a "userinfo" parameter conveniently size to match a pointer. You can use this to your advantage by passing your object as this "userinfo" parameter.
Then in callbacks, you cast the pointer back to an object and make the calls you need.

Calling base class functions through derived pointers

( Objective C ) How would I call a base class function using a derived pointer where foo is overridden in the derived class. Essentially the equivalent of this C++ code
base* b_ptr = 0 ;
derived* d_ptr = new derived() ;
d->base::foo() ;
I would think this should be fairly simple. Do I need to use a selector?
You don't. Objective-C's view of object-orientation is very different from C++'s. These are not "class functions" — they're methods of objects. More to the point, you don't call them directly — you send a message to an object and the object responds by executing an appropriate method. If a class chooses to override a method, then that is the implementation its instances will use when it receives the corresponding message. Directly calling a method implementation breaks encapsulation, and you can't do it without some ugly hacks.
There's one limited exception: Within a method implementation, there are two names you use to refer to the current object. If you say [self doSomething], then it will call the current class's doSomething method. If instead you write [super doSomething], it will ignore its own implementation and use the superclass's method.
You would normally only do this from inside the class, using the super keyword
- (int)doSomething {
NSLog(#"calling doSomething on base class");
return [super doSomething];
}
However, it's still possible to do it from outside the class using the runtime function objc_msgSendSuper, but it's a bit more tricky.
#import <objc/objc-runtime.h>
...
Derived *d = [Derived new];
// call doSomething on derived class
[d doSomething];
// call doSomething on base class
struct objc_super b = {
.receiver = d,
.class = class_getSuperclass([d class])
};
objc_msgSendSuper(&b, #selector(doSomething));
}