Hi everyone,
I’m just working on this challenge and here is my solution. It seems it works but I’m still not very sure about the NSError part. I just check the brand name to see whether it’s in the list and decide to return the error message or not. I think there should be better ways.
[code]- (NSString *)encodeAsSpeakableString
{
// Create the list of all brands
// Keep the NSDictionary object for reuse
static NSDictionary *brandList = nil;
if (!brandList) {
brandList = @{@“Camry”: @0, @“Nikon”: @1, @“Apple”: @2, @“Ford”: @3, @“Audi”: @4,@“Google”: @5,@“Nike”: @6,@“Amazon”: @7,@“Honda”: @8, @“Mazda”: @9,@“Buick”: @10,@“Fiat”: @11, @“Jeep”: @12, @“Lexus”: @13, @“Volvo”: @14, @“Fuji”: @15, @“Sony”: @16, @“Delta”: @17, @“Focus”: @18, @“Puma”: @19, @“Samsung”: @20, @“Tivo”: @21, @“Halo”: @22, @“Sting”: @23, @“Shrek”: @24, @“Avatar”: @25, @“Shell”: @26, @“Visa”: @27, @“Vogue”: @28, @“Twitter”: @29, @“Lego”: @30, @“Pepsi”: @31, };
}
// Get bytes from the NSData object to convert
unsigned char bytes[8];
[self getBytes:bytes];
// Create a mutable string to store converted speakable strings
NSMutableString *dataToString = [[NSMutableString alloc] init];
for (int i = 0; i < [self length]; i++) {
unsigned char x = bytes[i] >> 5; // Digit part of the string
unsigned char w = bytes[i] << 3;
unsigned char y = w >> 3; // Brand part of the string
NSArray *key = [brandList allKeysForObject:[NSNumber numberWithUnsignedChar:y]]; // Find the key corresponding to the brand number
NSString *brand = key[0];
NSString *digit = [NSString stringWithFormat:@"%d ", x + 2]; // To avoid digit 1 and 0
[dataToString appendString:digit];
[dataToString appendString:brand];
// add space except for the last brand
if (i != [self length] - 1) {
[dataToString appendString:@" "];
}
}
return [dataToString copy];
}
-
(NSData *)dataWithSpeakableString:(NSString *)string
error:(NSError **)error
{
static NSDictionary *brandList = nil;
if (!brandList) {
brandList = @{@“Camry”: @0, @“Nikon”: @1, @“Apple”: @2, @“Ford”: @3, @“Audi”: @4,@“Google”: @5,@“Nike”: @6,@“Amazon”: @7,@“Honda”: @8, @“Mazda”: @9,@“Buick”: @10,@“Fiat”: @11, @“Jeep”: @12, @“Lexus”: @13, @“Volvo”: @14, @“Fuji”: @15, @“Sony”: @16, @“Delta”: @17, @“Focus”: @18, @“Puma”: @19, @“Samsung”: @20, @“Tivo”: @21, @“Halo”: @22, @“Sting”: @23, @“Shrek”: @24, @“Avatar”: @25, @“Shell”: @26, @“Visa”: @27, @“Vogue”: @28, @“Twitter”: @29, @“Lego”: @30, @“Pepsi”: @31, };
} // Create the list incase it is not created yet// Create the character set of 10 digits
NSCharacterSet *digitSet = [NSCharacterSet decimalDigitCharacterSet];NSRange searchRange;
searchRange.location = 0;
searchRange.length = [string length];unsigned char digits[8]; // Store the digits of the speakable string
unsigned long digitLocations[8]; // Store the locations of the digits in the speakable string
// Find the digits one by one and store them in "digits"
for (int i = 0; i < [string length]; i++) {
NSRange range = [string rangeOfCharacterFromSet:digitSet
options:NSLiteralSearch
range:searchRange];
if (range.length == 0) {
break; // Stop the loop if no more digit can be found
} else {
int digit = [[string substringWithRange:range] intValue] - 2; // convert the substring of digit to an integer
digits[i] = (unsigned char)digit; // Store it in a byte of "digits"
digitLocations[i] = range.location; // Store the location here for future use
// Define a new range to search for next digit
searchRange.location = range.location + 1;
searchRange.length = [string length] - searchRange.location;
}
}// Now it’s time to convert the brands
unsigned char brandParts[8]; // Store the number of brands here
for (int i = 0; i < 8; i++) {
// Calculate the range of a particular brand
NSRange brandRange;
brandRange.location = digitLocations[i] + 2;
if (i < 7) {
brandRange.length = digitLocations[i+1] - digitLocations[i] - 3;
} else {
brandRange.length = [string length] - brandRange.location;
}
NSString *brand = [string substringWithRange:brandRange]; // Get the brand
NSNumber *brandNumber = [brandList objectForKey:brand];// Is the brand string in the brand list? if (brandNumber == nil) { //Did the user give the address to place error? if (error) { NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"Unable to parse!"}; *error = [NSError errorWithDomain:@"SpeakableBytes" code:1 userInfo]; return nil; } } brandParts[i] = [brandNumber unsignedCharValue];
}
// Combine the two parts above
unsigned char bytesFromString[8];
for (int i = 0; i < 8; i++) {
bytesFromString[i] = (digits[i] << 5) | brandParts[i];
}// Create an NSData to wrap the bytes
NSData *Data = [NSData dataWithBytes:&bytesFromString
length:8 * sizeof(unsigned char)];return Data;
}
[/code]