Objective C Message Argument Array Parsing (AJNMessageArgument) - ios

I'm working with AllJoyn on iOS using objective C. I'm having trouble parsing an ALLJOYN_ARRAY type in objective C. The problem is that the MsgArg type (C++) is abstracted through the AJNMessagArgument type (objective c). The sample code for parsing an array signature of "a{iv}" in c++ is as follows:
MsgArg *entries;
size_t num;
arg.Get("a{iv}", &num, &entries);
for (size_t i = 0; i > num; ++i) {
char *str1;
char *str2;
uint32_t key;
status = entries[i].Get("{is}", &key, &str1);
if (status == ER_BUS_SIGNATURE_MISMATCH) {
status = entries[i].Get("{i(ss)}", &key, &str1, &str2);
}
}
Now in objective c, the msgarg is the handle of the AJNMessageArgument type. I've tried the following to try getting this to work with no avail:
AJNMessageArgument *strings = [AJNMessageArgument new];
size_t numVals;
QStatus status = [supportedLangsArg value: #"as", &numVals, strings.handle];
if(status != ER_OK){
NSLog(#"ERROR: Could not supported languages from the message argument");
}
This returns ER_OK, but I can't see any data in the handle via the debugger like I can with valid AJNMessageArguments.
Passing in &strings.handle throws a compile error "Address of property expression required".
I've tried quite a few other things, but none make much sense compared to the one above.
Please help me! I need an example of how to parse an "as" signature in objc. I haven't been able to find any docs for this.
Thanks for any help!

Ok, short story is this can't be done without adding custom code to the AJNMessageArgument Class. This is because in this scenario, the "value" method will return a pointer to an array of MsgArg types. Objective C cannot interact with MsgArg - Which is the whole reason they created the AJNMessageArgument wrapper for Objective C.
Here is how it is done:
Add this static method to your AJNMessageArgument.mm class:
+ (NSArray*)getAJNMessageArgumentArrayFromMsgArgArray:(void*)arg : (int)size
{
NSMutableArray * toReturn = [NSMutableArray new];
MsgArg *msgArray = (MsgArg*) arg;
for (int i = 0; i < size; ++i)
{
void * msarg = malloc(sizeof(MsgArg));
MsgArg arg = msgArray[i];
memcpy(msarg, &msgArray[i], sizeof(MsgArg));
AJNMessageArgument *toAdd = [[AJNMessageArgument alloc] initWithHandle:msarg];
[toReturn addObject:toAdd];
}
return [toReturn copy];
}
Don't forget to add the method definition to the AJNMessageArgument.h file:
+ (NSMutableArray*)getAJNMessageArgumentArrayFromMsgArgArray:(void*)arg : (int)size
So now, in our objective C code, we can parse the AJNMessageArgument with signature "as" - but we can't cast it to the MsgArg type yet because we can't access that structure outside of objc++ - so we will use a (void *).
+ (NSArray*)getSupportedLangsFromMessageArgument:(AJNMessageArgument*)supportedLangsArg
{
void *strings; //void * to keep track of MsgArg array data.
size_t numVals;
QStatus status = [supportedLangsArg value: #"as", &numVals, &strings];
if(status != ER_OK){
NSLog(#"ERROR: Could not supported languages from the message argument");
}
NSMutableArray *arrayOfMsgArgs = [AJNMessageArgument getAJNMessageArgumentArrayFromMsgArgArray:strings :numVals];
//Now loop through the resulting AJNMessageArguments of type ALLJOYN_STRING - and parse out the string.
NSMutableArray *arrayOfStrings = [NSMutableArray new];
for (AJNMessageArgument *arg in arrayOfMsgArgs) {
NSString* msgArgValue = [AboutUtil getStringFromMessageArgument:arg];
[arrayOfStrings addObject:msgArgValue];
}
return [arrayOfStrings copy];
}
Now we have an NSArray of NSStrings. Whew.
In case you were wanting to see the code to get the NSString out of the AJNMessageArguments that are in the array, here is that method:
+ (NSString*)getStringFromMessageArgument:(AJNMessageArgument*)msgarg
{
char *charStr;
QStatus status = [msgarg value:#"s", &charStr];
if (status != ER_OK) {
NSLog(#"Error");
}
NSString *str = [NSString stringWithFormat:#"%s", charStr];
return str;
}
Happy AllJoyn-ing.

Related

custom NSExpression functions like sin(x)

I know how to add custom functions to NSNumber for NSExpression to work with it. But for use it i need to declarate a string like "FUNCTION(1, 'sin')". Is is any way to declarate it just like "sin(1)"?
No, you cannot extend the syntax understood by NSExpression(format:).
For advanced expression parsing and evaluating, use 3rd party solutions
such as DDMathParser.
The selected answer is, in my opinion, ridiculous. You can, of course, simply reformat your string to your desired custom function, no need to become dependent on an entire library.
In your case, something like the following would work just fine.
NSString *equation = #"2+sin(54.23+(2+sin(sin(3+5))))-4+(5-3)+cos(4)";//your equation here
NSArray *functionNames = #[#"sin", #"cos", #"tan"];//your supported functions here
for (NSString *functionName in functionNames) {
NSString *functionPrefix = [NSString stringWithFormat:#"%#(", functionName];
while ([equation containsString:functionPrefix]) {
int parensLevel = 1;
int functionParameterIndex = ((int)[equation rangeOfString:functionPrefix].location)+((int)functionPrefix.length);
int characterIndex = functionParameterIndex;
while (characterIndex < equation.length) {
NSString *character = [equation substringWithRange:NSMakeRange(characterIndex, 1)];
if ([character isEqualToString:#"("]) {
parensLevel++;
} else if ([character isEqualToString:#")"]) {
parensLevel--;
}
if (parensLevel == 0) {
break;
}
characterIndex++;
}
if (parensLevel != 0) {
break;//parens weren't balanced, error handle as needed
}
NSString *functionParameter = [equation substringWithRange:NSMakeRange(functionParameterIndex, characterIndex-functionParameterIndex)];
NSString *function = [NSString stringWithFormat:#"%#(%#)", functionName, functionParameter];
equation = [equation stringByReplacingOccurrencesOfString:function withString:[NSString stringWithFormat:#"FUNCTION(%#,'%#')", functionParameter, functionName]];
}
}
//po string = "2+FUNCTION(54.23+(2+FUNCTION(FUNCTION(3+5,'sin'),'sin')),'sin')-4+(5-3)+FUNCTION(4,'cos')"
I wrote this in Objective-C but it works converted to swift as well.

EXC_BAD_ACCESS when converting Objective-C code to Swift

I try to use a Objective-C framework to my project and have some questions when converting Objective-C code to Swift.
One of the APIs:
- (void)ioFrameChannel:(PTChannel*)channel didReceiveFrameOfType:(uint32_t)type tag:(uint32_t)tag payload:(PTData*)payload
payload.data is a struct like this:
typedef struct _PTExampleTextFrame {
uint32_t length;
uint8_t utftext[0];
} PTExampleTextFrame;
I want to get PTExampleTextFrame.utftext which is a message send from the framework
So, I create a local struct:
struct CPTExampleTextFrame {
var length: UInt32
var utf8text: UnsafePointer<UInt8>
}
And write like this:
var textFrame = UnsafePointer<CPTExampleTextFrame>(payload.data).memory
textFrame.length = CFSwapInt32(textFrame.length)
print(textFrame.length) // textFrame.length is correct!
let message = NSString(bytes: textFrame.utf8text, length: Int(textFrame.length), encoding: NSUTF8StringEncoding) // error
print(message)
But I get an error: EXC_BAD_ACCESS(code=1,address=0x31)
Can anyone tell me what's the problem?
And also I give you the framework's example which is in Objective-C:
- (void)ioFrameChannel:(PTChannel*)channel didReceiveFrameOfType:(uint32_t)type tag:(uint32_t)tag payload:(PTData*)payload {
if (type == PTExampleFrameTypeTextMessage) {
PTExampleTextFrame *textFrame = (PTExampleTextFrame*)payload.data;
textFrame->length = ntohl(textFrame->length);
NSString *message = [[NSString alloc] initWithBytes:textFrame->utf8text length:textFrame->length encoding:NSUTF8StringEncoding];
[self appendOutputMessage:[NSString stringWithFormat:#"[%#]: %#", channel.userInfo, message]];
} else if (type == PTExampleFrameTypePing && peerChannel_) {
[peerChannel_ sendFrameOfType:PTExampleFrameTypePong tag:tag withPayload:nil callback:nil];
}
}
Since Objective-C is a superset of C, I'd really recommend that you keep code that interfaces with C as Objective-C code. Interfacing C and Swift directly is an absolute pain.
And an array of char and an unsafe mutable pointer to char are obviously not compatible.
You don't need to create a local struct, it's memory layout is not compatible with c type.
After clarification:
let x: PTExampleTextFrame = UnsafeMutablePointer<PTExampleTextFrame>(payload.data).memory
And use x as you will

ios blocks with different parameters

Iam completely new to ios Blocks and have no idea about the syntax .Iam trying to create a block which takes two parameter one an int and another a NSString and returns an int value. Iam getting error and don't know how to proceed help me with some tutorial or guide me through this is the block .
int (^indexFinder)(int , NSString *) = int (^(int passedValue , NSString * passedText) {};
Do like this:
int (^indexFinder)(int , NSString *) = ^(int a, NSString * b) {
return 10 ;
} ;
int i = indexFinder(1, #"") ;
NSLog(#"%d", i) ;
I learn it from Blocks programming topic
should be like this:
int (^indexFinder)(int , NSString *) = ^int (int passedValue , NSString * passedText) {
NSLog(#">> %d %#",passedValue,passedText);
return 0;
};
indexFinder(0,#"hello");
here are some links that tackles about block: link1, link2

ios 6 and 7 doesnt return same results

It seems that our apps which use getPropertyType(..) are failing under ios7. For whatever reason, getPropertyType(..) on for example a NSString property returns NSString$'\x19\x03\x86\x13 as the type, instead of just NSString, and also instead of NSNumber it returns NSNumber\xf0\x90\xae\x04\xff\xff\xff\xff. All of this is causing some tricky problems when i later on check against a specific type. I have changed this (legacy?) code to use isKindOfClass instead, but it bothers me that I don't understand whats going on here.
The code in question:
#import <objc/runtime.h>
static const char *getPropertyType(objc_property_t property) {
const char *attributes = property_getAttributes(property);
char buffer[1 + strlen(attributes)];
strcpy(buffer, attributes);
char *state = buffer, *attribute;
while ((attribute = strsep(&state, ",")) != NULL) {
if (attribute[0] == 'T') {
return (const char *)[[NSData dataWithBytes:(attribute + 3) length:strlen(attribute) - 4] bytes];
}
}
return "#";
}
What on earth is going on, why are the results different??
The buffer returned by getPropertyType isn't NULL terminated. I think it's only dumb luck that it ever worked. Also, returning the data pointed to by a newly created NSData is not guaranteed to work once that function returns.
I'd make this return an NSString.
NSString* getPropertyType(objc_property_t property) {
const char *attributes = property_getAttributes(property);
char buffer[1 + strlen(attributes)];
strcpy(buffer, attributes);
char *state = buffer, *attribute;
while ((attribute = strsep(&state, ",")) != NULL) {
if (attribute[0] == 'T') {
return [[NSString alloc] initWithBytes:attribute + 3 length:strlen(attribute) - 4 encoding:NSASCIIStringEncoding];
}
}
return #"#";
}
This assumes ARC.
The return value of your method need not be NULL-terminated, as it
points to the internal memory of an NSData object.
This would explain random bytes after your expected output.
Note also that the return value might not point to valid memory at all if the NSData object
is destroyed (which might be at any time after your function returns).

creating a prefix NSString using two NSStrings

I have instructions to make a prefix method that takes two strings for each position where mask = 0 and the first string = second string up until these conditions are not meet that is your prefix NSString.
I made my attempt but for some reason my prefix string is returning as null and I was hoping i could get some help.
here is my method
- (void)prefixCalculation:(NSString *)seriesStart SeriesEnd:(NSString *)seriesEnd {
// call this method when loading the view to get everything set up
NSLog(#"start %#", seriesStart);
NSLog(#"end %#", seriesEnd);
// allocate values so you can use this to create the UITextField
seriesStartString = seriesStart;
seriesEndString = seriesEnd;
// set prefix string
for (int i = 0; i <= seriesStartString.length ; i++) {
unichar c1 = [seriesStartString characterAtIndex:i];
unichar c2 = [seriesEndString characterAtIndex:i];
if (c1 != c2) {
break;
}
else if (c1 == c2) {
NSString *str = [NSString stringWithFormat: #"%C", c1];
[prefixString appendFormat:#"%#",str];
}
}
NSLog(#"prefix %#", prefixString);
}
I am not sure what I am doing wrong but prefixString which is a NSMutableStrong comes back as null, any help would be greatly appreciated.
Since in your code you don't show the initialization of prefixString, I take a guess and suggest you to check whether you initialized it or not.
If that's not the case, prefixString is nil and sending messages to it will fail silently.

Resources