Discussion:
Returning a string value from a c function to a Objective-C class method. Is there an approved approach?
(too old to reply)
Alex Zavatone
2016-03-04 20:07:35 UTC
Permalink
I'm in the middle of some fun where there is a wrapper class to a lib that's written in C and the c function has a char string that I'd like to return back to or somehow pass on to an Cbjective-C class.

I'm sure there is an established practice for performing this type of task, but while I have the opportunity to do this, I'd like to start be learning the right way to handle this operation.

I've seen really poor use of a catch all delegate for this approach, but am pretty unsure on viable and safe methods to handle this.

Any tips to how to handle this?

Thanks in advance,

Alex Zavatone


_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

This email sent to
Doug Hill
2016-03-04 20:48:05 UTC
Permalink
Alex,

I’ve worked on a few wrapper libraries, so I have some experience with this.

In your Obj-C wrapper, you would need to create the NSString yourself. So, if you have a C function:

char* MyCFunc(void);

The Objective-C wrapper method would do something like:

- (void) myObjcMethod
{
char* cStr = MyCFunc();
NSString* objcStr = [[NSString alloc] initWithUTF8String:cStr];

return objCStr;
}

Depending on the C function implementation, you might have to deal with releasing the C string in your wrapper. Also, I assume UTF-8 encoding, which may or may not be true.

Hopefully this helps you.

Doug Hill
Post by Alex Zavatone
I'm in the middle of some fun where there is a wrapper class to a lib that's written in C and the c function has a char string that I'd like to return back to or somehow pass on to an Cbjective-C class.
I'm sure there is an established practice for performing this type of task, but while I have the opportunity to do this, I'd like to start be learning the right way to handle this operation.
I've seen really poor use of a catch all delegate for this approach, but am pretty unsure on viable and safe methods to handle this.
Any tips to how to handle this?
Thanks in advance,
Alex Zavatone
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-i
Alex Zavatone
2016-03-04 21:14:45 UTC
Permalink
Great! It certainly does… but here's where my brain breaks.

The call is originating from the C lib and within the C function. I am not calling the C function from Objective-C.

I'm looking at somehow passing this as a string (UTF-8, yep) back to an OC class instance, so this implies either a callback or some reference to the OC instance that that cares about the response and a means to get that message to it.

If this is as simple as setting up a callback or a pointer reference, from the c class to the OC instance? Is it sane programming for the C class to have more than one callback to different OC object instances?

I was thinking one for data and one for method calls for organizational purposes.

Or should there be one layer that serves as a clearly defined API to create a walled garden between the OC world and the C interface to the compiled C lib?

I'm working with PJSIP and PJ's docs clearly state, "we are going to crater unless you do everything SIP related on the main thread." The code that I am rewriting replacing has nasty try/catch clauses and forces many operations to the main thread just in case they call PJSIP operations - which clearly makes for a sucky user experience and really clunky application architecture.

I'm looking to avoid that nastiness by starting from ground zero so that we can wrap a solidly conceived architecture around a neatly walled off interface layer to PJSIP.


Would it make sense to send a notification from the C method to an Objective-C object to get the value from the C class? Then I'd need to worry about storing it, that seems clunky and too involved just to return a string.

Thank you, sir. Loads for me to learn here.

Alex Zavatone
Post by Doug Hill
Alex,
I’ve worked on a few wrapper libraries, so I have some experience with this.
char* MyCFunc(void);
- (void) myObjcMethod
{
char* cStr = MyCFunc();
NSString* objcStr = [[NSString alloc] initWithUTF8String:cStr];
return objCStr;
}
Depending on the C function implementation, you might have to deal with releasing the C string in your wrapper. Also, I assume UTF-8 encoding, which may or may not be true.
Hopefully this helps you.
Doug Hill
Post by Alex Zavatone
I'm in the middle of some fun where there is a wrapper class to a lib that's written in C and the c function has a char string that I'd like to return back to or somehow pass on to an Cbjective-C class.
I'm sure there is an established practice for performing this type of task, but while I have the opportunity to do this, I'd like to start be learning the right way to handle this operation.
I've seen really poor use of a catch all delegate for this approach, but am pretty unsure on viable and safe methods to handle this.
Any tips to how to handle this?
Thanks in advance,
Alex Zavatone
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

This email sent to ***@ml-in.narki
Doug Hill
2016-03-04 22:11:01 UTC
Permalink
The approach I took for my wrapper library was using bindings. Not the Cocoa type, but the language type. I created a series of Objective-C classes that serve as the Obj-C interface to the Cocoa developer. The Obj-C classes would make calls into the C/C++ libraries and do conversions between C/C++ types to Obj-C. For example the C-string to NSString conversion. This way, a convenient Objective-C framework could be created that Cocoa developers could use very easily. C arrays were converted to Foundation NSArrays, etc. There was also conversions of C++ exceptions to Obj-C exceptions, although this might be unified in CLang/LLVM.
Since I was wrapping a C++ library, I made up some special bindings that allowed me to call into C++ objects via templates and some special sauce that allowed us to store method pointers and call into them from any platform/language. This is probably more work than is needed though.

