Pass pointer to var in C function from Swift - objective-c

I have a C function in a file with name (Buffer is a C struct)
BufferInit(Buffer *buffer, int32_t size)
As I am moving to Swift, in my Swift class I declare a private var like
var buffer:Buffer?
and in init function I make a call like this
BufferInit(&buffer, 32)
But I get compilation errors, what is the correct way to achieve the same in Swift? I call call the same BufferInit from Objective-C without issues but Swift is messy.
EDIT: Here are details,
typedef struct {
void *buffer;
int32_t length;
int32_t tail;
int32_t head;
} Buffer;
Error is compiler is asking me to unwrap buffer and correct the code as(which I don't think is correct):
BufferInit(&buffer!, 32)

Your C function is imported to Swift as
func BufferInit(_ buffer: UnsafeMutablePointer<Buffer>!, _ size: Int32)
and you have to pass the address of a (initialized, nonoptional)
variable of type Buffer as an inout expression.
Structures imported from C have a default constructor in Swift which
initializes all members to zero, so you can write
var buffer = Buffer()
BufferInit(&buffer, 32)

Related

Pass Objective-C block or method as C-function pointer

I'm using https://github.com/nodejs/http-parser, the callbacks it uses are like this
struct http_parser_settings {
http_cb on_message_begin;
http_data_cb on_url;
http_data_cb on_status;
http_data_cb on_header_field;
http_data_cb on_header_value;
http_cb on_headers_complete;
http_data_cb on_body;
http_cb on_message_complete;
/* When on_chunk_header is called, the current chunk length is stored
* in parser->content_length.
*/
http_cb on_chunk_header;
http_cb on_chunk_complete;
};
The main callback type is defined here
typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
I'm trying to find a way to pass either an Objective-C block or method as the function pointer in the parser_settings. However it lets me use only a C-function, which doesn't suit me because I also need to access the state of an Objective-C object in the callback
At the moment my solution is as follows:
int onHeaderField(http_parser* _, const char* at, size_t length) {
// Need to access state here, so doesn't work for me as a c function
char header[length];
strncpy(header, at, length);
NSLog(#"Header %s", header);
return 0;
}
...
- (void)method {
http_parser_settings settings;
settings.on_header_field = onHeaderField; // rather than func would like to set a block/method to capture and access self
size_t nparsed = http_parser_execute(self.parser, &parserSettings, charData, messageLength)
}
How would I go about accessing self from the callback passed to http_parser_execute?
Technically you can "extract" an Objective-C method implementation in form of a C-pointer with use of class_getMethodImplementation, however these implementations have objc_msgSend-like signature and always require the receiver as an argument, thus not really usable outside of Objective-C world:
NSString *str = #"Hollow World";
SEL sel = #selector(isEqualToString:);
Method meth = class_getInstanceMethod([str class], sel);
typedef BOOL(*IsEqualToStringPtr)(NSString *, SEL, NSString *);
IsEqualToStringPtr impl = (IsEqualToStringPtr)method_getImplementation(meth);
NSLog(#"Is equal? %#", impl(str, sel, #"Hello, World!") ? #"YES" : #"NO"); // prints "NO"
NSLog(#"Is equal? %#", impl(str, sel, #"Hollow World") ? #"YES" : #"NO"); // prints "YES"
Having that said, neither blocks nor Objective-C methods are directly convertible to a C function pointer (they are pointers to structures under the hood), especially when you want to complement it with any kind of context/state.
The simplest thing you can do is to use a global/statically allocated block variable which can be accessed from a C function without altering it's signature:
static int(^StaticBlock)(http_parser *parser, const char *at, size_t length);
static int my_callback(http_parser *parser, const char *at, size_t length) {
return StaticBlock(parser, at, length);
}
...
- (void)someObjectiveCMethod {
__weak typeof(self) weakSelf = self;
StaticBlock = ^(http_parser *parser, const char *at, size_t length) {
if (!weakSelf) {
return -1;
}
__strong typeof(weakSelf) strongSelf = weakSelf;
strongSelf.mprpty += length;
NSLog(#"Hello from Objective-C");
return 8;
};
http_parser_settings settings;
settings.on_header_field = my_callback;
}
The only viable alternative I can think of is using C++ lambdas. However it's still a big challenge when you need to access current state/context, let alone it will require you to switch to Objective-C++. If you are ok with it, first you need to rename your Objective-C file from SomeClass.m into SomeClass.mm. This way you tell Clang that the source code is Objective-C++ now and the compiler should accept a C++ code. Next, if your C library doesn't have C++ guards, you may want to wrap the C includes with extern "C" expression (otherwise linker would not be able to locate C symbols, because C++ mangles them):
extern "C" {
#include <c_header.h>
}
Now the tricky part: lambda expressions return special objects, closures, which can be seamlessly converted to C function pointers only if they don't capture anything from surrounding context. In our scenario it's not the case and it will require extra steps to convert it to a C pointer. Add this code somewhere in your *.mm file:
template<typename L>
struct c_functor_factory : c_functor_factory<decltype(&L::operator())> {};
template<typename R, typename F, typename ...Args>
struct c_functor_factory<R(F::*)(Args...) const> {
using pointer = typename std::add_pointer<R(Args...)>::type;
static pointer make_cptr(F&& func) {
static F instance = std::forward<F>(func);
return [](Args... args) {
return instance(std::forward<Args>(args)...);
};
}
};
template<typename L>
inline static typename c_functor_factory<L>::pointer make_cptr(L&& lambda) {
return c_functor_factory<L>::make_cptr(std::forward<L>(lambda));
}
In fact this solution is not much far from the global C function solution I suggested above. When a closure is passed as an argument here, this template function just perfect-forwards it to a statically allocated variable. As a result the static closure can be called from a capture-less lambda, which in turn is converted to a C function pointer.
Finally, you can make use of C++ lambda expressions and pass them as C function pointers anywhere in your Objective-C code:
- (void)someObjectiveCMethod {
__weak typeof(self) weakSelf = self;
const auto cptr = make_cptr([weakSelf](http_parser *parser, const char *at, size_t length) {
if (!weakSelf) {
return -1;
}
__strong typeof(weakSelf) strongSelf = weakSelf;
strongSelf.num += val;
NSLog(#"Hello from Objective-C++, %s!", at);
return 32;
});
http_parser_settings settings;
settings.on_header_field = my_callback;
}
Unlike the previous one, C++ solution is much more reliable, because each time your code hits the lambda expression, it emits a new closure object. In both cases, however, the function objects have static storage duration, thus make sure you don't pass any strong pointer in the body of it (otherwise it will never be released).

When should we use two-dimensional pointer in objective c

I want to know when should we use two-dimensional pointer in objective c. I read a article about the runtime mechanism. The implementation details of method objc_msgSend is as follows:
Any NSObject objective has a attribute of isa which will point to the corresponding Class object.
#interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
Class objective is as follows:
struct objc_class {
Class isa;
Class superclass;
const char *name;
uint32_t version;
uint32_t info;
uint32_t instance_size;
struct old_ivar_list *ivars;
struct old_method_list **methodLists; // Method list of the class
Cache cache;
struct old_protocol_list *protocols;
}
The question I want to ask is that why methodLists is two-dimensional pointer, what if we use one-dimensional or do not use pointer, can sb explain this question to me?Thanks in advance.
The struct old_method_list is as below:
struct old_method_list {
void *obsolete;
int method_count;
/* variable length structure */
struct old_method method_list[1]; //The address of the first Method
};
OK, I read another article about why old_method_list use two-dimensional pointer, the reason is that, it may point to an array.My another question is that for struct old_method method_list[1], the comment is "The address of the first Method", but method_list is an old_method array which length is 1. How it can store address?
I solved this question by reading another article.
The array struct old_method method_list[1] is dynamic, it can be changed by adding elements(methods) to it.
Because it points at array of pointers at old_method_list.
Update for old_method_list.
old_method_list * can point not just at old_method_list. It also can point at for example:
struct old_method_list_with_10_methods
{
struct old_method_list list;
struct old_method method_list[9];
};
Or if you need dynamic size:
old_method_list* list = malloc(sizeof(old_method_list) + (n-1) * sizeof(old_method));
list->method_count = n;
It's such variable length structure.

Dynamic allocating an array (dynamic size of the vector implementation)

In the obj-c, we can create vector objects as follows:
SomeClass* example[100];
or
int count[7000];
But what if we know the size of the vector only at the time init the class?
(Maybe we need example[756] or count[15])
First of all, those aren't vector objects, they're compile-time arrays. One of the features of compile time arrays is automatic memory management; that is, you don't have to worry about allocation and deallocation of these arrays.
If you want to create an array whose size you don't know until runtime, you'll need to use new[] and delete[]:
int size = somenumber;
int* arr = new int[size];
// use arr
arr[0] = 4;
// print the first value of arr which is 4
cout << arr[0];
The catch is that after you're done with this array, you have to deallocate it:
delete[] arr;
If you forget to deallocate something created by new with a corresponding delete1, you'll create a memory leak.
You are probably better off using std::vector though because it manages memory for you automatically:
// include the header
#include <vector>
using namespace std; // so we don't have std:: everywhere
vector<int> vec; // create a vector for ints
vec.push_back(4); // add some data
vec.push_back(5);
vec.push_back(6);
// vec now holds 4, 5, and 6
cout << vec[0]; // print the first element of vec which is 4
// we can add as many elements to vec as we want without having to use any
// deallocation functions on it like delete[] or anything
// when vec goes out of scope, it will clean up after itself and you won't have any leaks
1 Make sure you use delete on pointers that you created with new and delete[] on pointers you make with new[x]. Do not mix and match them. Again, if you use std::vector, you don't have to worry about this.
Why not just use an std::vector
//file.mm
#include <vector>
-(void)function
{
std::vector<int> count;
std::vector<SomeClass*> example;
count.push_back(10); // add 10 to the array;
count.resize(20); // make count hold 20 objects
count[10] = 5; //set object at index of 10 to the value of 5
}
Then you do something like:
SomeClass **example = calloc(numClasses, sizeof(SomeClass *));
or:
int *count = malloc(num_of_counts * sizeof(int));
Note that you should:
#include <stdlib.h>
C++ cannot make global/local arrays of a variable size, only dynamic arrays on the heap.
int main() {
int variable = 100;
SomeClass* example = new SomeClass[variable];
//do stuff
delete [] example; //DO NOT FORGET THIS. Better yet, use a std::vector
return 0;
}
I don't know anything about objective-C, but your question is probably only one or the other.

How do you create a pointer to a struct and type cast it?

can someone tell me where I'm going wrong here? I'm trying to create a pointer to the struct aqData that is passed in to the function, and type type cast it to a struct type of AQPlayerState.
I'm getting the errors - Use of undeclared identifier "AQPlayerState" and Expected expression
#implementation AudioPlayer
#define kNumberBuffers 3
struct AQPlayerState {
AudioStreamBasicDescription mDataFormat;
AudioQueueRef mQueue;
AudioQueueBufferRef mBuffers[kNumberBuffers];
AudioFileID mAudioFile;
UInt32 bufferByteSize;
SInt64 mCurrentPacket;
UInt32 mNumPacketsToRead;
AudioStreamPacketDescription *mPacketDescs;
bool mIsRunning;
};
static void HandleOutputBuffer (
void *aqData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer
) {
struct AQPlayerState *pAqData = (AQPlayerState *) aqData;
Thanks in advance for any help
I believe Objective-C behaves as C. If it doesn't this might not apply to Objective-C.
structs in C are recognized by their "full name". Try
struct AQPlayerState *pAqData = (struct AQPlayerState *) aqData;
or, even better, don't cast at all. The C compiler knows how to convert from void* to any other pointer to object
struct AQPlayerState *pAqData = aqData;
implicit conversion: good
explicit conversion (cast): not so good

Class dump and CFObjects

Does class dump get confused by CFObjects/structs? I used class dump on an application and one of the method's argument was a struct arg1 which is a BInstantMessage:
struct BInstantMessage {
void **_field1;
struct CFString _field2;
unsigned short *_field3;
struct DTextStyle _field4;
struct BUser *_field5;
struct BChat *_field6;
};
struct CFString {
void **_vptr$CFObject;
struct __CFString *mCFRef;
_Bool mIsMutable;
};
struct __CFString;
So, how can I get a CFStringRef or NSString* from this arg1? I am guess that class dump is replacing some CFStringRef by CFString definitions, but it's just a guess...
All I want is to get a CFStringRef from arg1 which is a BInstantMessage.
Thnaks!
The application is using a C++ wrapper for Core Foundation objects. the struct CFString in BInstantMessage is an object of this type. You want (NSString *)(arg1._field2.mCFRef).
The void **_vptr$CFObject field is the major hint here – it represents the vtable for a virtual superclass CFObject – combined with the common C++ m prefix naming convention.