TheJeff TheJeff - 5 months ago 25
Objective-C Question

Objective C Message Argument Array Parsing (AJNMessageArgument)

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!

Answer

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.

Comments