base64EncodedStringWithOptions crashing on SenTest
ios, testing
Solution
As you noted, `base64EncodedStringWithOptions` is an iOS 7 method. You can use third-party base-64 library if you want, but Apple has exposed the previously private method, `base64Encoding`, for backward compatibility with older iOS versions. Thus, you can do:
NSString string;
if ([data respondsToSelector:@selector(base64EncodedStringWithOptions:)]) {
string = [data base64EncodedStringWithOptions:kNilOptions]; // iOS 7+
} else {
string = [data base64Encoding]; // pre iOS7
}
and to convert back:
NSData *data;
if ([NSData instancesRespondToSelector:@selector(initWithBase64EncodedString:options:)]) {
data = [[NSData alloc] initWithBase64EncodedString:string options:kNilOptions]; // iOS 7+
} else {
data = [[NSData alloc] initWithBase64Encoding:string]; // pre iOS7
}
Problem
I'm having trouble with a function that only seems to crash during my tests inside a SenTestCase object. What I'm trying to do is get a base64-Encoded String from an NSData object (that's actually a serialized JSON dictionary). What actually happens in the code below is the NSJSONSerialization creates an NSConcreteData object which then crashes on `[dataFromDictionary base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]` The crash returned is `test failure: -[NSConcreteData base64EncodedStringWithOptions:]: unrecognized selector sent to instance`. ``` (in my SenTestCase implementation) -(NSString *)paramsAsString { NSDictionary *storedParams = @{@"stringKeyTest":@"testValueString", @"dictionaryKeyTest":@{@"testDictKey":@"testDictValue"}, @"numberKeyTest":@1 }; NSError *error = nil; BOOL paramCheck = [NSJSONSerialization isValidJSONObject:storedParams]; //paramCheck is true NSData *dataFromDictionary = [NSJSONSerialization dataWithJSONObject:storedParams options:0 error:&error]; //dataFromDictionary is actually NSConcreteData NSString *stringFromData = [dataFromDictionary base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; //should stringify NSData, actually crashes return stringFromData; //never reached } ``` I've been googling & stackOverflowing around and there might be a dependency or a header missing from my test target. I just can't understand what that is. Aren't these all Foundation framework functions? The `-all-load` and `-ObjC` flags are also set in the target, the same error occurs. UPDATE: In the writing of this post I found the solution to this bug. Keeping the post here for posterity and in case I have found a suboptimal solution. Turned out the SenTest was a red herring. What actually was causing the problem was the build target (which was 6.1 in the test simulator, 7.0 on my dev device) not actually having access to the method that was newly made public iOS 7. I came across this in the documentation for `base64EncodedStringWithOptions:`: ``` Although this method was only introduced publicly for iOS 7, it has existed since iOS 4 ``` Since I'm planning on supporting iOS 5 and higher, I added my own implementation of base64 encoding/decoding (based on Matt Gallagher's implementation) and now all is well. It was simple case of backwards incompatibility. A good lesson to keep in mind for the future.