Wednesday, July 1, 2026
HomeiOS Developmentios - Cannot fetch saved account from Keychain

ios – Cannot fetch saved account from Keychain

[ad_1]

I made a easy analog of the account supervisor for iOS utilizing Apple Keychain:

@Serializable
information class Account(
    val identify: String,
    val password: String,
    val accessToken: String,
    val refreshToken: String,
)  

precise class AccountManagerGateway : IAccountManagerGateway {
    non-public val json = Json { encodeDefaults = true }

    override enjoyable addAccount(account: Account) = updateAccount(account)

    override enjoyable updateAccount(account: Account) {
        val information = json.encodeToString(account)
        if (!saveData(information)) {
            throw AccountException("Account not saved")
        }
    }

    override enjoyable getAccount(): Account? = this.getData()?.let {
        json.decodeFromString(it)
    }

    override enjoyable deleteAccount() {
        deleteData()
    }

    non-public enjoyable getData(): String? {
        memScoped {
            val question = question(
                kSecClass to kSecClassGenericPassword,
                kSecAttrService to SERVICE.toCFDict(),
                kSecAttrAccount to ACCOUNT_TYPE.toCFDict(),
            )
            val consequence = alloc<CFTypeRefVar>()
            val standing = SecItemCopyMatching(question, consequence.ptr)
            if (standing == errSecSuccess && consequence.worth != null) {
                val worth = CFBridgingRelease(consequence.worth) as? NSData
                return worth?.stringValue
            }
            return null
        }
    }

    non-public enjoyable deleteData(): Boolean {
        memScoped  standing == errSecItemNotFound
        
    }

    non-public enjoyable saveData(worth: String): Boolean {
        memScoped {
            val question = question(
                kSecClass to kSecClassGenericPassword,
                kSecAttrService to SERVICE.toCFDict(),
                kSecAttrAccount to ACCOUNT_TYPE.toCFDict(),
                kSecValueData to worth.toCFDict(),
            )
            var standing = SecItemAdd(question, null)
            if (standing == errSecDuplicateItem) {
                SecItemDelete(question)
                standing = SecItemAdd(question, null)
            }
            return standing == errSecSuccess
        }
    }

    non-public enjoyable question(vararg pairs: Pair<CValuesRef<*>?, CValuesRef<*>?>): CFMutableDictionaryRef? {
        memScoped {
            val dict = CFDictionaryCreateMutable(null, pairs.dimension.toLong(), null, null)
            pairs.forEach {
                CFDictionaryAddValue(dict, it.first, it.second)
            }
            return dict
        }
    }

    non-public enjoyable String.toCFDict(): CFTypeRef? {
        memScoped {
            return CFBridgingRetain(
                NSData.dataWithBytes(
                    bytes = this@toCFDict.cstr.ptr,
                    size = this@toCFDict.size.toULong()
                )
            )
        }
    }

    non-public val NSData.stringValue: String?
        get() = NSString.create(this, NSUTF8StringEncoding) as String?

    companion object {
        const val ACCOUNT_TYPE = "com.myapp"
        const val SERVICE = "www.myapp.com"
    }
}

The supervisor saves accounts appropriately, not less than I feel so cuz on the second name I get the errSecDuplicateItem standing. Nonetheless, once I name getAccount it at all times returns null.

What’s the issue with my code?

UPD

I’ve improved getData() a little bit:

non-public enjoyable getData(): String? {
    memScoped {
        val question = question(
            kSecClass to kSecClassGenericPassword,
            kSecAttrService to SERVICE.toCFDict(),
            kSecAttrAccount to ACCOUNT_TYPE.toCFDict(),
        )
        val consequence = alloc<CFTypeRefVar>()
        val standing = SecItemCopyMatching(question, consequence.ptr)
        when (standing) {
            errSecSuccess -> {
                if (consequence.worth != null) {
                    val worth = CFBridgingRelease(consequence.worth) as? NSData
                    return worth?.stringValue
                } else {
                    throw AccountException(
                        "Error whereas looking for an account, result's null"
                    )
                }
            }
            errSecItemNotFound -> return null
        }
        throw AccountException("Error whereas looking for an account, standing: `$standing`")
    }
}

It crashes with exception: Error whereas looking for an account, result's null, i.e. the search is profitable however the result’s null though saveData() finds duplicates… I do not simply perceive already…

[ad_2]

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments