سؤال

انا استعمل ال ورقة التفاح لسلسلة المفاتيح, ، وحاول حفظ عنصر عليه (تشغيل في Simulator ، iOS 4.1).

لم أختبر مع سلسلة المفاتيح من قبل.

أحصل على هذا الخطأ:

لا يمكن إضافة عنصر سلسلة المفاتيح. خطأ - 25299

في keychainitemwrapper.m الخط 304:

// No previous item found; add the new one.
result = SecItemAdd((CFDictionaryRef)[self dictionaryToSecItemFormat:keychainItemData], NULL);
NSAssert( result == noErr, @"Couldn't add the Keychain Item." );

هذه هي الطريقة التي أفعل بها الحفظ:

- (void) saveKey:(NSString *)key value:(NSString *)value {
    KeychainItemWrapper *keyItem = [[KeychainItemWrapper alloc] initWithIdentifier:key accessGroup:nil];
    [keyItem setObject:value forKey:(id)kSecValueData];
    [keyItem release];
}

وهذه هي القيم التي تحاول API حفظها:

<CFBasicHash 0x7231f60 [0x320d380]>{type = mutable dict, count = 5,
entries =>
2 : <CFString 0x2e6eb98 [0x320d380]>{contents = "labl"} = <CFString 0x2fb018 [0x320d380]>{contents = ""}
3 : <CFString 0x2e6efb8 [0x320d380]>{contents = "v_Data"} = <CFString 0x727de60 [0x320d380]>{contents = "dit8"}
4 : <CFString 0x2e6ebc8 [0x320d380]>{contents = "acct"} = <CFString 0x2fb018 [0x320d380]>{contents = ""}
5 : <CFString 0x2e6eb58 [0x320d380]>{contents = "desc"} = <CFString 0x2fb018 [0x320d380]>{contents = ""}
6 : <CFString 0x2e6ebe8 [0x320d380]>{contents = "gena"} = <CFString 0x2ffd08 [0x320d380]>{contents = "userCode"}
}
هل كانت مفيدة؟

المحلول

أعلم أن هذا منذ عدة أشهر ، لكنني واجهت نفس المشكلة وكانت مؤلمة لذلك اعتقدت أنني سأشارك. لقد قمت بحله بإضافة هذا الخط:

[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];   

نصائح أخرى

وفق وثائق, ، الخطأ -25299 الذي تحصل عليه هو "errsecduplicateItem" ، مما يعني أن العنصر الذي تحاول إضافته موجود بالفعل. بالنظر إلى الكود المرتبط بـ keychainitemwrapper ، أعتقد أن SecItemCopyMatching المكالمة تفشل مع خطأ آخر غير errsecitemnotfound (–25300).

يمكنك التخزين بسهولة واستعادة القيم باستخدام سلسلة المفاتيح باستخدام sfhfkeychainutils بواسطة Buzz Andersen.

  1. تنزيل ونسخ في مشروعك sfhfkeychainutils.h و .m
  2. أضف الأمان.
  3. تأكد من إضافة هذه الملفات إلى هدفك
  4. استيراد sfhfkeychainutils.h حيث تريد استخدامه

هذا مثال بسيط على كيفية استخدام هذه المكتبة.

// To store data
NSError *error = nil;
[SFHFKeychainUtils storeUsername:username andPassword:password forServiceName:kStoredData updateExisting:YES error:&error];

// To retrieve data
NSString *password = [SFHFKeychainUtils getPasswordForUsername:username andServiceName:kStoredData error:&error];

// To delete data from keychain
[SFHFKeychainUtils deleteItemForUsername:username andServiceName:kStoredData error:&error];

سلسلة المفاتيح هو ألم كامل. يجب أن تستخدم Buzz Andersen's Stutils المكتبة بدلا من ذلك كركبة. سيجعل حياتك أسهل بكثير. لم أواجه مشكلة في ذلك.

بالنسبة لي ، كان الحل هو أنني أنشأت أ KeychainItemWrapper "Singleton" واستخدم ذلك في جميع أنحاء التطبيق. (في الواقع ، في حالتي ، كان لدي قاموس مفردة مليئة 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)];
}

(وما إلى ذلك ، مكالمات مماثلة في أماكن أخرى.)

لقد واجهت هذه المشكلة أيضًا وحلها بفضل إجابة القبول والرابط الإضافي لـ UseOurloaf.

كانت المشكلة التي واجهتها مثيرة للاهتمام ، وكنت بحاجة لتوفير قيمة واحدة فقط وقررت تخزينها في هذا المجال ksecvaluedata. ذلك لأنني رأيت منشورات أخرى حول استخدام سلسلة المفاتيح وبدأت تنفيذي قبل التحول إلى keychainitemwrapper. تسبب هذا في المشكلة التالية: على الجهاز الأول الذي كنت أختبره (iPad 1st Gen) كنت أتلقى خطأً في WriteTokeyChain. لقد قمت بتغيير الجهاز (أيضًا iPad 1st Gen) وقد نجح! العودة إلى الجهاز الأول لا يزال لم ينجح.

لذلك أنا هذه النقطة عرفت أنني سبق أن ارتكبت شيئًا خاطئًا في سلسلة مفاتيح الجهاز ولم أتمكن من العودة بسهولة. كانت رموز الخطأ التي كنت أحصل عليها هي: -25300 على SecitemCopyminging's WriteTokeyChain (غير موجود) وبعد -25299 مباشرة على Secitemadd. (عنصر تكرار)

مع هذا السؤال ، كل هذا منطقي: الجهاز لديه مفتاح يتطابق أي مفتاح جديد ، لكن keychainitemwrapper لا يمكن حذفه ولكن لا يمكن استرداد المفتاح. بمجرد أن أضفت نفس القيمة إلى الحقل Ksecattraccount ، بدأت العمل.

قصة قصيرة طويلة ، بالنسبة للمستخدمين الآخرين الذين يعانون من هذه المشكلة ، قد تبدو مشكلتك مختلفة ولكن الانتباه إلى التفاصيل. إذا كان لديك -25300 (العنصر غير موجود) متبوعًا بـ -25299 (عنصر تكرار) ؛ تأكد من قيامك بتعيين حقل يحدد تفرد عنصر سلسلة المفاتيح. إذا لم ينجح ذلك على جهاز واحد ، جرب آخر إذا كنت تستطيع أن تتمكن من عزل المشكلة لجهاز واحد. رموز خطأ في سلسلة مفاتيح Apple: http://developer.apple.com/library/ios/#documentation/security/reference/keychainservices/reference/reference.html#//apple_ref/doc/uid/tp30000898-ch5g-cjbeabhg (ابحث عن رموز النتائج)

جربت جميع الحلول الاستماع أعلاه ولكن لا شيء يعمل بالنسبة لي. كان يعمل فقط على جهاز فعلي ولكن ليس على جهاز المحاكاة.

كان الحل الخاص بي لتشغيله على جهاز المحاكاة هو تشغيل "مشاركة استحقاق سلسلة المفاتيح".

مشاركة استحقاق سلسلة المفاتيح

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top