Quick disclaimer. I've programmed Java for years but this is the first Objective C I've ever written.
I've written some code which almost unfortunately works but frankly hurts my eyes with the number of lines of code and quality. Basically looking for the right way to convert the original string:
<TUHandle 0x280479f50 type=PhoneNumber, value=07700000000, normalizedValue=(null), isoCountryCode=(null)>
Into JSON (ignoring the TUHandle 0x280479f50) part which I don't need:
{"value": "07700000000",
"normalizedValue": "(null)",
"type": "PhoneNumber",
"isoCountryCode": "(null)"}
Line breaks and indents are NOT important, only that this is valid JSON
//Format of string
//<TUHandle 0x280479f50 type=PhoneNumber, value=07700000000, normalizedValue=(null), isoCountryCode=(null)>
NSString *original = [NSString stringWithFormat:@"%@", hand];
//Trim off unused stuff
NSRange startKeyValues = [original rangeOfString:@"type="];
NSRange endKeyValues = [original rangeOfString:@">"];
NSRange rangeOfString = NSMakeRange(startKeyValues.location, endKeyValues.location - startKeyValues.location);
NSString *keysValues = [original substringWithRange:rangeOfString];
//Create a dictionary to hold the key values
NSMutableDictionary *dict = [[NSMutableDictionary alloc]initWithCapacity:10];
//Split the keysValuesstring
NSArray *items = [keysValues componentsSeparatedByString:@","];
for (NSString* o in items)
{
//Create key value pairs
NSArray *item = [o componentsSeparatedByString:@"="];
NSString *key=[item objectAtIndex:0];
NSString *value=[item objectAtIndex:1];
[dict setObject:value forKey:key];
}
[dict setObject:currentUUID forKey:@"uid"];
//Convert to Json Object
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:nil];
Any tips which would make this look a hell of a lot less clunky?
1 Answer 1
In your question, you don't make it clear what needs to be dynamic and what can be static. If the only string you ever have to parse is the one you showed, then don't bother parsing it, just make the json string and use:
NSData *jsonData = [@"{\"normalizedValue\":\"(null)\",\"value\":\"07700000000\",\"isoCountryCode\":\"(null)\",\"type\":\"PhoneNumber\",\"uid\":\"uuid\"}" dataUsingEncoding:NSUTF8StringEncoding];
If you know all the keys will be the same and just the data will be different, then I would go with something like:
NSString *valueFor(NSString *key, NSString *original) {
unsigned long startOf = [original rangeOfString:key].location + key.length;
unsigned long endOfComma = [original rangeOfString:@"," options:NSLiteralSearch range:NSMakeRange(startOf, original.length - startOf)].location;
return [
[original substringWithRange:NSMakeRange(startOf, (endOfComma == NSNotFound ? original.length : endOfComma) - startOf)]
stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@">"]
];
}
NSData *example(NSString *original, NSString *currentUUID) {
NSString *type = valueFor(@"type=", original);
NSString *value = valueFor(@"value=", original);
NSString *normalizedValue = valueFor(@"normalizedValue=", original);
NSString *isoCountryCode = valueFor(@"isoCountryCode=", original);
NSDictionary *dict = @{
@"value": value,
@"normalizedValue": normalizedValue,
@"type": type,
@"isoCountryCode": isoCountryCode,
@"uid": currentUUID
};
return [NSJSONSerialization dataWithJSONObject:dict options:0 error:nil];
}
The above is much cleaner and easier to read than what you have currently.
If even the keys have to be dynamic, then the code you have is about as good as you can get.
I ended up with this:
NSData* example(NSString* original, NSString *currentUUID) {
NSArray<NSString*>* elements =
[[[original stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]]
componentsSeparatedByString:@" "]
filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
return [evaluatedObject containsString:@"="];
}]];
NSMutableArray* values = [NSMutableArray new];
for (NSString* each in elements) {
NSArray<NSString*>* keyValue = [[each stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]]
componentsSeparatedByString:@"="];
NSString* value = [NSString stringWithFormat:@"\"%@\": \"%@\"", keyValue[0], keyValue[1]];
[values addObject:value];
};
[values addObject: [NSString stringWithFormat:@"\"uid\": \"%@\"", currentUUID]];
NSData* jsonData = [[NSString stringWithFormat:@"{%@}", [values componentsJoinedByString:@", "]] dataUsingEncoding:NSUTF8StringEncoding];
return jsonData;
}
Which is maybe a little more generic than the code you have, but I don't think it's any more readable.
%hook TUProxyCall -(id)handle { TUHandle *hand = %orig; NSString *original = [NSString stringWithFormat:@"%@", hand]; ....}
Thanks in advance \$\endgroup\$