Skip to content

Instantly share code, notes, and snippets.

@tigi44
Created January 5, 2022 06:27
Show Gist options
  • Save tigi44/cbf496f5f1f3d6f4ff28e7f2dd88079a to your computer and use it in GitHub Desktop.
Save tigi44/cbf496f5f1f3d6f4ff28e7f2dd88079a to your computer and use it in GitHub Desktop.
use a propertyWrapper for keychain in SwiftUI
import Foundation
class KeyChainHelper {
static let shared = KeyChainHelper()
func save(data: Data, key: String, account: String) {
let query = [
kSecValueData: data,
kSecAttrAccount: account,
kSecAttrService: key,
kSecClass: kSecClassGenericPassword
] as CFDictionary
let status = SecItemAdd(query, nil)
switch status {
case errSecSuccess: print("success")
case errSecDuplicateItem:
let query = [
kSecValueData: data,
kSecAttrAccount: account,
kSecAttrService: key,
kSecClass: kSecClassGenericPassword
] as CFDictionary
let updateAttr = [kSecValueData: data] as CFDictionary
SecItemUpdate(query, updateAttr)
default: print("Error \(status)")
}
}
func read(key: String, account: String) -> Data? {
let query = [
kSecAttrAccount: account,
kSecAttrService: key,
kSecClass: kSecClassGenericPassword,
kSecReturnData: true
] as CFDictionary
var resultData: AnyObject?
SecItemCopyMatching(query, &resultData)
return resultData as? Data
}
func delete(key: String, account: String) {
let query = [
kSecAttrAccount: account,
kSecAttrService: key,
kSecClass: kSecClassGenericPassword,
] as CFDictionary
SecItemDelete(query)
}
}
import SwiftUI
@propertyWrapper
struct KeyChainPropertyWrapper: DynamicProperty {
@State var data: Data?
var wrappedValue: Data? {
get {
data
}
nonmutating set {
guard let newValue = newValue else {
data = nil
KeyChainHelper.shared.delete(key: key, account: account)
return
}
KeyChainHelper.shared.save(data: newValue, key: key, account: account)
data = newValue
}
}
var key: String
var account: String
init(key: String, account: String) {
self.key = key
self.account = account
_data = State(wrappedValue: KeyChainHelper.shared.read(key: key, account: account))
}
}
import SwiftUI
struct KeyChainView: View {
@KeyChainPropertyWrapper(key: "text", account: "keychainview") var textData
@State var inputText: String = ""
var body: some View {
VStack {
HStack {
TextField("input", text: $inputText)
.padding()
.background(.thinMaterial)
.cornerRadius(10)
Button("save") {
let textData = inputText.data(using: .utf8)
self.textData = textData
}
}
.padding(.horizontal)
HStack(spacing: 0) {
Text("Saved Text : ")
if let textData = textData {
Text(String(data: textData, encoding: .utf8) ?? "no saved text")
}
}
.padding()
}
}
}
struct KeyChainView_Previews: PreviewProvider {
static var previews: some View {
KeyChainView()
}
}
@tigi44
Copy link
Author

tigi44 commented Jan 5, 2022

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment