Does the self keyword have any special meaning for a C struct? - objective-c

Trying to make sense of MTAudioProcessingTap sample code from WWDC 2012.
This structure is used by the Tap to pass data around.
typedef struct AVAudioTapProcessorContext {
...
void *self; //Note use of word self
} AVAudioTapProcessorContext;
The word self here is used apparently as a standard variable name even though Xcode highlights it in pink. Is this just a code parsing oversight in Xcode?
Later, the Tap management class passes a reference to itself to this variable.
//Setting up Tap callbacks:
callbacks.clientInfo = (__bridge void *)self,
//And then storing it in the above struct when it's passed by the callback:
static void tap_InitCallback(MTAudioProcessingTapRef tap, void *clientInfo, void **tapStorageOut)
{
AVAudioTapProcessorContext *context = calloc(1, sizeof(AVAudioTapProcessorContext));
...
context->self = clientInfo;
*tapStorageOut = context;
}
And the confusion starts again in a later function (another Tap callback). Once again, the word self is used to refer to the Tap management class reference. Note that this occurs in a function defined after #end of the Tap management class implementation.
AudioFFTTapProcessor *self = ((__bridge AudioFFTTapProcessor *)context->self);

self has a special meaning only in the context of an Objective-C method. In all other contexts, it's just an ordinary identifier. You can think of Objective-C methods as being rewritten to take a hidden parameter with the name self (and a second hidden parameter named _cmd that's not relevant for this discussion), e.g.:
#implementation MyClass
- (void)doSomething:(int)param1 withThis:(NSString *)param2
{
// 'self' refers to the MyClass instance in this function
...
}
#end
could be imagined as if it were rewritten like this:
void MyClass_doSomething(id self, SEL _cmd, int param1, NSString *param2)
{
// 'self' refers to the MyClass instance in this function
...
}
Outside of Objective-C methods, you can use self as any other kind of identifier, whether it be a local variable, a struct member, a global function, or type name, etc., though the latter uses should be highly discouraged due to high potential for confusion.
So yes, XCode highlighting the self instance in pink in the struct definition is just a parsing anomaly.

self is not a keyword in C. It's a keyword for Objective-C, which is probably why it's getting highlighted.

self does not mean anything special as a C struct field name. Objective-C uses it as the equivalent of most other OO languages' this, which is why Xcode highlights it specially.

Related

C function accessing private ivar of Objective-C class

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.

Is there a way to reflectively call a function in Objective-C from a string?

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! 👓 ⌘ 🐻

Using objc_msgSendSuper to invoke a class method

I was going through and replacing #synthesized(self) locks w/ this method
void _ThreadsafeInit(Class theClassToInit, void *volatile *theVariableItLivesIn, void(^InitBlock)(void))
{
//this is what super does :X
struct objc_super mySuper = {
.receiver = (id)theClassToInit,
.super_class = class_getSuperclass(theClassToInit)
};
id (*objc_superAllocTyped)(struct objc_super *, SEL, NSZone *) = (void *)&objc_msgSendSuper;
// id (*objc_superAllocTyped)(id objc_super, SEL, NSZone *) = (void *)&objc_msgSend;
do {
id temp = [(*objc_superAllocTyped)(&mySuper /*theClassToInit*/, #selector(allocWithZone:), NULL) init];//get superclass in case alloc is blocked in this class;
if(OSAtomicCompareAndSwapPtrBarrier(0x0, temp, theVariableItLivesIn)) { //atomic operation forces synchronization
if( InitBlock != NULL ) {
InitBlock(); //only the thread that succesfully set sharedInstance pointer gets here
}
break;
}
else
{
[temp release]; //any thread that fails to set sharedInstance needs to clean up after itself
}
} while (*theVariableItLivesIn == NULL);
}
which while a bit more verbose exhibits significantly better performance in non-contested cases
along with this little macro (excuse poor formatting, it's very simple). To allow the block to be declared after the initial nil check, looks to help LLVM keep the "already initialized" path extremely fast. That's the only one I care about.
#define ThreadsafeFastInit(theClassToInit, theVariableToStoreItIn, aVoidBlockToRunAfterInit) if( theVariableToStoreItIn == nil) { _ThreadsafeInitWithBlock(theClassToInit, (void *)&theVariableToStoreItIn, aVoidBlockToRunAfterInit); }
So initially implemented it using the commented out sections for objc_superAllocTyped (actually first using [theClassToInit allocWithZone:NULL], which was definitely the best approach :) ), which worked great until I realized that most of the singletons in the project had overridden allocWithZone to return the singleton method... infinite loop. So I figured using objc_msgSendSuper should sort it out quickly, but I get this error.
[51431:17c03] +[DataUtils allocWithZone:]: unrecognized selector sent to class 0x4f9584
The error doesn't seem to be related to the actual problem, as...
(lldb) po 0x4f9584
$1 = 5215620 DataUtils
(lldb) print (BOOL)[$1 respondsToSelector:#selector(allocWithZone:)]
(BOOL) $2 = YES
So I'm definitely missing something... I compared to assembly generated by a [super allocWithZone:NULL] method in an empty class... almost identical except for the functions called have different names (maybe just using different symbols, no idea, can't read it that well).
Any ideas? I can use class_getClassMethod on the superclass and call the IMP directly, but I'm trying to be reasonable in my abuse of the runtime :)
Alright, this wasn't actually that tricky once I recalled that the meta class contains all of the method information for a Class instance obtained via -[self class] or +[self] -> thanks http://www.cocoawithlove.com/2010/01/what-is-meta-class-in-objective-c.html
This error occurred because I was asking the runtime to look up the method in NSObject's set of instance methods, which obviously doesn't contain allocWithZone: . The mistake in the error log presumably originated because the receiver was a metaclass instance, and Apple has their interns implement error logs.
so while with a normal instance method call via objc_msgSendSuper, you would pass a metaclass instance as objc_super.super_class, to invoke a class method, the metaclass itself is needed (everything is one level up).
Example, and a diagram that helped me understand this - (http://www.sealiesoftware.com/blog/archive/2009/04/14/objc_explain_Classes_and_metaclasses.html)
struct objc_super mySuper;
mySuper.receiver = theClassToInit; //this is our receiver, no doubt about it
//either grab the super class and get its metaclass
mySuper.super_class = object_getClass( class_getSuperclass( theClassToInit ) );
//or grab the metaclass, and get its super class, this is the exact same object
mySuper.super_class = class_getSuperclass( object_getClass( theClassToInit ) );
Then the message can be resolved correctly. Makes perfect sense now that I started paying attention :P
Anyways, now that I found my mistake I feel like I've leveled up my Objc runtime understanding. I was also able to fix an architectural mistake made two years ago by someone I never met without having to modifying and re-test dozens of classes across 3 projects and 2 static libraries (God I love Objective-C). Replacing the #synchronized construct with a simple function call also halved the compiled code size of those methods. As a bonus, all our singleton accessors are now (more) threadsafe, because the performance cost for doing so is now negligible. Methods which naively re-fetched the singleton object multiple times (or in loops) have seen a huge speedup now that they don't have to acquire and release a mutex multiple times per invocation. All in all I'm very happy it all worked as I'd hoped.
I made a "normal" Objective-C method for this on a category of NSObject, which will work for both instance and Class objects to allow you to invoke a superclass's implementation of a message externally. Warning: This is only for fun, or unit tests, or swizzled methods, or maybe a really cool game.
#implementation NSObject (Convenience)
-(id)performSelector:(SEL)selector asClass:(Class)class
{
struct objc_super mySuper = {
.receiver = self,
.super_class = class_isMetaClass(object_getClass(self)) //check if we are an instance or Class
? object_getClass(class) //if we are a Class, we need to send our metaclass (our Class's Class)
: class //if we are an instance, we need to send our Class (which we already have)
};
id (*objc_superAllocTyped)(struct objc_super *, SEL) = (void *)&objc_msgSendSuper; //cast our pointer so the compiler can sort out the ABI
return (*objc_superAllocTyped)(&mySuper, selector);
}
so
[self performSelector:#selector(dealloc) asClass:[self superclass]];
would be equivalent to
[super dealloc];
Carry on runtime explorers! Don't let the naysayers drag you into their land of handwaving and black magik boxes, it's hard to make uncompromisingly awesome programs there*.
*Please enjoy the Objective-C runtime responsibly. Consult with your QA team for any bugs lasting more than four hours.

When I have use ARC in IOS project,how can I use void *?

LooK this method:
beginAnimations:context:
This is a method of class UIView. The context need parameter which is a type of void-pointer,and I need to send a UIImageView to context.
I get a warning,which says void* has been forbidden when I use ARC. So how can I send UIImageView to context except not use ARC.
The comments above provided the correct answer for this particular case (use the block-based animation methods) but in general if you have an API which takes a context void * and you'd like to pass an object, I find it best to convert your id to a CFTypeRef so you can get manual memory management semantics on the pointer (CFTypeRef is a typedef for void *), etc. Note however that this requires that the callback must be called in order to get your object released (i.e. converted back to ARC's built-in management).
Here's an example for some imaginary API I just dreamt up:
- (void) doSomethingWithObject: (id) object {
// use CFBridgingRetain() to turn object into a manually-retained CFTypeRef/void*
[someObject performBackgroundTaskWithTarget: self
selector: #selector(bgTask:)
context: CFBridgingRetain(object)];
}
- (void) bgTask: (void *) context
{
// use CFBridgingRelease() to turn our void*/CFTypeRef into an ARC-managed id
id object = CFBridgingRelease((CFTypeRef)context);
...
}

How do I write to an NSObject from within a C function that doesn't see Obj-C variables?

I'm trying to get some code going that lets me display raw trackpad data from my macbook pro, like the app FingerMgmt. Unfortunately, no one seems to have the source for FingerMgmt. I did find some other source code that kind of works, however. I was able to NSLog the data I wanted to see like this:
int callback(int device, Finger *data, int nFingers, double timestamp, int frame) {
for (int i=0; i<nFingers; i++) {
Finger *f = &data[i];
NSLog(#"Frame %7d: Angle %6.2f, ellipse %6.3f x%6.3f; "
"position (%6.3f,%6.3f) vel (%6.3f,%6.3f) "
"ID %d, state %d [%d %d?] size %6.3f, %6.3f?\n",
f->frame,
f->angle * 90 / atan2(1,0),
f->majorAxis,
f->minorAxis,
f->normalized.pos.x,
f->normalized.pos.y,
f->normalized.vel.x,
f->normalized.vel.y,
f->identifier, f->state, f->foo3, f->foo4,
f->size, f->unk2);
//todo-get data from raw C to obj-C variable
}
return 0;
}
But whenever I try to store any of the data to an Obj-c string or variable, the C code does not see the variable as having been declared. Because of this, I cannot write to any text fields or graphical displays in Obj-C, and I cannot store the data to a variable that Obj-c can access.
Basically, I need a way to write to an Obj-C variable or object from within the callback.
On a side note, I had a very similar problem with an iPhone app a while back, and I ended up fixing it by somehow declaring the app delegate within the C code and writing to or reading from the variable like this-
me.delegate=(id <UIApplicationDelegate,UITabBarControllerDelegate>)[[UIApplication sharedApplication] delegate];//allows access to the delegate within C function
me.delegate.number0=5;//writes to this variable in the delegate
For some reason, I can not seem to adapt this to my current situation. I always get the error that "me" is undeclared.
A Objective-C method can access instance variables because it is automagically passed a hidden parameter with the public name self - any reference to an instance variable, say fred, is translated by the compiler into a field reference, say self->fred (and a similar translation for property references).
For your C function callback to access the fields of any object (or call an object's methods) you need to pass the function a reference to the object. Two simple ways:
Add an argument to the function. Many C callback protocols include a general "user defined" values which is passed around as void *, if you are calling one of these pass your object reference as this value and cast it within the C function back to the correct Objective-C type.
Pass the object via a global (or file static) variable, e.g. static NSSomeType *objectForCallback;. This method works when you're stuck with an existing C callback protocol which doesn't support a user defined value. However it is not thread or re-entrant safe as you are sharing a single static variable.
In both cases make sure the objected is retain'ed if you're not using garbage collection.
In response to comment
Case 1: You will see C functions declared which (a) take a callback function and (b) a user-defined value to pass to that function on every call. For example:
typedef T ...;
T findMatching(T *buffer, // an array of T to search
size_t count, // number of items in array
int (*matcher)(T item, void *user), // user function for match, 1st arg is item, 2nd user-supplied value
void *userValue); // user-supplied value to pass to matcher
If you are faced with C function like this you can pass a (retain'ed if needed) Objective-C object as userValue and cast it back to its Objective-C type inside matcher. For example:
int myMatcher(T item, void *user)
{
NSMutableDictionary *myDictionary = (NSMutableDictionary *)user;
...
}
- (void) someMethod
{
NSMutableDictionary *sharedWithC = ...;
...
T found = findMatching(buffer, count, myMatcher, (void *)sharedWithC);
...
}
Case 2: Objective-C is (a superset of) C. You declare a global just as you would in C. For example (little checking, not thread safe):
static NSMutableDictionary *myGlobalDictionary = nil; // "static" makes the variable only visible to code in the same file
- (void) setupTheSharedDictionary
{
myGlobalDictionary = [[[NSMutableDictionary alloc] init] retain];
}
- (void) releaseTheSharedDictionary
{
if(myGlobalDictionary != nil)
{
[myGlobalDictionary release];
myGlobalDictionary = nil;
}
}
In response to second comment
I'm guessing you are trying to use some third party (Google?) code. That code defines a callback protocol - a C function type. You cannot just redefine that C function type adding an extra argument and expect the third party code to magically cope!
So unless you intend to change the C you can use the second approach - store the reference to Objective-C object in a global. In your case this will be something like:
static MT2AppDelegate *sharedWithCAppDelegateReference;
int callback(...)
{
...
[sharedWithCAppDelegateReference->L1 setStringValue:#"Hellofff"];
...
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
sharedWithCAppDelegateReference = self; // store so C can pick it up
...
MTRegisterContactFrameCallback(dev, callback);
...
}
But remember this is not thread or re-entrant safe - you are effectively passing a function parameter via a global variable. If you need it to be thread/re-entrant safe you need to get a bit more involved.