iOS: Unable to access instance methods inside a C-class - objective-c

I dont think I've understood C well enough.
In my codes, added a call back method.
And inside the method, I want to be able call a method that beings to the instance. I tried [self methodName] but I'm told 'self is an undeclared identifier`.
Added code snippets:
#implementation TheClass
static void audioRouteChangeListenerCallback (
void *inUserData,
AudioSessionPropertyID inPropertyID,
UInt32 inPropertyValueSize,
const void *inPropertyValue)
{
.
.
//trying to call a instance method of TheClass here.
}

You cannot use self in a plain C function, it doesn't belong to any Objective-C instance (that's the difference between a function and a method).
For callbacks that are supposed to interact with Objective-C, you would usually pass a pointer to your object when you set up the callback. In this case, inUserData is probably something that you can set yourself when registering the callback.

In your question, the syntax you are using is not C, but objective-C. Are you attempting to use objective-C? If so, self is a keyword, not an identifier. The compiler clearly thinks your code is C, not Objective-C. Does your source file have a .m file extension?

Related

Objective C - Call Method defined from a Macro

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.

Can someone explain how I might use this function call that includes a delegate?

This is the prototype:
- (void)startDownloadingDataOfType:(NSString *) type fromURL:(NSURL *) url delegate:(id <GetURLAsyncDelegate>) delegate;
There is a delegate set up with methods such as URLDidFinishDownloading and so on. However I stil don't totally understand delegates - I get their point, but I don't really know how to use them.
This function seems to contain a parameter to pass IN a delegate, but surely I want to extract one?
In the class where I want to call this function I essentially want to be able to trigger a method when the URL has finished it's download. What is the syntax for using this kind of function in a class?
Passing the delegate to the prototype will cause the method to be called on the supplied delegate.
If you want the method (URLDidFinishDownloading) to be called when the download is complete in the class you called it from, implement the delegate in that class and specify the URLDidFinishDownloading method.
Something like below - (note: my obj-c isn't the greatest, but hopefully you get the idea)
#interface MyClass : BaseClass<GetURLAsyncDelegate> {
}
#implementation MyClass
-(void)URLDidFinishDownloading {
...
}
-(void)downloadData {
[object startDownloadingDataOfType:#"..." fromUrl:... delegate:self];
}

Can I inline static class methods in Objective-C?

You can declare functions as inlines like this:
#ifdef DEBUG
void DPrintf(NSString *fmt,...);
#else
inline void DPrintf(NSString *fmt,...) {}
#endif
so that when you're not in DEBUG, there's no cost to the function because it's optimized and inline. What if you want to have the same thing but for a class method?
My class is declared like this:
#interface MyClass : NSObject {
}
+ (void)DPrintf:(NSString *)format, ...;
// Other methods of this class
#end
I want to convert 'DPrintf' into something similar to the inline so that there's no cost to invoking the method.
But I can't do this:
inline +(void)DPrintf:(NSString *)format, ...; {}
How can I have a zero-cost static method of a class turned off for non-debug compilations?
Be careful. Objective-C methods are not the same as C functions. An Objective-C method is translated by the compiler into the objc_msgSend() function call; you don't have control over whether a method is inline or not because that is irrelevant. You can read more about the Objective-C runtime here (Objective-C Runtime Programming Guide), here (Objective-C Runtime Reference), and here (CocoaSamurai post), and a quick Google search should bring up more info.
There is no such thing as a static method in Objective-C. There are only class methods, which are just like instance methods except they belong to a class. This means that, just like instance methods, a message send to a class must go through the message dispatch machinery to determine the correct method to call, and that is done at runtime. You could inline the call to the method dispatch machinery, but the method body still can't be inlined without a crazy level of optimization that doesn't exist in any Objective-C compiler at the moment.
At any rate, this is a micro-optimization. If profiling shows it to be necessary (which it almost never will), then you can go through the gymnastics. Otherwise, worry about the actual performance concerns in your application.
Yes!
You can accomplish this with blocks
-(void)viewDidLoad {
void(^inlineFunction)(int) = ^(int argument) {
NSLog(#"%i", argument);
};
inlineFunction(5);//logs '5'
}
Apple even documents this here (archive).
Enjoy!

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.

Using Super in an Objective C Category?

I'd like to override a method in an Objective C class that I don't have the source to.
I've looked into it, and it appears that Categories should allow me to do this, but I'd like to use the result of the old method in my new method, using super to get the old methods result.
Whenever I try this though, my method gets called, but "super" is nil... Any idea why? I'm doing iPhone development with the XCode 2.2 SDK. I'm definitely working with an instance of a class, and the method of the class is an instance method.
#implementation SampleClass (filePathResolver)
-(NSString*) fullPathFromRelativePath:(NSString*) relPath
{
NSString *result = [super fullPathFromRelativePath: relPath];
... do some stuff with the old result
return result;
}
Note and clarification: From what I can see in the Apple Docs, it appears to me that this should be allowed?
Categories docs at developer.apple.com:
When a category overrides an inherited method, the method in the
category can, as usual, invoke the
inherited implementation via a message
to super. However, if a category
overrides a method that already
existed in the category's class, there
is no way to invoke the original
implementation.
Categories extend the original class, but they don't subclass it, therefore a call to super doesn't find the method.
What you want is called Method Swizzling. But be aware that your code could break something. There's an article on Theocacao written by Scot Stevenson about Method Swizzling in the old Objective-C runtime, Cocoa with Love by Matt Gallagher has an article about Method Swizzling in the new Objective-C 2.0 runtime and a simple replacement for it.
Alternatively, you could subclass the class and then either use the subclass or use + (void)poseAsClass:(Class)aClass to replace the superclass. Apple writes:
A method defined by a posing class
can, through a message to super,
incorporate the superclass method it
overrides.
Be aware that Apple has deprecated poseAsClass: in Mac OS X 10.5.
If you will be coding against this class, simply rename the selector to something your code can use, and call the original selector on self:
#implementation SampleClass (filePathResolver)
-(NSString*) myFullPathFromRelativePath:(NSString*) relPath
{
NSString *result = [self fullPathFromRelativePath: relPath];
... do some stuff with the old result
return result;
}
If you want to override the default implementation of this selector for that class, you'll need to use the method swizzling approach.
Not exactly in category but there is a workaround by adding the method dynamically at runtime. Samuel Défago in his article describes a neat way to create block IMP implementation calling super, his original article can be found here
The relevant code is:
#import <objc/runtime.h>
#import <objc/message.h>
const char *types = method_getTypeEncoding(class_getInstanceMethod(clazz, selector));
class_addMethod(clazz, selector, imp_implementationWithBlock(^(__unsafe_unretained id self, va_list argp) {
struct objc_super super = {
.receiver = self,
.super_class = class_getSuperclass(clazz)
};
id (*objc_msgSendSuper_typed)(struct objc_super *, SEL, va_list) = (void *)&objc_msgSendSuper;
return objc_msgSendSuper_typed(&super, selector, argp);
}), types);