Created
January 9, 2015 19:03
-
-
Save loganwright/8865d4ea792b9533cf7b to your computer and use it in GitHub Desktop.
SwiftContact - Converting ABRecordRef to Clean, usable contact object
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Contact.swift | |
// FriendLender | |
// | |
// Created by Logan Wright on 9/22/14. | |
// Copyright (c) 2014 lowriDevs. All rights reserved. | |
// | |
import UIKit | |
import AddressBook | |
// MARK: Debugging | |
private let ContactDebug = false | |
// MARK: NSCoding Constants | |
private let ContactFirstNameKey = "firstNameKey" | |
private let ContactFirstNamePhoneticKey = "firstNamePhoneticKey" | |
private let ContactMiddleNameKey = "middleNameKey" | |
private let ContactMiddleNamePhoneticKey = "middleNamePhoneticKey" | |
private let ContactLastNameKey = "lastNameKey" | |
private let ContactLastNamePhoneticKey = "lastNamePhoneticKey" | |
private let ContactPrefixKey = "prefixKey" | |
private let ContactSuffixKey = "suffixKey" | |
private let ContactNicknameKey = "nicknameKey" | |
private let ContactBirthDateKey = "birthDateKey" | |
private let ContactCreationDateKey = "creationDateKey" | |
private let ContactModificationDateKey = "modificationDateKey" | |
private let ContactOrganizationKey = "organizationKey" | |
private let ContactJobTitleKey = "jobTitleKey" | |
private let ContactDepartmentKey = "departmentKey" | |
private let ContactPhoneNumbersKey = "phoneNumbersKey" | |
private let ContactEmailsKey = "emailsKey" | |
private let ContactNoteKey = "noteKey" | |
// MARK: Contact Class | |
class Contact: NSObject, NSCoding { | |
// MARK: Names | |
var firstName: String? | |
var firstNamePhonetic: String? | |
var middleName: String? | |
var middleNamePhonetic: String? | |
var lastName: String? | |
var lastNamePhonetic: String? | |
var prefix: String? // Prefix ("Sir" "Duke" "General") - kABStringPropertyType | |
var suffix: String? // Suffix ("Jr." "Sr." "III") - kABStringPropertyType | |
var nickname: String? | |
var fullName: String? { | |
get { | |
var fullName: String = "" | |
if let firstName = self.firstName { | |
fullName += firstName | |
} | |
if let lastName = self.lastName { | |
if countElements(fullName) > 0 { | |
fullName += " " | |
} | |
fullName += lastName | |
} | |
return countElements(fullName) > 0 ? fullName : nil | |
} | |
} | |
// MARK: Dates | |
var birthDate: NSDate? | |
var creationDate: NSDate? | |
var modificationDate: NSDate? | |
// MARK: Work | |
var organization: String? | |
var jobTitle: String? | |
var department: String? | |
// MARK: Contact Information | |
var phoneNumbers: PhoneNumbers? | |
var emails: Emails? | |
// MARK: Additional Info | |
var note: String? | |
// MARK: Initialization | |
init(recordRef: ABRecordRef) { | |
super.init() | |
self.initializeNamesWithABRecordRef(recordRef) | |
self.initializeWorkInfoWithABRecordRef(recordRef) | |
self.initializeCreationInfoWithABRecordRef(recordRef) | |
self.birthDate = self.rawValueFromABRecordRef(recordRef, forProperty: kABPersonBirthdayProperty) as? NSDate | |
self.note = self.rawValueFromABRecordRef(recordRef, forProperty: kABPersonNoteProperty) as? String | |
if let phonesRef: Unmanaged<AnyObject> = ABRecordCopyValue(recordRef, kABPersonPhoneProperty){ | |
self.phoneNumbers = PhoneNumbers(phoneNumbersRef: phonesRef.takeRetainedValue() as ABMultiValueRef) | |
} | |
if let emailRef: Unmanaged<AnyObject> = ABRecordCopyValue(recordRef, kABPersonEmailProperty){ | |
self.emails = Emails(emailsRef: emailRef.takeRetainedValue() as ABMultiValueRef) | |
} | |
} | |
func initializeNamesWithABRecordRef(recordRef: ABRecordRef) { | |
self.firstName = self.rawValueFromABRecordRef(recordRef, forProperty: kABPersonFirstNameProperty) as? String | |
self.firstNamePhonetic = self.rawValueFromABRecordRef(recordRef, forProperty: kABPersonFirstNamePhoneticProperty) as? String | |
self.lastName = self.rawValueFromABRecordRef(recordRef, forProperty: kABPersonLastNameProperty) as? String | |
self.lastNamePhonetic = self.rawValueFromABRecordRef(recordRef, forProperty: kABPersonLastNamePhoneticProperty) as? String | |
self.middleName = self.rawValueFromABRecordRef(recordRef, forProperty: kABPersonMiddleNameProperty) as? String | |
self.middleNamePhonetic = self.rawValueFromABRecordRef(recordRef, forProperty: kABPersonMiddleNamePhoneticProperty) as? String | |
self.prefix = self.rawValueFromABRecordRef(recordRef, forProperty: kABPersonPrefixProperty) as? String | |
self.suffix = self.rawValueFromABRecordRef(recordRef, forProperty: kABPersonSuffixProperty) as? String | |
self.nickname = self.rawValueFromABRecordRef(recordRef, forProperty: kABPersonNicknameProperty) as? String | |
} | |
func initializeWorkInfoWithABRecordRef(recordRef: ABRecordRef) { | |
self.organization = self.rawValueFromABRecordRef(recordRef, forProperty: kABPersonOrganizationProperty) as? String | |
self.jobTitle = self.rawValueFromABRecordRef(recordRef, forProperty: kABPersonJobTitleProperty) as? String | |
self.department = self.rawValueFromABRecordRef(recordRef, forProperty: kABPersonDepartmentProperty) as? String | |
} | |
func initializeCreationInfoWithABRecordRef(recordRef: ABRecordRef) { | |
self.creationDate = self.rawValueFromABRecordRef(recordRef, forProperty: kABPersonCreationDateProperty) as? NSDate | |
self.modificationDate = self.rawValueFromABRecordRef(recordRef, forProperty: kABPersonModificationDateProperty) as? NSDate | |
} | |
// MARK: Getting Properties From RecordRef | |
func rawValueFromABRecordRef(recordRef: ABRecordRef, forProperty property: ABPropertyID) -> AnyObject? { | |
return ABRecordCopyValue(recordRef, property).takeRetainedValue() | |
} | |
// MARK: NSCoding | |
func encodeWithCoder(aCoder: NSCoder) { | |
if firstName != nil {aCoder.encodeObject(firstName!, forKey: ContactFirstNameKey)} | |
if firstNamePhonetic != nil {aCoder.encodeObject(firstNamePhonetic!, forKey: ContactFirstNamePhoneticKey)} | |
if middleName != nil {aCoder.encodeObject(middleName!, forKey: ContactMiddleNameKey)} | |
if middleNamePhonetic != nil {aCoder.encodeObject(middleNamePhonetic!, forKey: ContactMiddleNamePhoneticKey)} | |
if lastName != nil {aCoder.encodeObject(lastName!, forKey: ContactLastNameKey)} | |
if lastNamePhonetic != nil {aCoder.encodeObject(lastNamePhonetic!, forKey: ContactLastNamePhoneticKey)} | |
if prefix != nil {aCoder.encodeObject(prefix!, forKey: ContactPrefixKey)} | |
if suffix != nil {aCoder.encodeObject(suffix!, forKey: ContactSuffixKey)} | |
if nickname != nil {aCoder.encodeObject(nickname!, forKey: ContactNicknameKey)} | |
if birthDate != nil {aCoder.encodeObject(birthDate!, forKey: ContactBirthDateKey)} | |
if creationDate != nil {aCoder.encodeObject(creationDate!, forKey: ContactCreationDateKey)} | |
if modificationDate != nil {aCoder.encodeObject(modificationDate!, forKey: ContactModificationDateKey)} | |
if organization != nil {aCoder.encodeObject(organization!, forKey: ContactOrganizationKey)} | |
if jobTitle != nil {aCoder.encodeObject(jobTitle!, forKey: ContactJobTitleKey)} | |
if department != nil {aCoder.encodeObject(department!, forKey: ContactDepartmentKey)} | |
if phoneNumbers != nil {aCoder.encodeObject(phoneNumbers!, forKey: ContactPhoneNumbersKey)} | |
if emails != nil {aCoder.encodeObject(emails!, forKey: ContactEmailsKey)} | |
if note != nil {aCoder.encodeObject(note!, forKey: ContactNoteKey)} | |
} | |
required init(coder aDecoder: NSCoder) { | |
self.firstName = aDecoder.decodeObjectForKey(ContactFirstNameKey) as? String | |
self.firstNamePhonetic = aDecoder.decodeObjectForKey(ContactFirstNamePhoneticKey) as? String | |
self.middleName = aDecoder.decodeObjectForKey(ContactMiddleNameKey) as? String | |
self.middleNamePhonetic = aDecoder.decodeObjectForKey(ContactMiddleNamePhoneticKey) as? String | |
self.lastName = aDecoder.decodeObjectForKey(ContactLastNameKey) as? String | |
self.lastNamePhonetic = aDecoder.decodeObjectForKey(ContactLastNamePhoneticKey) as? String | |
self.prefix = aDecoder.decodeObjectForKey(ContactPrefixKey) as? String | |
self.suffix = aDecoder.decodeObjectForKey(ContactSuffixKey) as? String | |
self.nickname = aDecoder.decodeObjectForKey(ContactNicknameKey) as? String | |
self.birthDate = aDecoder.decodeObjectForKey(ContactBirthDateKey) as? NSDate | |
self.creationDate = aDecoder.decodeObjectForKey(ContactCreationDateKey) as? NSDate | |
self.modificationDate = aDecoder.decodeObjectForKey(ContactModificationDateKey) as? NSDate | |
self.organization = aDecoder.decodeObjectForKey(ContactOrganizationKey) as? String | |
self.jobTitle = aDecoder.decodeObjectForKey(ContactJobTitleKey) as? String | |
self.department = aDecoder.decodeObjectForKey(ContactDepartmentKey) as? String | |
self.phoneNumbers = aDecoder.decodeObjectForKey(ContactPhoneNumbersKey) as? PhoneNumbers | |
self.emails = aDecoder.decodeObjectForKey(ContactEmailsKey) as? Emails | |
self.note = aDecoder.decodeObjectForKey(ContactNoteKey) as? String | |
} | |
} | |
// MARK: Emails Class NSCoding Constants | |
private let EmailsHomeKey = "EmailsHomeKey" | |
private let EmailsWorkKey = "EmailsWorkKey" | |
private let EmailsOtherKey = "EmailsOtherKey" | |
private let EmailsUnknownEmailsKey = "EmailsUnknownEmailsKey" | |
// MARK: Emails | |
class Emails: NSObject, NSCoding { | |
// MARK: Public Properties | |
var home: String? | |
var work: String? | |
var other: String? | |
var unknownEmails: [String : String] = [:] | |
var bestEmail: String? { | |
get { | |
var bestEmail: String? | |
if let home = home { | |
bestEmail = home | |
} else if let work = work { | |
bestEmail = work | |
} else if let other = other { | |
bestEmail = other | |
} else if unknownEmails.count > 0 { | |
bestEmail = unknownEmails.values.first | |
} | |
return bestEmail | |
} | |
} | |
// MARK: Initialization | |
init(emailsRef: ABMultiValueRef) { | |
super.init() | |
for i in 0..<ABMultiValueGetCount(emailsRef) { | |
let emailKey = (ABMultiValueCopyLabelAtIndex(emailsRef, i).takeRetainedValue() as CFStringRef) | |
let emailValue = ABMultiValueCopyValueAtIndex(emailsRef, i).takeRetainedValue() as String | |
if emailKey == kABHomeLabel { | |
home = emailValue | |
} | |
else if emailKey == kABWorkLabel { | |
work = emailValue | |
} | |
else if emailKey == kABOtherLabel { | |
other = emailValue | |
} | |
else { | |
if ContactDebug {println("UnknownEmailKey: \(emailKey) Val: \(emailValue)")} | |
/* | |
I implemented all of the available keys as well as Home, not sure if other keys exist. Just in case, I store unexpected values here. | |
*/ | |
unknownEmails[emailKey] = emailValue | |
} | |
if ContactDebug { | |
println("EmailKey: \(emailKey)") | |
println("EmailVal: \(emailValue)") | |
} | |
} | |
} | |
// MARK: NSCoding | |
func encodeWithCoder(aCoder: NSCoder) { | |
if home != nil {aCoder.encodeObject(home!, forKey: EmailsHomeKey)} | |
if work != nil {aCoder.encodeObject(work!, forKey: EmailsWorkKey)} | |
if other != nil {aCoder.encodeObject(other!, forKey: EmailsOtherKey)} | |
if unknownEmails.count > 0 {aCoder.encodeObject(unknownEmails, forKey: EmailsUnknownEmailsKey)} | |
} | |
required init(coder aDecoder: NSCoder) { | |
home = aDecoder.decodeObjectForKey(EmailsHomeKey) as? String | |
work = aDecoder.decodeObjectForKey(EmailsWorkKey) as? String | |
other = aDecoder.decodeObjectForKey(EmailsOtherKey) as? String | |
if let decodedUnknownEmails = aDecoder.decodeObjectForKey(EmailsUnknownEmailsKey) as? [String : String] { | |
unknownEmails = decodedUnknownEmails | |
} | |
} | |
} | |
// MARK: Phone Numbers Class NSCoding Constants | |
private let PhoneNumbersMobileKey = "PhoneNumbersMobileKey" | |
private let PhoneNumbersIPhoneKey = "PhoneNumbersIPhoneKey" | |
private let PhoneNumbersMainKey = "PhoneNumbersMainKey" | |
private let PhoneNumbersFaxHomeKey = "PhoneNumbersFaxHomeKey" | |
private let PhoneNumbersFaxWorkKey = "PhoneNumbersFaxWorkKey" | |
private let PhoneNumbersFaxOtherKey = "PhoneNumbersFaxOtherKey" | |
private let PhoneNumbersPagerKey = "PhoneNumbersPagerKey" | |
private let PhoneNumbersHomeKey = "PhoneNumbersHomeKey" | |
private let PhoneNumbersUnknownNumbersKey = "PhoneNumbersUnknownNumbersKey" | |
// MARK: PhoneNumbers | |
class PhoneNumbers: NSObject, NSCoding { | |
// MARK: Public Properties | |
var mobile: String? | |
var iPhone: String? | |
var main: String? | |
var home: String? | |
var faxHome: String? | |
var faxWork: String? | |
var faxOther: String? | |
var pager: String? | |
var unknownNumbers: [String : String] = [:] | |
var bestTextNumber: String? { | |
get { | |
var textNumber: String? | |
if let iPhone = iPhone { | |
textNumber = iPhone | |
} else if let mobile = mobile { | |
textNumber = mobile | |
} else if let main = main { | |
textNumber = main | |
} | |
return textNumber | |
} | |
} | |
var bestPhoneNumber: String? { | |
get { | |
var phoneNumber: String? | |
if let iPhone = iPhone { | |
phoneNumber = iPhone | |
} else if let mobile = mobile { | |
phoneNumber = mobile | |
} else if let main = main { | |
phoneNumber = main | |
} else if let home = home { | |
phoneNumber = home | |
} | |
return phoneNumber | |
} | |
} | |
// MARK: Initialization | |
init(phoneNumbersRef: ABMultiValueRef) { | |
super.init() | |
for i in 0..<ABMultiValueGetCount(phoneNumbersRef) { | |
let phoneNumberKey = (ABMultiValueCopyLabelAtIndex(phoneNumbersRef, i).takeRetainedValue() as CFStringRef) | |
let phoneNumberValue = ABMultiValueCopyValueAtIndex(phoneNumbersRef, i).takeRetainedValue() as String | |
if phoneNumberKey == kABPersonPhoneMobileLabel { | |
self.mobile = phoneNumberValue; | |
} | |
else if phoneNumberKey == kABPersonPhoneIPhoneLabel { | |
self.iPhone = phoneNumberValue; | |
} | |
else if phoneNumberKey == kABPersonPhoneMainLabel { | |
self.main = phoneNumberValue; | |
} | |
else if phoneNumberKey == kABPersonPhoneHomeFAXLabel { | |
self.faxHome = phoneNumberValue; | |
} | |
else if phoneNumberKey == kABPersonPhoneWorkFAXLabel { | |
self.faxWork = phoneNumberValue; | |
} | |
else if phoneNumberKey == kABPersonPhoneOtherFAXLabel { | |
self.faxOther = phoneNumberValue; | |
} | |
else if phoneNumberKey == kABPersonPhonePagerLabel { | |
self.pager = phoneNumberValue | |
} | |
else if phoneNumberKey == "_$!<Home>!$_" { | |
self.home = phoneNumberValue | |
} | |
else { | |
if ContactDebug {println("UnknownPhoneNumberKey: \(phoneNumberKey) Val: \(phoneNumberValue)")} | |
/* | |
I implemented all of the available keys as well as Home, not sure if other keys exist. Just in case, I store unexpected values here. | |
*/ | |
unknownNumbers[phoneNumberKey] = phoneNumberValue | |
} | |
if ContactDebug { | |
println("PhoneNumberKey: \(phoneNumberKey)") | |
println("PhoneNumberVal: \(phoneNumberValue)") | |
} | |
} | |
} | |
// MARK: NSCoding | |
func encodeWithCoder(aCoder: NSCoder) { | |
if mobile != nil {aCoder.encodeObject(mobile!, forKey: PhoneNumbersMobileKey)} | |
if iPhone != nil {aCoder.encodeObject(iPhone!, forKey: PhoneNumbersIPhoneKey)} | |
if main != nil {aCoder.encodeObject(main!, forKey: PhoneNumbersMainKey)} | |
if faxHome != nil {aCoder.encodeObject(faxHome!, forKey: PhoneNumbersFaxHomeKey)} | |
if faxWork != nil {aCoder.encodeObject(faxWork!, forKey: PhoneNumbersFaxWorkKey)} | |
if faxOther != nil {aCoder.encodeObject(faxOther!, forKey: PhoneNumbersFaxOtherKey)} | |
if pager != nil {aCoder.encodeObject(pager!, forKey: PhoneNumbersPagerKey)} | |
if home != nil {aCoder.encodeObject(home!, forKey: PhoneNumbersHomeKey)} | |
if unknownNumbers.count > 0 {aCoder.encodeObject(unknownNumbers, forKey: PhoneNumbersUnknownNumbersKey)} | |
} | |
required init(coder aDecoder: NSCoder) { | |
mobile = aDecoder.decodeObjectForKey(PhoneNumbersMobileKey) as? String | |
iPhone = aDecoder.decodeObjectForKey(PhoneNumbersIPhoneKey) as? String | |
main = aDecoder.decodeObjectForKey(PhoneNumbersMainKey) as? String | |
faxHome = aDecoder.decodeObjectForKey(PhoneNumbersFaxHomeKey) as? String | |
faxWork = aDecoder.decodeObjectForKey(PhoneNumbersFaxWorkKey) as? String | |
faxOther = aDecoder.decodeObjectForKey(PhoneNumbersFaxOtherKey) as? String | |
pager = aDecoder.decodeObjectForKey(PhoneNumbersPagerKey) as? String | |
home = aDecoder.decodeObjectForKey(PhoneNumbersHomeKey) as? String | |
if let decodedUnknownNumbersDict = aDecoder.decodeObjectForKey(PhoneNumbersUnknownNumbersKey) as? [String : String] { | |
unknownNumbers = decodedUnknownNumbersDict | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This crashes with Xcode 6.3 beta 3 for nil values. I fixed it this way: