Skip to content

Instantly share code, notes, and snippets.

@qnoid
Last active June 16, 2017 19:24
Show Gist options
  • Save qnoid/c230d3b0033e33e6c0d5 to your computer and use it in GitHub Desktop.
Save qnoid/c230d3b0033e33e6c0d5 to your computer and use it in GitHub Desktop.
This is a sample project to demonstrate how you can use a computed property to create a reusable function ("closure") that mimics a constant value. Think of it as a way to encapsulate both the data and the function it applies to.
//
// AppDelegate.swift
// Keychain
//
// Created by Markos Charatzas on 07/09/2014.
// Copyright (c) 2014 qnoid.com. All rights reserved.
//
import Cocoa
//Keychain
struct KeychainAccount
{
let serviceName : String
let name : String
}
class Keychain
{
var keychain:SecKeychainRef!
class func defaultKeychain() -> Keychain {
return Keychain()
}
func addGenericPassword(account:KeychainAccount, password:String) -> OSStatus
{
let status = SecKeychainAddGenericPassword(self.keychain,
UInt32(countElements(account.serviceName.utf8)), account.serviceName,
UInt32(countElements(account.name.utf8)), account.name,
UInt32(countElements(password.utf8)), password,
nil)
return status;
}
func findGenericPassword(account:KeychainAccount) -> (status:OSStatus, password:String?) {
var passwordLength: UInt32 = 0
var passwordPtr: UnsafeMutablePointer<Void> = nil
let status = SecKeychainFindGenericPassword(
nil,
UInt32(countElements(account.serviceName.utf8)),
account.serviceName,
UInt32(countElements(account.name.utf8)),
account.name,
&passwordLength,
&passwordPtr,
nil)
if status == OSStatus(errSecSuccess) {
let password = NSString(bytes: passwordPtr, length: Int(passwordLength), encoding: NSUTF8StringEncoding)
return (status, password)
}
return (status, nil)
}
}
//extension Keychain
typealias KeychainCreateUser = (String) -> OSStatus
typealias KeychainFindUser = () -> NSString?
let KeychainAccountIOWindmillUser = KeychainAccount(serviceName: "io.windmill", name: "io.windmill.user")
extension Keychain
{
var createUser : KeychainCreateUser
{
func createUser(user:String) -> OSStatus {
return self.addGenericPassword(KeychainAccountIOWindmillUser, password:user)
}
return createUser;
}
var findUser : KeychainFindUser
{
func findUser() -> NSString?
{
let account = self.findGenericPassword(KeychainAccountIOWindmillUser);
if let user = account.password{
return user;
}
return nil
}
return findUser;
}
/**
Creates a new user under the KeychainAccountIOWindmillUsers if one doesn't already exist.
@param user the user to create
@return true if created, false otherwise
*/
func createUser(user:String) -> Bool
{
if let user = self.findUser(){
return false
}
self.createUser(user)
return true
}
}
//AppDelegate
class AppDelegate: NSObject, NSApplicationDelegate
{
@IBOutlet weak var window: NSWindow!
var keychain : Keychain {
return Keychain.defaultKeychain()
}
func applicationDidFinishLaunching(aNotification: NSNotification?)
{
self.keychain.createUser("qnoid")
}
func applicationWillTerminate(aNotification: NSNotification?) {
}
}
@qnoid
Copy link
Author

qnoid commented Sep 7, 2014

See https://devforums.apple.com/message/1036179#1036179 for answers to the following two questions.

  1. Given that the computed property "createUser" shares the same name and arguments as the method #createUser, which one will be called? Running the code, it's the property. However, if the property is private there is no doubt, tho still fragile)
  2. Will the #createUser method create a recursion? Running the code, doesn't look like it, tho not sure what are the exact requirements.

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