Objective C: Two implicit parameters passed to every method called by an object - objective-c-2.0

What are the two implicit parameters passed to every method by an object in Objective-c? Is it _cmd and id?

That is a good question,
the short answer is:
yes, two parameters are being implicitly passed. self of type id, and _cmd of type SEL.
to better understand it, here is what happens behind the method call.
#interface Item:NSObject
-(void)dummyMethod;
#end
#implementation Item
-(void)dummyMethod{
NSLog(#"dummyPrint");
}
#end
a normal method call would be like:
Item* objectOne = [[Item alloc]init;
[objectOne dummyMethod];
that call gets translated/complied to:
objc_msgSend(objectOne,#selector(dummyMethod)); //since the dummy method takes no parameters and returns void
to try it/use it your self.
1. #import<objc/message.h
2. cast the objc_msgSend method to an appropriate function pointer type before being used, like that.
void (*objc_msgSendPointer)(id self, SEL _cmd) = (void*)objc_msgSend;
objc_msgSendPointer(one, #selector(dummyMethod));
here is the function declaration
id objc_msgSend(id self, SEL op, ...);
take a look at this documentation for further info..
objc_msgSend.
take a look also at this topic using objc_msgSend to call a Objective C function with named arguments
for more info regarding other methods, specially Ken's answer.
I hope that was helpful!

Related

Swift can't call self from c callback in linphone sdk

I have problem when try to call Swift instance method from c callback.
Error: "A C function pointer cannot be formed from a closure that captures context."
linphone_core_cbs_set_registration_state_changed(cbs) { (lc, cfg, state, message) in
switch state{
case LinphoneRegistrationOk:
print("LinphoneRegistrationOk")
self.call()
}
func call() {
let account = "test"
let domain = "sip.linphone.org"
let identity = "sip:" + account + "#" + domain
linphone_core_invite(lc, identity)
}
If you have the ability to pass an arbitrary void* as a context then using Unmanaged<SelfType>.passUnretained(self).toOpaque() and converting it back with Unmanaged<SelfType>.fromOpaque(context).takeUnretainedValue() is the best solution.
But based on your small snippet of (lc, cfg, state, message) none of them seem like a context pointer. So getting self back is still possible but likely more complex. Because you will need to create a global/static piece of data that can be accessed from inside your closure in a safe manner. Some ideas of how you can do this are below:
1) You can do this with just a simple global/static if you know that is safe.
2) You can use thread local storage and store a pointer to self and cast it back and forth in the same way as if you had the void* argument and used Unmanaged. This one of course requires that your C callback be raised on the same thread where you store the value.
3) If you have access to a unique identifier that both Swift and C can access that will continue to be valid and accessible in your callback you can create a map of type [UniqueIdentifierAccessibleBySwiftAndC: TypeOfSelf] and use that to get self back.

Using Lua FFI with complex types

Bit of a complicated use case... Trying to access a C++ Object inside of Lua FFI, via a C wrapper.
ffi.load("wrapper.so")
​
ffi.cdef[[
struct puppy;
typedef struct puppy puppy_t;
puppy_t * puppy_bark (const char *encoded);
]]
However every time I try to instantiate a puppy, it returns "size of C type is unknown or too large".
I've tried the following to get a puppy created...
pup = ffi.typeof("puppy_t")
pup.puppy_bark("some text")
Results in struct puppy has no member named puppy_bark
pup = ffi.new("struct puppy_t")
pup.puppy_bark("some text")
Returns undeclared or implicit tag
pup = ffi.new("struct puppy puppy_t")
pup.puppy_bark("some stringish thing")
Returns '<eof>' expected near puppy_t
Assuming that the C Wrapper correctly has a Puppy Struct, Type, and the requisite method, how do create an instance of or a pointer to a Puppy in order to make it bark?
Thanks in advance!
You ask "how do I create an instance of or a pointer to a puppy in order to make it bark" - but it's not possible to create an instance of something without having its definition, and it's not possible to create a pointer to something without having an instance of it, and puppies don't bark with your code anyway (but there is a global function puppy_bark that creates a new puppy?).
It looks like you can create a puppy by calling puppy_bark (in which case, what a horribly badly named function!), but I can't be sure of that without seeing the actual code behind puppy_bark.
Since I don't have a specific answer to a specific question, here are some things that are likely to help you:
ffi.new("puppy_t") doesn't work because the FFI needs to have the definition of struct puppy, not just a forward declaration, for exactly the same reason this won't work in C++:
struct puppy;
puppy *p = new puppy;
So, if you want to do this, you need to load the complete definition into the FFI. Note that LuaJIT's FFI only supports C code, not C++.
ffi.new("struct puppy_t") doesn't work because that's not a type that exists.
ffi.new("struct puppy puppy_t") don't work because that's not a valid type.
pup = ffi.typeof("puppy_t") pup.puppy_bark("some text") doesn't work because puppy_bark isn't a member of struct puppy (as the error message tells you).
It also seems like you're misunderstanding the purpose of ffi.typeof. According to the documentation, ffi.typeof returns a constructor for the given type, so that
local new_puppy = ffi.typeof("puppy_t")
local puppy = new_puppy(1, 2, 3, 4)
is the same as
local puppy = ffi.new("puppy_t", 1, 2, 3, 4)
If you want to call the global function puppy_bark, you can do that with ffi.C.puppy_bark("some text").

SWIG R wrapper not setting class properly/Create R object from C memory pointer

I have a SWIG generated R wrapper which contains the following setClass operations:
setClass('_p_f_p_struct_parameters_p_struct_chromosome_p_struct_dataSet__double',
prototype = list(parameterTypes = c('_p_parameters', '_p_chromosome', '_p_dataSet'),
returnType = '_p_f_p_struct_parameters_p_struct_chromosome_p_struct_dataSet__double'),
contains = 'CRoutinePointer')
setClass('_p_f_p_struct_parameters_p_p_struct_chromosome_p_p_struct_chromosome_int_int__void',
prototype = list(parameterTypes = c('_p_parameters', '_p_p_chromosome', '_p_p_chromosome', '_int', '_int'),
returnType = '_p_f_p_struct_parameters_p_p_struct_chromosome_p_p_struct_chromosome_int_int__void'),
contains = 'CRoutinePointer')
These operation do not appear to be behaving as expected. When I call a function with the output being the creation of a _p_parameters object (defined above), I get the following error:
Error in getClass(Class, where = topenv(parent.frame())) :
“_p_parameters” is not a defined class
The setClass therefore seems to be not doing it's thing.
I tried to manually set the _p_parameters class via:
p_parameters<-setClass(Class="_p_parameters", representation = representation(ref = "externalptr"))
But this does not seem to work as when I try and modify other parameters (or even print parameters via an inbuilt function) the terminal crashes and hangs.
For reference, the final lines in initialiseParameters (the function which initially own _p_parameters) are calling the native C function via .Call then assigning the external pointer to a new object of class _p_paramters as follows:
;ans = .Call('R_swig_initialiseParameters', numInputs, numNodes, numOutputs, arity, as.logical(.copy), PACKAGE='cgp');
ans <- new("_p_parameters", ref=ans) ;
I've read various R doc on new(), setClass, S3/S4 classes but nothing seems to clarify what I'm meant to be doing here.
Any suggestions on where to start or tutorials that would give a good heads up would be most welcome.
Please keep in mind the C code is not mine (but is freely available under GNU), I am not a C programmer and am only weakly-moderately proficient in R. So please be gentle :)
Cheers.
PS: If I call the function in R terminal via .Call it works as expected (so it doesn't seem to e a C function error)
I thought I should post the solution I have to this. The least I could do for a 'tumbleweed' medal haha.
The only solution I could find to this is to comment out the following line:
ans <- new("_p_parameters", ref=ans) ;
in all function that try to create an R object.
The resulting memory pointer is then assigned to an R object at function call.
It's dirty, but I couldn't work out how to create an object from a memory pointer (at least from within the functions themselves).
It seems to work so I guess it will do.

Scala's multidimensional arrays one more time

var channelsNumber = track.getNumberOfChannels()
var framesNumber = lastFrame - firstFrame
var frames = Array.ofDim[Int](channelsNumber)(framesNumber)
System.out.println(frames.length);
System.out.println(frames.length);
I try to define two dimensional array of integers. And I get this error:
[error] .../test.scala:58: type mismatch;
[error] found : Int
[error] required: scala.reflect.ClassManifest[Int]
[error] var frames = Array.ofDim[Int](channelsNumber)(framesNumber)
[error] ^
[error] one error found
What is "scala.reflect.ClassManifest[Int]"? Why channelsNumber passes and framesNumber, which is also an integer doesn't?
Now, you are calling method ofDim [T] (n1: Int)(implicit arg0: ClassManifest[T]) which you don't want to. Change the call to Array.ofDim[Int](channelsNumber,framesNumber) and the method ofDim [T] (n1: Int, n2: Int)(implicit arg0: ClassManifest[T]) will be called. You want to leave the implicit parameter group implicit.
And - class manifest is a way how to preserve type information in generic classes.
First your error: ofDim takes all the dimension in a single parameter list. You need
Array.ofDim[Int](channelsNumber, framesNumber)
Second, ClassManifest. Due to type erasure, and the fact than in the JVM, arrays are very much like generics, but are not generic (among other things, no type erasure), the generic method ofDim needs to be passed the type of the elements. That is the ClassManifest, which is close to passing a Class in java (you have to do the same in java -or pass an empty array of the proper type, in Collection.toArray- if you have a generic method that must return an array) This comes as as an implicit arguments, that is there is another parameter list with this argument, but the scala compiler will try to fill it automatically, without you having to write it in the code. But if you give a second parameter list, it means you intend to pass the ClassManifest yourself.

Does this function IOHIDManagerRegisterDeviceMatchingCallback operate under the cocoa environment?

I am struggling to implement an HID control with a Mac : I cannot send the expected function as depicted here below:
IOHIDManagerRegisterDeviceMatchingCallback( gIOHIDManagerRef, Handle_DeviceMatchingCallback, NULL );
with : gIOHIDManagerRef -> the valid HID manager dedicated to this routine
Handle_DeviceMatchingCallback --> the routine that will be called back when the HID
device is attached to the USB port
NUUL --> not used here, contain data from the USB
The issue is that Handle_DeviceMatchingCallback must be a pointer to the routine, but how can I send a pointer ?
On the other hand, all the examples , from the Apple source, are based on C, not on cocoa.
Well, does that means that I must rework my program in C ??? Or is it possible to have fraction of the program in C under the cocoa environment?
Sorry for so "stupid" question queries, but, although I have some background in the field of electronic an programming, I am very newbees with cocoa.
Your comments will be very appreciated !
Michael
Objective-C is mostly a super-set of C. In order to combine C and Objective-C code, you simply compile your C code as if it were Objective-C code. The easiest way to do this in Xcode is to ensure the file in question has a .m extension.
To route handling back to the Objective-C world, you need a pointer to an Obj-C object. Many callback-based APIs allow you to provide a generic pointer (void *) that they then pass back to you when they callback. This argument has several common names:
context or ctx
refcon (for "reference constant")
userData
userInfo
If the callback API does not allow this, you'll need some uglier way to dispatch the callback to your object, such as a global pointer or a lookup table.
The API you're using does let you provide a context pointer. When it calls back to your code, it provides you with the pointer you used when you registered for the callback. Here is an example of registering the callback from an object of type MyObjCClass (see the -registerMatching method below) and then using the context pointer to route the callback back to the object that registered the callback for handling (see the Handle_DeviceMatchingCallback function's use of the context pointer).
/*! #file C-ObjC-Callbacks.m
* Demonstrates routing a C callback to an Obj-C object
* using the callback's context pointer.
*/
#import <Cocoa/Cocoa.h>
#import <IOKit/hid/IOHIDManager.h>
// Global HID manager reference.
IOHIDManagerRef gIOHIDManager;
// HID callback
void Handle_DeviceMatchingCallback(void *context,
IOReturn result,
void *sender,
IOHIDDeviceRef device);
#interface MyObjCClass : NSObject {
}
- (void)registerMatching;
- (void)handleMatchingDevice:(IOHIDDeviceRef)device
sender:(void *)sender
result:(IOReturn)result;
#end
#implementation MyObjCClass
- (void)registerMatching {
// Assume gIOHIDManager has already been created.
// Set up a device matching callback, providing a pointer to |self| as the context.
IOHIDManagerRegisterDeviceMatchingCallback(gIOHIDManager,
Handle_DeviceMatchingCallback,
(void *)self);
}
- (void)handleMatchingDevice:(IOHIDDeviceRef)device
sender:(void *)sender
result:(IOReturn)result {
// Do something...
}
#end
void
Handle_DeviceMatchingCallback(void *context,
IOReturn result,
void *sender,
IOHIDDeviceRef device); {
MyObjCClass *const myObject = (MyObjCClass *const)context;
[myObject handleMatchingDevice:device sender:sender result:result];
}
Handle_DeviceMatchingCallback must be a pointer to the routine, but how
can I send a pointer ?
If you want to pass in a function functionName, you can pass it as
&functionName.
On the other hand, all the examples , from the Apple source, are based on
C, not on cocoa. Well, does that means that I must rework my program in C
??? Or is it possible to have fraction of the program in C under the cocoa
environment?
You can mix C and Objective-C at will. As long as you pass it a function,
and not a method attached to an object, it should work.

Resources