Anyways, I didn’t use delegates, notifications, etc. The easiest way to integrate these wrappers into your app is to have a pure Objective-C interface and do all work inside those, but probably the most effort to write.

Doug Hill
Post by Alex Zavatone
Great! It certainly does… but here's where my brain breaks.
The call is originating from the C lib and within the C function. I am not calling the C function from Objective-C.
I'm looking at somehow passing this as a string (UTF-8, yep) back to an OC class instance, so this implies either a callback or some reference to the OC instance that that cares about the response and a means to get that message to it.
If this is as simple as setting up a callback or a pointer reference, from the c class to the OC instance? Is it sane programming for the C class to have more than one callback to different OC object instances?
I was thinking one for data and one for method calls for organizational purposes.
Or should there be one layer that serves as a clearly defined API to create a walled garden between the OC world and the C interface to the compiled C lib?
I'm working with PJSIP and PJ's docs clearly state, "we are going to crater unless you do everything SIP related on the main thread." The code that I am rewriting replacing has nasty try/catch clauses and forces many operations to the main thread just in case they call PJSIP operations - which clearly makes for a sucky user experience and really clunky application architecture.
I'm looking to avoid that nastiness by starting from ground zero so that we can wrap a solidly conceived architecture around a neatly walled off interface layer to PJSIP.
Would it make sense to send a notification from the C method to an Objective-C object to get the value from the C class? Then I'd need to worry about storing it, that seems clunky and too involved just to return a string.
Thank you, sir. Loads for me to learn here.
Alex Zavatone
Post by Doug Hill
Alex,
I’ve worked on a few wrapper libraries, so I have some experience with this.
char* MyCFunc(void);
- (void) myObjcMethod
{
char* cStr = MyCFunc();
NSString* objcStr = [[NSString alloc] initWithUTF8String:cStr];
return objCStr;
}
Depending on the C function implementation, you might have to deal with releasing the C string in your wrapper. Also, I assume UTF-8 encoding, which may or may not be true.
Hopefully this helps you.
Doug Hill
Post by Alex Zavatone
I'm in the middle of some fun where there is a wrapper class to a lib that's written in C and the c function has a char string that I'd like to return back to or somehow pass on to an Cbjective-C class.
I'm sure there is an established practice for performing this type of task, but while I have the opportunity to do this, I'd like to start be learning the right way to handle this operation.
I've seen really poor use of a catch all delegate for this approach, but am pretty unsure on viable and safe methods to handle this.
Any tips to how to handle this?
Thanks in advance,
Alex Zavatone
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

This email sent to ***@ml-in
Alex Zavatone
2016-03-04 23:36:39 UTC
Permalink
I guess I neglected to mention this was on iOS.

Your words make me happy to see that I’m at least thinking along a similar line. Basically, your class is a glue layer or a translation layer between the C and Obj-C worlds.

Now, I love the concept of bindings, but iOS, since bindings aren’t available, how would you suggest I approach the issue of the C method knowing the appropriate Obj-C class to provide the response to.

I’m afraid I’ve been insulated from the world of pointers in my time on iOS, so I’m not rusty there, more than I am ignorant to those issues.

Thanks,

Alex Zavatone
Post by Doug Hill
The approach I took for my wrapper library was using bindings. Not the Cocoa type, but the language type. I created a series of Objective-C classes that serve as the Obj-C interface to the Cocoa developer. The Obj-C classes would make calls into the C/C++ libraries and do conversions between C/C++ types to Obj-C. For example the C-string to NSString conversion. This way, a convenient Objective-C framework could be created that Cocoa developers could use very easily. C arrays were converted to Foundation NSArrays, etc. There was also conversions of C++ exceptions to Obj-C exceptions, although this might be unified in CLang/LLVM.
Since I was wrapping a C++ library, I made up some special bindings that allowed me to call into C++ objects via templates and some special sauce that allowed us to store method pointers and call into them from any platform/language. This is probably more work than is needed though.
Anyways, I didn’t use delegates, notifications, etc. The easiest way to integrate these wrappers into your app is to have a pure Objective-C interface and do all work inside those, but probably the most effort to write.
Doug Hill
Post by Alex Zavatone
Great! It certainly does… but here's where my brain breaks.
The call is originating from the C lib and within the C function. I am not calling the C function from Objective-C.
I'm looking at somehow passing this as a string (UTF-8, yep) back to an OC class instance, so this implies either a callback or some reference to the OC instance that that cares about the response and a means to get that message to it.
If this is as simple as setting up a callback or a pointer reference, from the c class to the OC instance? Is it sane programming for the C class to have more than one callback to different OC object instances?
I was thinking one for data and one for method calls for organizational purposes.
Or should there be one layer that serves as a clearly defined API to create a walled garden between the OC world and the C interface to the compiled C lib?
I'm working with PJSIP and PJ's docs clearly state, "we are going to crater unless you do everything SIP related on the main thread." The code that I am rewriting replacing has nasty try/catch clauses and forces many operations to the main thread just in case they call PJSIP operations - which clearly makes for a sucky user experience and really clunky application architecture.
I'm looking to avoid that nastiness by starting from ground zero so that we can wrap a solidly conceived architecture around a neatly walled off interface layer to PJSIP.
Would it make sense to send a notification from the C method to an Objective-C object to get the value from the C class? Then I'd need to worry about storing it, that seems clunky and too involved just to return a string.
Thank you, sir. Loads for me to learn here.
Alex Zavatone
Post by Doug Hill
Alex,
I’ve worked on a few wrapper libraries, so I have some experience with this.
char* MyCFunc(void);
- (void) myObjcMethod
{
char* cStr = MyCFunc();
NSString* objcStr = [[NSString alloc] initWithUTF8String:cStr];
return objCStr;
}
Depending on the C function implementation, you might have to deal with releasing the C string in your wrapper. Also, I assume UTF-8 encoding, which may or may not be true.
Hopefully this helps you.
Doug Hill
Post by Alex Zavatone
I'm in the middle of some fun where there is a wrapper class to a lib that's written in C and the c function has a char string that I'd like to return back to or somehow pass on to an Cbjective-C class.
I'm sure there is an established practice for performing this type of task, but while I have the opportunity to do this, I'd like to start be learning the right way to handle this operation.
I've seen really poor use of a catch all delegate for this approach, but am pretty unsure on viable and safe methods to handle this.
Any tips to how to handle this?
Thanks in advance,
Alex Zavatone
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

This email
Doug Hill
2016-03-05 02:17:09 UTC
Permalink
Alex,

I guess I tried to make the distinction between Cocoa Bindings and language bindings, but I was referring to this.

https://en.wikipedia.org/wiki/Language_binding <https://en.wikipedia.org/wiki/Language_binding>

This is a general concept to bridge multiple languages.

The idea is that none of the bindings are automatic, you have to write them yourself. So, you would need to analyze the C library and figure out a set of interfaces in Objective-C that gives Obj-C developers access to that library.

Just as a hypothetical example (as I don’t have the knowledge or time to look up the SIP library you mentioned), let’s say the C library had the following functions:

SIPRef CreateSIPRef(void);
void DialNumber(SIPRef sipRef, char *phoneNumber);

Then your Objective-C interface would be something like:

@interface SIPDialer

@private
SIPRef privSIPRef;

- (instancetype) init;
- (void) dialNumber( NSString *phoneNumber);
@end

The implementation would do something like:

@implementation SIPDialer

- (instancetype) init
{
self = [super init];
if( self )
{
self.privSIPRef = CreateSIPRef();
}
return self;
}

- (void) dialNumber( NSString *phoneNumber)
{
char *cStrPhoneNumber = [phoneNumber cStringUsingEncoding: NSUTF8StringEncoding];
DialNumber( self.privSIPRef, cStrPhoneNumber);
}

@end

I think you get the general idea (ignore any typos or syntax errors, I’m just typing in my email here). Obviously you would also have to deal with all kinds of error handling and possibly exception handling.

Good luck!

