Skip to content

Instantly share code, notes, and snippets.

@loganwright
Created January 9, 2015 19:03
Show Gist options
  • Save loganwright/8865d4ea792b9533cf7b to your computer and use it in GitHub Desktop.
Save loganwright/8865d4ea792b9533cf7b to your computer and use it in GitHub Desktop.

Revisions

  1. loganwright created this gist Jan 9, 2015.
    413 changes: 413 additions & 0 deletions Contact.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,413 @@
    //
    // 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
    }
    }
    }