My solution for Speakable


#1

The challenge of this chapter is really hard for me! It took me one day to solve it.
I know my solution is not elegant and need to review, so comments are welcome!

NSData+Speakable.h

[code]#import “NSData+Speakable.h”

@implementation NSData (Speakable)

  • (NSString *)encodeAsSpeakableString
    {
    NSMutableString *str = [[NSMutableString alloc] init];

    NSArray *brands = [[NSArray alloc] initWithObjects:@“Camry”,
    @“Nikon”, @“Apple”, @“Ford”, @“Audi”, @“Google”,
    @“Nike”, @“Amazon”, @“Honda”, @“Mazda”, @“Buick”,
    @“Fiat”, @“Jeep”, @“Lexus”, @“Volvo”, @“Fuji”,
    @“Sony”, @“Delta”, @“Focus”, @“Puma”, @“Samsung”,
    @“Tivo”, @“Halo”, @“Sting”, @“Shrek”, @“Avatar”,
    @“Shell”, @“Visa”, @“Vogue”, @“Twitter”, @“Lego”,
    @“Pepsi”, nil];

    int64_t aBytes;

    for (int i = 0; i < 8; i++) {
    [self getBytes:&aBytes range:(NSRange){i, 1}];

      int64_t leftThreeBits = (aBytes >> 5);
      int64_t digit = (leftThreeBits + 2) & 0xff;
      int64_t rightFiveBits = aBytes & 0x1f;
    
      [str appendFormat:@"%lld %@ ", digit, brands[rightFiveBits]];
    

    }

    [str deleteCharactersInRange:NSMakeRange([str length]-1, 1)];
    return [str copy];

}

  • (NSData *)dataWithSpeakableString:(NSString *)s
    error:(NSError **)e
    {
    NSArray *brands = [[NSArray alloc] initWithObjects:@“Camry”,
    @“Nikon”, @“Apple”, @“Ford”, @“Audi”, @“Google”,
    @“Nike”, @“Amazon”, @“Honda”, @“Mazda”, @“Buick”,
    @“Fiat”, @“Jeep”, @“Lexus”, @“Volvo”, @“Fuji”,
    @“Sony”, @“Delta”, @“Focus”, @“Puma”, @“Samsung”,
    @“Tivo”, @“Halo”, @“Sting”, @“Shrek”, @“Avatar”,
    @“Shell”, @“Visa”, @“Vogue”, @“Twitter”, @“Lego”,
    @“Pepsi”, nil];

    NSArray *speakableArray = [s componentsSeparatedByString:@" "];
    NSCharacterSet *digits = [NSCharacterSet decimalDigitCharacterSet];

    int64_t digit = 0;
    int64_t tmp = 0;
    int64_t aBytes = 0;

    for (int i = 0; i < [speakableArray count]; i++) {
    NSString *n = speakableArray[i];
    BOOL isDigit = [digits characterIsMember:[n characterAtIndex:0]];

      if (i % 2 == 0 && !isDigit) {
          if (e) {
              NSDictionary *userInfo = @{ NSLocalizedDescriptionKey:@"Unable to parse"};
              *e = [NSError errorWithDomain:@"SpeakableBytes"
                                       code:1
                                   userInfo];
              return nil;
          }
      }
    
      if (isDigit) {
          digit = [n longLongValue] - 2;
          tmp = digit << 5;
      } else {
          digit = [brands indexOfObject:n];
          tmp |= digit;
      }
    
      if (i % 2) {
          aBytes |= tmp << (4 * (i - 1));
      }
    

    }
    NSData *outData = [NSData dataWithBytes:&aBytes
    length:sizeof(int64_t)];
    return outData;
    }

@end[/code]