Doug Hill
Post by Alex Zavatone
I guess I neglected to mention this was on iOS.
Your words make me happy to see that I’m at least thinking along a similar line. Basically, your class is a glue layer or a translation layer between the C and Obj-C worlds.
Now, I love the concept of bindings, but iOS, since bindings aren’t available, how would you suggest I approach the issue of the C method knowing the appropriate Obj-C class to provide the response to.
I’m afraid I’ve been insulated from the world of pointers in my time on iOS, so I’m not rusty there, more than I am ignorant to those issues.
Thanks,
Alex Zavatone
Post by Doug Hill
The approach I took for my wrapper library was using bindings. Not the Cocoa type, but the language type. I created a series of Objective-C classes that serve as the Obj-C interface to the Cocoa developer. The Obj-C classes would make calls into the C/C++ libraries and do conversions between C/C++ types to Obj-C. For example the C-string to NSString conversion. This way, a convenient Objective-C framework could be created that Cocoa developers could use very easily. C arrays were converted to Foundation NSArrays, etc. There was also conversions of C++ exceptions to Obj-C exceptions, although this might be unified in CLang/LLVM.
Since I was wrapping a C++ library, I made up some special bindings that allowed me to call into C++ objects via templates and some special sauce that allowed us to store method pointers and call into them from any platform/language. This is probably more work than is needed though.
Anyways, I didn’t use delegates, notifications, etc. The easiest way to integrate these wrappers into your app is to have a pure Objective-C interface and do all work inside those, but probably the most effort to write.
Doug Hill
Post by Alex Zavatone
Great! It certainly does… but here's where my brain breaks.
The call is originating from the C lib and within the C function. I am not calling the C function from Objective-C.
I'm looking at somehow passing this as a string (UTF-8, yep) back to an OC class instance, so this implies either a callback or some reference to the OC instance that that cares about the response and a means to get that message to it.
If this is as simple as setting up a callback or a pointer reference, from the c class to the OC instance? Is it sane programming for the C class to have more than one callback to different OC object instances?
I was thinking one for data and one for method calls for organizational purposes.
Or should there be one layer that serves as a clearly defined API to create a walled garden between the OC world and the C interface to the compiled C lib?
I'm working with PJSIP and PJ's docs clearly state, "we are going to crater unless you do everything SIP related on the main thread." The code that I am rewriting replacing has nasty try/catch clauses and forces many operations to the main thread just in case they call PJSIP operations - which clearly makes for a sucky user experience and really clunky application architecture.
I'm looking to avoid that nastiness by starting from ground zero so that we can wrap a solidly conceived architecture around a neatly walled off interface layer to PJSIP.
Would it make sense to send a notification from the C method to an Objective-C object to get the value from the C class? Then I'd need to worry about storing it, that seems clunky and too involved just to return a string.
Thank you, sir. Loads for me to learn here.
Alex Zavatone
Post by Doug Hill
Alex,
I’ve worked on a few wrapper libraries, so I have some experience with this.
char* MyCFunc(void);
- (void) myObjcMethod
{
char* cStr = MyCFunc();
NSString* objcStr = [[NSString alloc] initWithUTF8String:cStr];
return objCStr;
}
Depending on the C function implementation, you might have to deal with releasing the C string in your wrapper. Also, I assume UTF-8 encoding, which may or may not be true.
Hopefully this helps you.
Doug Hill
Post by Alex Zavatone
I'm in the middle of some fun where there is a wrapper class to a lib that's written in C and the c function has a char string that I'd like to return back to or somehow pass on to an Cbjective-C class.
I'm sure there is an established practice for performing this type of task, but while I have the opportunity to do this, I'd like to start be learning the right way to handle this operation.
I've seen really poor use of a catch all delegate for this approach, but am pretty unsure on viable and safe methods to handle this.
Any tips to how to handle this?
Thanks in advance,
Alex Zavatone
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

This email sen
Jonathan Mitchell
2016-03-04 22:24:35 UTC
Permalink
Hi Alex

Not sure if this will help at all as I am not 100% sure what you are doing.
In my case, using Mono, I needed to track events being raised in the Mono C runtime back into Obj-C space.
You need some method of defining a call back function in the target C Api - without that thinks would look rather bleak.

Basically the C Mono runtime is configured to a call static C function in an Obj C .m file in response to a C# managed event firing.
The static then calls a static method on an Obj-C class.
This Obj-C static uses collections to track registered events and invokes performSelector: on a registered Obj-C target.
See here:
https://github.com/ThesaurusSoftware/Dubrovnik/blob/master/Framework/XCode/Representations/DBManagedEvent.m

One of the arguments based in as part of the event callback is a pointer that is used as a a key to retrieve the target NSObject.
This is complicated by the fact that the incoming pointer represents a moveable memory location so there is some extra indirection too.
https://github.com/ThesaurusSoftware/Dubrovnik/blob/master/Framework/XCode/Representations/DBPrimaryInstanceCache.m

This can get a bit complex but its all doable.

