То, что может сделать JVM, определяется байт-кодом JVM (что Вы находите в .class файлах), а не исходный язык. Так изменение языка исходного кода высокого уровня не собирается оказывать существенное влияние на доступную функциональность.
, Что касается какой требуется, чтобы писать компилятор для JVM, все, что действительно необходимо сделать, генерируют корректный байт-код / .class файлы. Как Вы пишете/компилируете, что код с альтернативным видом компилятора зависит от рассматриваемого компилятора, но однажды выходы компилятора .class файлы, выполняя их не отличается, чем выполнение .class файлов, сгенерированных javac.
Я знаю, что это было несколько месяцев назад, но у меня была та же самая проблема, и это было больно, поэтому я решил поделиться. Я решил эту проблему, добавив следующую строку:
[self.keychainItemWrapper setObject:@"MY_APP_CREDENTIALS" forKey:(id)kSecAttrService];
//@"MY_APP_CREDENTIALS" can be any string.
Я нашел эту запись в блоге очень полезной: «В терминах базы данных вы можете подумать, что они являются уникальным индексом для двух атрибутов kSecAttrAccount, kSecAttrService, требующих комбинации этих два атрибута, которые должны быть уникальными для каждой записи в цепочке для ключей. " (из http://useyourloaf.com/blog/2010/4/28/keychain-duplicate-item-when-adding-password.html ).
Кроме того, в примере проекта Apple, использующего этот код, они создают экземпляр KeychainItemWrapper в делегате приложения. Я не знаю, если это необходимо, но мне нравится как можно точнее следовать их примерам:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
//there will be some standard code here.
KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MY_APP_CREDENTIALS" accessGroup:nil];
self.keychainWrapper = wrapper;
[self.keychainWrapper setObject:@"MYOBJECT" forKey:(id)kSecAttrService];
[wrapper release];
}
Я думаю, что это ошибка в коде оболочки. Логика в основном говорит: «Эта запись уже существует? Нет, это не так. Хорошо, я добавлю ее. Ой, вы не можете добавить ее, потому что она уже есть».
Вам также может понадобиться установить kSecAttrAccount; Я никогда не пробовал без установки этого значения, поскольку он предназначен для сохранения имени пользователя, которое идет с паролем:
[self.wrapper setObject:txtUserName.text forKey:(id)kSecAttrAccount];
Для меня решение состояло в том, что я создал KeychainItemWrapper
«синглтон» и использовал его во всем приложении. (На самом деле, в моем случае, у меня был одноэлементный словарь, полный KeychainItemWrapper
-s, потому что я использую больше, чем один.)
Это решило проблему, когда я добирался до пути к коду, который фактически сказал: « существует ли этот элемент в цепочке для ключей? Нет? Затем добавьте его. Ой! NSAssert()
Я пытаюсь добавить уже существующий элемент (Ошибка -25299) "
Пока я не уверен, Я подозреваю, что проблема связана с синхронизацией цепочки для ключей. У меня были похожие проблемы с NSUserDefaults
, когда я записывал в NSUD, затем, где-нибудь в коде, получал standardUserDefaults
и читал из них, а обновление еще не произошло (потому что я не сделал [ud synchronize]
], пока.)
В коде моя рутина выглядит так:
+ (KeychainItemWrapper*) keyChainWrapperForKeyID: (NSString*) keyID
{
static dispatch_once_t onceToken = 0;
static NSMutableDictionary *rfcuKeyChains = nil;
dispatch_once(&onceToken, ^{
rfcuKeyChains = [NSMutableDictionary new];
});
KeychainItemWrapper *keychain = nil;
@synchronized (rfcuKeyChains)
{
keychain = [rfcuKeyChains objectForKey: keyID];
if (keychain == nil)
{
keychain = [[KeychainItemWrapper alloc] initWithIdentifier: keyID accessGroup: nil];
[rfcuKeyChains setObject: keychain forKey: keyID];
}
}
return keychain;
}
И я использую ее так:
KeychainItemWrapper *keychain = [RFCUtils keyChainWrapperForKeyID: keyID];
NSString *firstLaunch = [keychain objectForKey: (__bridge id)(kSecAttrAccount)];
if (firstLaunch == nil)
{
[keychain setObject: MY_APP_KEY forKey: (__bridge id)(kSecAttrAccount)];
}
(и т. звонки в другие места.)
Я попробовал все решения, слушайте выше, но у меня ничего не получалось. Он работал только на реальном устройстве, но не на симуляторе.
Мое решение запустить его на симуляторе состояло в том, чтобы включить «Право доступа к цепочке ключей».