2014-01-27 5 views
2

У меня возникли проблемы с функцией, которая, как кажется, только во время моих тестов внутри объекта SenTestCase.base64EncodedStringWithOptions crashing on SenTest

То, что я пытаюсь сделать, это получить кодировку base64 из объекта NSData (на самом деле это сериализованный словарь JSON).

Что на самом деле происходит в коде ниже это NSJSONSerialization создает объект NSConcreteData который затем падает на [dataFromDictionary base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]

Катастрофа возвращаемые 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 
} 

Я & stackOverflowing прибегая к помощи вокруг и там может быть зависимость или заголовок отсутствует моей тестовой цели. Я просто не понимаю, что это такое. Не все ли функции Foundation Foundation?

Флаги -all-load и -ObjC также установлены в цель, происходит та же ошибка.

ОБНОВЛЕНИЕ: В написании этого сообщения я нашел решение этой ошибки. Сохраняя сообщение здесь для потомков, и в случае, если я нашел субоптимальное решение.

Оказалось, что SenTest была красной селедкой. То, что на самом деле вызывало проблему, было целью сборки (которая была 6.1 в тестовом симуляторе, 7.0 на моем устройстве dev), фактически не имеющим доступа к вновь опубликованному методу iOS 7.

Я столкнулся с этим в документация для base64EncodedStringWithOptions::

Although this method was only introduced publicly for iOS 7, it has existed since iOS 4 

Поскольку я планирую поддерживать IOS 5 и выше, я добавил свою собственную реализацию base64 кодирования/декодирования (на основе Matt Gallagher's implementation), и теперь все хорошо.

Это был простой случай обратной совместимости. Хороший урок, чтобы иметь в виду будущее.

ответ

15

Как вы отметили, base64EncodedStringWithOptions - это метод iOS 7. Вы можете использовать стороннюю библиотеку base-64, если хотите, но Apple раскрыла ранее закрытый метод, base64Encoding, для обратной совместимости со старыми версиями iOS.Таким образом, вы можете сделать:

NSString string; 

if ([data respondsToSelector:@selector(base64EncodedStringWithOptions:)]) { 
    string = [data base64EncodedStringWithOptions:kNilOptions]; // iOS 7+ 
} else { 
    string = [data base64Encoding];        // pre iOS7 
} 

и преобразовать обратно:

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 
} 
+0

Это был подход, который я первоначально пытался. К сожалению, я все еще получал ту же ошибку. 'NSJSONSerialization' возвращал объекты подкласса' NSConcreteData' вместо 'NSData'. Похоже, что 'NSConcreteData' не отвечает ни« base64EncodedStringWithOptions: », ни« base64Encoding »и не может быть расширен в категории (поскольку NSConcreteData не отображается). То, что я в конце концов прибегли к был отдельный 'APBBase64Encoder' класс с двумя методами класса: ' + (NSData *) dataFromBase64String: (NSString *) aString; '' + (NSString *) base64EncodedStringFromData: (NSData *) ADATA ; '. – Andrew

+0

@Andrew 1. 'NSConcreteData' - это просто подкласс' NSData', поэтому любые методы NSData, которые у вас есть, будут работать с ним. Если это не так, ваши сторонние библиотеки тоже не сработали бы. (Если факт, часто когда вы создаете экземпляр объекта NSData, вы действительно получаете объект 'NSConcreteData'.) 2. Что вы подразумеваете под' NSJSONSerialization', возвращающим 'NSConcreteData'? Метод 'dataWithJSONObject'? Конечно, но этот метод предназначен для преобразования словаря/массива в JSON 'NSData', поэтому я не уверен, насколько это актуально здесь. И метод 'JSONObjectWithData' не возвращает' NSConcreteData'. – Rob

+0

Независимо от того, что было предложено вашим комментарием, я повторно протестировал вышеуказанный код в iOS 7, 6 и 5, чтобы убедиться, что я ничего не забыл, и он работал нормально во всех трех. iOS 5 определенно не должен сообщать «непризнанный селектор», если вы используете правильный «responsesToSelector» (и, в частности, если вы вызываете «base64Encoding» в iOS 5, он отлично работает). Не стесняйтесь использовать стороннюю библиотеку, если хотите, но версии iOS до 7 отвечают на методы «base64Encoding» и «initWithBase64Encoding». – Rob

0

Оказалось, что SenTest была красной селедкой. То, что на самом деле вызывало проблему, было целью сборки (которая была 6.1 в тестовом симуляторе, 7.0 на моем устройстве dev), фактически не имеющим доступа к вновь опубликованному методу iOS 7.

Я столкнулся с этим в документация для base64EncodedStringWithOptions ::

Although this method was only introduced publicly for iOS 7, it has existed since iOS 4 

Поскольку я планирую поддерживать IOS 5 и выше, я добавил свою собственную реализацию base64 кодирования/декодирования (на основе Matt Gallagher's implementation), и теперь все хорошо.

Это был простой случай обратной совместимости. Хороший урок, чтобы иметь в виду будущее.