Jonathan
Post by Alex Zavatone
Great! It certainly does… but here's where my brain breaks.
The call is originating from the C lib and within the C function. I am not calling the C function from Objective-C.
I'm looking at somehow passing this as a string (UTF-8, yep) back to an OC class instance, so this implies either a callback or some reference to the OC instance that that cares about the response and a means to get that message to it.
If this is as simple as setting up a callback or a pointer reference, from the c class to the OC instance? Is it sane programming for the C class to have more than one callback to different OC object instances?
I was thinking one for data and one for method calls for organizational purposes.
Or should there be one layer that serves as a clearly defined API to create a walled garden between the OC world and the C interface to the compiled C lib?
I'm working with PJSIP and PJ's docs clearly state, "we are going to crater unless you do everything SIP related on the main thread." The code that I am rewriting replacing has nasty try/catch clauses and forces many operations to the main thread just in case they call PJSIP operations - which clearly makes for a sucky user experience and really clunky application architecture.
I'm looking to avoid that nastiness by starting from ground zero so that we can wrap a solidly conceived architecture around a neatly walled off interface layer to PJSIP.
Would it make sense to send a notification from the C method to an Objective-C object to get the value from the C class? Then I'd need to worry about storing it, that seems clunky and too involved just to return a string.
Thank you, sir. Loads for me to learn here.
Alex Zavatone
Post by Doug Hill
Alex,
I’ve worked on a few wrapper libraries, so I have some experience with this.
char* MyCFunc(void);
- (void) myObjcMethod
{
char* cStr = MyCFunc();
NSString* objcStr = [[NSString alloc] initWithUTF8String:cStr];
return objCStr;
}
Depending on the C function implementation, you might have to deal with releasing the C string in your wrapper. Also, I assume UTF-8 encoding, which may or may not be true.
Hopefully this helps you.
Doug Hill
Post by Alex Zavatone
I'm in the middle of some fun where there is a wrapper class to a lib that's written in C and the c function has a char string that I'd like to return back to or somehow pass on to an Cbjective-C class.
I'm sure there is an established practice for performing this type of task, but while I have the opportunity to do this, I'd like to start be learning the right way to handle this operation.
I've seen really poor use of a catch all delegate for this approach, but am pretty unsure on viable and safe methods to handle this.
Any tips to how to handle this?
Thanks in advance,
Alex Zavatone
_______________________________________________
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
https://lists.apple.com/mailman/options/cocoa-dev/lists%40mugginsoft.com
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in
Alex Zavatone
2016-03-04 23:42:08 UTC
Permalink
Post by Jonathan Mitchell
Hi Alex
Not sure if this will help at all as I am not 100% sure what you are doing.
In my case, using Mono, I needed to track events being raised in the Mono C runtime back into Obj-C space.
You need some method of defining a call back function in the target C Api - without that thinks would look rather bleak.
Yes, this is exactly what I am a looking at figuring out.
Post by Jonathan Mitchell
Basically the C Mono runtime is configured to a call static C function in an Obj C .m file in response to a C# managed event firing.
The static then calls a static method on an Obj-C class.
This Obj-C static uses collections to track registered events and invokes performSelector: on a registered Obj-C target.
https://github.com/ThesaurusSoftware/Dubrovnik/blob/master/Framework/XCode/Representations/DBManagedEvent.m
Bingo. That is what I need to read.
Post by Jonathan Mitchell
One of the arguments based in as part of the event callback is a pointer that is used as a a key to retrieve the target NSObject.
This is complicated by the fact that the incoming pointer represents a moveable memory location so there is some extra indirection too.
https://github.com/ThesaurusSoftware/Dubrovnik/blob/master/Framework/XCode/Representations/DBPrimaryInstanceCache.m
This can get a bit complex but its all doable.
Jonathan
Wonderful. I believe you’ve outlined the issues that I will be facing and need to be aware of. I already have some samples that I didn’t know were doing part of what you’ve outlined, but I had no idea that’s how it was being done due to my ignorance of C matters.

Well, now I know what I’ll be doing this weekend.

Thanks, Jonathan. You and Doug are certainly pointing me in the direction I need to be header.

Alex Zavatone
Post by Jonathan Mitchell
Post by Alex Zavatone
Great! It certainly does… but here's where my brain breaks.
The call is originating from the C lib and within the C function. I am not calling the C function from Objective-C.
I'm looking at somehow passing this as a string (UTF-8, yep) back to an OC class instance, so this implies either a callback or some reference to the OC instance that that cares about the response and a means to get that message to it.
If this is as simple as setting up a callback or a pointer reference, from the c class to the OC instance? Is it sane programming for the C class to have more than one callback to different OC object instances?
I was thinking one for data and one for method calls for organizational purposes.
Or should there be one layer that serves as a clearly defined API to create a walled garden between the OC world and the C interface to the compiled C lib?
I'm working with PJSIP and PJ's docs clearly state, "we are going to crater unless you do everything SIP related on the main thread." The code that I am rewriting replacing has nasty try/catch clauses and forces many operations to the main thread just in case they call PJSIP operations - which clearly makes for a sucky user experience and really clunky application architecture.
I'm looking to avoid that nastiness by starting from ground zero so that we can wrap a solidly conceived architecture around a neatly walled off interface layer to PJSIP.
Would it make sense to send a notification from the C method to an Objective-C object to get the value from the C class? Then I'd need to worry about storing it, that seems clunky and too involved just to return a string.
Thank you, sir. Loads for me to learn here.
Alex Zavatone
Post by Doug Hill
Alex,
I’ve worked on a few wrapper libraries, so I have some experience with this.
char* MyCFunc(void);
- (void) myObjcMethod
{
char* cStr = MyCFunc();
NSString* objcStr = [[NSString alloc] initWithUTF8String:cStr];
return objCStr;
}
Depending on the C function implementation, you might have to deal with releasing the C string in your wrapper. Also, I assume UTF-8 encoding, which may or may not be true.
Hopefully this helps you.
Doug Hill
Post by Alex Zavatone
I'm in the middle of some fun where there is a wrapper class to a lib that's written in C and the c function has a char string that I'd like to return back to or somehow pass on to an Cbjective-C class.
I'm sure there is an established practice for performing this type of task, but while I have the opportunity to do this, I'd like to start be learning the right way to handle this operation.
I've seen really poor use of a catch all delegate for this approach, but am pretty unsure on viable and safe methods to handle this.
Any tips to how to handle this?
Thanks in advance,
Alex Zavatone
_______________________________________________
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
https://lists.apple.com/mailman/options/cocoa-dev/lists%40mugginsoft.com
_______________________________________________
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
https://lists.apple.com/mailman/options/cocoa-dev/zav%40mac.com
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkiv
Alex Zavatone
2016-03-07 19:41:24 UTC
Permalink
Just a formal note:

