شروحات الكمبيوتر والإنترنت والموبايل

مشكلة استرجاع المفتاح من Keychain في Swift على iOS

نواجه في تطوير تطبيقات iOS أحيانًا مشكلات تتعلق بالتعامل مع Keychain، وهي أداة أساسية لتخزين البيانات الحساسة مثل كلمات المرور وأسماء المستخدمين. واحدة من الأخطاء الشائعة التي قد تصادفها المطورين هي "غير قادر على جلب المفتاح من Keychain". في هذه المقالة، سنستعرض سبب حدوث هذا الخطأ وكيف يمكن إصلاحه بكفاءة.

ما هو Keychain في iOS؟

Keychain هو نظام أمان في أنظمة التشغيل iOS وmacOS يوفر وسيلة لتخزين المعلومات الحساسة بشكل آمن. يمكن لمطوري التطبيقات استخدام Keychain لتخزين بيانات مثل كلمات المرور أو الرموز السرية بأمان دون القلق بشأن تعرضها للاختراق. ومع ذلك، قد تظهر بعض المشكلات، مثل عدم القدرة على جلب البيانات، مما يتطلب فهمًا أفضل لكيفية عمل Keychain.

أسباب المشكلة: Unable to fetch key from Keychain

قد تحدث المشكلة "غير قادر على جلب المفتاح من Keychain" لأسباب عدة. إليك بعض الأسباب الشائعة:

  1. المفتاح غير موجود: إذا كنت تحاول جلب مفتاح لم يتم تخزينه مسبقًا، فسيظهر هذا الخطأ.

  2. مشكلات في التنسيق: إذا كان هناك خطأ في الطريقة التي تم بها تخزين البيانات، قد تتسبب هذه المشكلة في عدم القدرة على استرجاع البيانات بشكل صحيح.

  3. تصاريح الوصول: إذا كانت التصاريح للوصول إلى البيانات غير صحيحة، فلن تتمكن من استرجاع القيمة المخزنة في Keychain.

خطوات لحل المشكلة

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

عمل دالة لتخزين البيانات في Keychain

في المثال التالي، سنقوم بإنشاء فئة (Class) خاصة بإدارة Keychain، والتي تحتوي على وظائف لإضافة البيانات، حذفها، واسترجاعها. إليك الكود:

class KeychainAccess {
    func addKeychainData(itemKey: String, itemValue: String) throws {
        guard let valueData = itemValue.data(using: .utf8) else {
            print("Keychain: غير قادر على تخزين البيانات، إدخال غير صالح - المفتاح: \(itemKey)، القيمة: \(itemValue)")
            return
        }
        do {
            try deleteKeychainData(itemKey: itemKey)
        } catch {
            print("Keychain: لا يوجد شيء لحذفه...")
        }
        let queryAdd: [String: AnyObject] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrAccount as String: itemKey as AnyObject,
            kSecValueData as String: valueData as AnyObject,
            kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked
        ]
        let resultCode = SecItemAdd(queryAdd as CFDictionary, nil)
        if resultCode != errSecSuccess {
            print("Keychain: لم تتم إضافة القيمة - الخطأ: \(resultCode)")
        } else {
            print("Keychain: القيمة أُضيفت بنجاح")
        }
    }
    func deleteKeychainData(itemKey: String) throws {
        let queryDelete: [String: AnyObject] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrAccount as String: itemKey as AnyObject
        ]
        let resultCodeDelete = SecItemDelete(queryDelete as CFDictionary)
        if resultCodeDelete != errSecSuccess {
            print("Keychain: غير قادر على الحذف من keychain: \(resultCodeDelete)")
        } else {
            print("Keychain: تم حذف العنصر بنجاح")
        }
    }
    func queryKeychainData(itemKey: String) throws -> String? {
        let queryLoad: [String: AnyObject] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrAccount as String: itemKey as AnyObject,
            kSecReturnData as String: kCFBooleanTrue,
            kSecMatchLimit as String: kSecMatchLimitOne
        ]
        var result: AnyObject?
        let resultCodeLoad = withUnsafeMutablePointer(to: &result) {
            SecItemCopyMatching(queryLoad as CFDictionary, UnsafeMutablePointer($0))
        }
        if resultCodeLoad != errSecSuccess {
            print("Keychain: غير قادر على تحميل البيانات - \(resultCodeLoad)")
            return nil
        }
        guard let resultVal = result as? NSData,
              let keyValue = String(data: resultVal as Data, encoding: .utf8) else {
            print("Keychain: خطأ في تحليل نتيجة سلسلة المفاتيح - \(resultCodeLoad)")
            return nil
        }
        return keyValue
    }
}

استخدام الفئة في التطبيق

بعد إعداد الوظائف، يمكنك استخدام فئة KeychainAccess لتخزين واسترجاع البيانات بسهولة. إليك كيفية استخدامها:

let keychain = KeychainAccess()
do {
    try keychain.addKeychainData(itemKey: "KeyChainUserName", itemValue: "[email protected]")
    try keychain.addKeychainData(itemKey: "KeyChainPassword", itemValue: "securePassword123")
    let userName = try keychain.queryKeychainData(itemKey: "KeyChainUserName")
    print("اسم المستخدم: \(userName ?? "غير موجود")")
} catch {
    print("خطأ في العملية: \(error)")
}

خاتمة

كذلك، نكون قد تعرفنا على كيفية التعامل مع مشكلة "غير قادر على جلب المفتاح من Keychain" في iOS. من خلال الفهم الجيد لكيفية عمل Keychain وتطبيق هذه الممارسات، يمكنك تحسين أمان تطبيقك وضمان عدم مواجهة مثل هذه الأخطاء. تذكر دائمًا اختبار الكود الخاص بك والتحقق من وجود الأخطاء المحتملة قبل نشر التطبيق.

فهد السلال

خبير تقني متخصص في شروحات الكمبيوتر والإنترنت والموبايل، يتمتع بخبرة واسعة في تقديم حلول تقنية مبتكرة ومبسطة. يهدف فهد إلى مساعدة المستخدمين على تحسين تجربتهم التقنية من خلال مقالات وأدلة عملية واضحة وسهلة الفهم.
زر الذهاب إلى الأعلى
Don`t copy text!