You guys are awesome.

THANK YOU.

I've got a .m file that serves as a C and Objective-C layer (glue layer?) to the library methods.

In it, I have one id that is the reference back to the object itself.

Each static C function that returns data, constructs an Objective-C friendly data type and passes it on to the C method's equivalent Objective-C partner.

This then pipes data off somewhere else and the chain drops.

Observers are set up in classes that care about the data and react to the change, taking it and storing it or further processing it as needed. If classes need to execute any of the functions within the API they can be called from Objective-C methods that wrap the corresponding C code and callbacks are handled in a block.

These C functions call the .a files' API and respond to its messages just like they are supposed to.

Now, to flesh this all out. Thanks again.

- Alex Zavatone



_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

This email sent to ***@ml
Greg Parker
2016-03-05 00:03:21 UTC
Permalink
Post by Jonathan Mitchell
Hi Alex
Not sure if this will help at all as I am not 100% sure what you are doing.
In my case, using Mono, I needed to track events being raised in the Mono C runtime back into Obj-C space.
You need some method of defining a call back function in the target C Api - without that thinks would look rather bleak.
Basically the C Mono runtime is configured to a call static C function in an Obj C .m file in response to a C# managed event firing.
The static then calls a static method on an Obj-C class.
This Obj-C static uses collections to track registered events and invokes performSelector: on a registered Obj-C target.
https://github.com/ThesaurusSoftware/Dubrovnik/blob/master/Framework/XCode/Representations/DBManagedEvent.m
One of the arguments based in as part of the event callback is a pointer that is used as a a key to retrieve the target NSObject.
This is complicated by the fact that the incoming pointer represents a moveable memory location so there is some extra indirection too.
https://github.com/ThesaurusSoftware/Dubrovnik/blob/master/Framework/XCode/Representations/DBPrimaryInstanceCache.m
This can get a bit complex but its all doable.
Block objects can help. clang supports block objects in plain C code (-fblocks, I think). Your Objective-C code can create a block object that performs the callback and pass it to the C code to store and call. The block object would capture the target NSObject so you don't need the dictionary of callback targets.
--
Greg Parker ***@apple.com Runtime Wrangler



_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

This email sent to ***@ml-in.
John McCall
2016-03-05 00:06:31 UTC
Permalink
Post by Greg Parker
Post by Jonathan Mitchell
Hi Alex
Not sure if this will help at all as I am not 100% sure what you are doing.
In my case, using Mono, I needed to track events being raised in the Mono C runtime back into Obj-C space.
You need some method of defining a call back function in the target C Api - without that thinks would look rather bleak.
Basically the C Mono runtime is configured to a call static C function in an Obj C .m file in response to a C# managed event firing.
The static then calls a static method on an Obj-C class.
This Obj-C static uses collections to track registered events and invokes performSelector: on a registered Obj-C target.
https://github.com/ThesaurusSoftware/Dubrovnik/blob/master/Framework/XCode/Representations/DBManagedEvent.m
One of the arguments based in as part of the event callback is a pointer that is used as a a key to retrieve the target NSObject.
This is complicated by the fact that the incoming pointer represents a moveable memory location so there is some extra indirection too.
https://github.com/ThesaurusSoftware/Dubrovnik/blob/master/Framework/XCode/Representations/DBPrimaryInstanceCache.m
This can get a bit complex but its all doable.
Block objects can help. clang supports block objects in plain C code (-fblocks, I think).
They're just enabled by default on our platform in all language modes.

John.
Post by Greg Parker
Your Objective-C code can create a block object that performs the callback and pass it to the C code to store and call. The block object would capture the target NSObject so you don't need the dictionary of callback targets.
--
_______________________________________________
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
https://lists.apple.com/mailman/options/cocoa-dev/rjmccall%40apple.com
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.n
Alex Zavatone
2016-03-08 20:59:57 UTC
Permalink
I just discovered that using KVO to get this returned value that is stored as a copied property within the class that is C & Obj-C is a really bad idea.

When I access the data through KVO from the VC that created the call to instantiate the lib that returns the C to Obj-C value, it's no problem, but moving the observing into a separate class results in a sigabrt when the observed value changes.

So, I'm assuming that KVO is out of the picture if I am to actually use the value that I am returning from C to Objective-C.

I'm browsing the Dubrovnik classes now to see the it handles returning the data now and am thinking of using another Obj-C object to register itself to have the data I care about sent to it.

Yeah, it's getting complex, that's for sure.
Post by John McCall
Post by Greg Parker
Post by Jonathan Mitchell
Hi Alex
Not sure if this will help at all as I am not 100% sure what you are doing.
In my case, using Mono, I needed to track events being raised in the Mono C runtime back into Obj-C space.
You need some method of defining a call back function in the target C Api - without that thinks would look rather bleak.
Basically the C Mono runtime is configured to a call static C function in an Obj C .m file in response to a C# managed event firing.
The static then calls a static method on an Obj-C class.
This Obj-C static uses collections to track registered events and invokes performSelector: on a registered Obj-C target.
https://github.com/ThesaurusSoftware/Dubrovnik/blob/master/Framework/XCode/Representations/DBManagedEvent.m
One of the arguments based in as part of the event callback is a pointer that is used as a a key to retrieve the target NSObject.
This is complicated by the fact that the incoming pointer represents a moveable memory location so there is some extra indirection too.
https://github.com/ThesaurusSoftware/Dubrovnik/blob/master/Framework/XCode/Representations/DBPrimaryInstanceCache.m
This can get a bit complex but its all doable.
Block objects can help. clang supports block objects in plain C code (-fblocks, I think).
They're just enabled by default on our platform in all language modes.
John.
Post by Greg Parker
Your Objective-C code can create a block object that performs the callback and pass it to the C code to store and call. The block object would capture the target NSObject so you don't need the dictionary of callback targets.
--
_______________________________________________
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
https://lists.apple.com/mailman/options/cocoa-dev/rjmccall%40apple.com
_______________________________________________
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
https://lists.apple.com/mailman/options/cocoa-dev/zav%40mac.com
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

This email sent to ***@ml-in.narkive.
Jonathan Mitchell
2016-03-08 21:16:55 UTC
Permalink
Alex
Post by Alex Zavatone
I'm browsing the Dubrovnik classes now to see the it handles returning the data now and am thinking of using another Obj-C object to register itself to have the data I care about sent to it.
KVO is very particular about the occurrence and sequencing of the willChangeValueForKey: and didChangeValueForKey: methods. Get it right and joy Reigns. Get it wrong and well…

It can tolerate some missing calls on the end component of a key path but a failure higher up a key path chain is usually fatal. Of course there are potential memory issues too. The objects in an observed key path need to stick around while the observation is live.

In Dubrovnik I translate the managed INotifyPropertyChanging and INotifyPropertyChanged interface events into their KVO equivalents. I incorporated a simple tracking mechanism that fired out warnings if an anomaly in the KVO xxxChangeValueForKey: sequencing occurred.

It took a bit of time to get the kinks out of it all but in the end I have a system that works reliably and enables me to bind many hundreds of NSControl instances to properties of .Net managed classes.

So the KVO route may not be dead, just wounded. In my case to get things sweet I had to disable automatic KVO notifications. For regular Cocoa classes auto KVO is the way to go but if you need more precise control maybe not.

J
Post by Alex Zavatone
Yeah, it's getting complex, that's for sure.
Post by John McCall
Post by Greg Parker
Post by Jonathan Mitchell
Hi Alex
Not sure if this will help at all as I am not 100% sure what you are doing.
In my case, using Mono, I needed to track events being raised in the Mono C runtime back into Obj-C space.
You need some method of defining a call back function in the target C Api - without that thinks would look rather bleak.
Basically the C Mono runtime is configured to a call static C function in an Obj C .m file in response to a C# managed event firing.
The static then calls a static method on an Obj-C class.
This Obj-C static uses collections to track registered events and invokes performSelector: on a registered Obj-C target.
https://github.com/ThesaurusSoftware/Dubrovnik/blob/master/Framework/XCode/Representations/DBManagedEvent.m
One of the arguments based in as part of the event callback is a pointer that is used as a a key to retrieve the target NSObject.
This is complicated by the fact that the incoming pointer represents a moveable memory location so there is some extra indirection too.
https://github.com/ThesaurusSoftware/Dubrovnik/blob/master/Framework/XCode/Representations/DBPrimaryInstanceCache.m
This can get a bit complex but its all doable.
Block objects can help. clang supports block objects in plain C code (-fblocks, I think).
They're just enabled by default on our platform in all language modes.
John.
Post by Greg Parker
Your Objective-C code can create a block object that performs the callback and pass it to the C code to store and call. The block object would capture the target NSObject so you don't need the dictionary of callback targets.
--
_______________________________________________
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
https://lists.apple.com/mailman/options/cocoa-dev/rjmccall%40apple.com
_______________________________________________
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
https://lists.apple.com/mailman/options/cocoa-dev/zav%40mac.com
_______________________________________________
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
https://lists.apple.com/mailman/options/cocoa-dev/lists%40mugginsoft.com
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.
Alex Zavatone
2016-03-08 22:38:56 UTC
Permalink
Super lovely code Jonathan. My feeble brain ended up seeing if a delegate pattern would resolve this issue and it did.

The trick I am trying to achieve is simply "get the data out of the C class, the C/Obj-C glue and dump it into a more friendly structure to expose the data.

Having the data container register a weak reference with the C/Obj-C glue class and then letting the data sit there and be observed by a view controller gets me where I need to be now.

Ahh yes, hard mode is hard.

Thanks again.
Post by Jonathan Mitchell
Alex
Post by Alex Zavatone
I'm browsing the Dubrovnik classes now to see the it handles returning the data now and am thinking of using another Obj-C object to register itself to have the data I care about sent to it.
KVO is very particular about the occurrence and sequencing of the willChangeValueForKey: and didChangeValueForKey: methods. Get it right and joy Reigns. Get it wrong and well…
It can tolerate some missing calls on the end component of a key path but a failure higher up a key path chain is usually fatal. Of course there are potential memory issues too. The objects in an observed key path need to stick around while the observation is live.
In Dubrovnik I translate the managed INotifyPropertyChanging and INotifyPropertyChanged interface events into their KVO equivalents. I incorporated a simple tracking mechanism that fired out warnings if an anomaly in the KVO xxxChangeValueForKey: sequencing occurred.
It took a bit of time to get the kinks out of it all but in the end I have a system that works reliably and enables me to bind many hundreds of NSControl instances to properties of .Net managed classes.
So the KVO route may not be dead, just wounded. In my case to get things sweet I had to disable automatic KVO notifications. For regular Cocoa classes auto KVO is the way to go but if you need more precise control maybe not.
J
Post by Alex Zavatone
Yeah, it's getting complex, that's for sure.
Post by John McCall
Post by Greg Parker
Post by Jonathan Mitchell
Hi Alex
Not sure if this will help at all as I am not 100% sure what you are doing.
In my case, using Mono, I needed to track events being raised in the Mono C runtime back into Obj-C space.
You need some method of defining a call back function in the target C Api - without that thinks would look rather bleak.
Basically the C Mono runtime is configured to a call static C function in an Obj C .m file in response to a C# managed event firing.
The static then calls a static method on an Obj-C class.
This Obj-C static uses collections to track registered events and invokes performSelector: on a registered Obj-C target.
https://github.com/ThesaurusSoftware/Dubrovnik/blob/master/Framework/XCode/Representations/DBManagedEvent.m
One of the arguments based in as part of the event callback is a pointer that is used as a a key to retrieve the target NSObject.
This is complicated by the fact that the incoming pointer represents a moveable memory location so there is some extra indirection too.
https://github.com/ThesaurusSoftware/Dubrovnik/blob/master/Framework/XCode/Representations/DBPrimaryInstanceCache.m
This can get a bit complex but its all doable.
Block objects can help. clang supports block objects in plain C code (-fblocks, I think).
They're just enabled by default on our platform in all language modes.
John.
Post by Greg Parker
Your Objective-C code can create a block object that performs the callback and pass it to the C code to store and call. The block object would capture the target NSObject so you don't need the dictionary of callback targets.
--
_______________________________________________
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
https://lists.apple.com/mailman/options/cocoa-dev/rjmccall%40apple.com
_______________________________________________
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
https://lists.apple.com/mailman/options/cocoa-dev/zav%40mac.com
_______________________________________________
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
https://lists.apple.com/mailman/options/cocoa-dev/lists%40mugginsoft.com
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in

Steve Sisak
2016-03-05 00:25:24 UTC
Permalink
Post by Alex Zavatone
I'm working with PJSIP and PJ's docs clearly state, "we are going to crater unless you do everything SIP related on the main thread."
Ugh. And of course, doing networking on the main thread is a no-no according to Apple.

——

First, it might be worth seeing if you can have a PJSIP queue (preferred) or thread, which isn’t the main thread — if there are no locks in PJSIP, but it doesn’t use thread-local storage, then it only need to be protected from reentrancy — then you can just make all your PJSIP calls from blocks wrapped in dispatch_async on the PJSIP queue. Thread-local storage complicates this. But I digress…

——

How is the storage of your C strings allocated? malloc()?

What I’d do is use CFString (from CoreFoundation, which is a C API and does all the right callback stuff) and take advantage of the fact the CFString is toll-free bridged to NSString.

Now your C code returns a CFString (C API) which can be cast to NSString as soon at it hits Obj-C code.

HTH,

-Steve



_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.nar
Continue reading on narkive:
Loading...