Swift: копирование информации, выбранной пользователем в ABPersonViewController, в словарь

Я пытаюсь реализовать функцию func personViewController(personViewController: ABPersonViewController!, shouldPerformDefaultActionForPerson person: ABRecord!, property property: ABPropertyID, identifier valueIdentifier: ABMultiValueIdentifier) -> Bool, которая является частью протокола ABPersonViewControllerDelegate и вызывается всякий раз, когда пользователь щелкает элемент в ABPersonViewController, так что любая информация, которую выбирает пользователь, будет скопирована в словарь [String : String], так что имя свойства будет ключом для значения свойства: скажем, [..."kABPersonFirstNameProperty" : "Alexander"...].

Я также хочу избежать переключения или длинного списка условий, проверяющих, является ли свойство тем или иным; Я бы предпочел обрабатывать его как можно более широко — я пытаюсь только для двух разных случаев: если свойство является одним значением или несколькими значениями. Если это многозначное значение, я хотел бы скопировать всю доступную информацию.

Например, если пользователь нажмет на адрес, результат может быть таким: [..."kABPersonAddressStreetKey" : "1 Infinite Loop", "kABPersonAddressCityKey" : "Cupertino" , "kABPersonAddressStateKey", "California (or CA?)"...].

Это все, что у меня есть после нескольких часов изучения библиотеки разработчиков Apple и связанных с этим вопросов SO (жалко, я знаю):

func personViewController(personViewController: ABPersonViewController!,
    shouldPerformDefaultActionForPerson person: ABRecord!,
    property property: ABPropertyID,
    identifier valueIdentifier: ABMultiValueIdentifier) -> Bool {

    s["kABPersonFirstNameProperty"] = ABRecordCopyValue(person, kABPersonFirstNameProperty) as! String //the name can't actually be selected by the user, but I want to capture it anyway
    s["kABPersonLastNameProperty"] = ABRecordCopyValue(person, kABPersonLastNameProperty) as! String

    if valueIdentifier == 0 { //property is a single property, not a multivalue property

        let record = ABRecordCopyValue(person, property)
        s[property as! String!] = record as! String

    } else { //property is an ABMultiValue

        let multiRecord = ABRecordCopyValue(person, property) as! ABMultiValueRef
        s[property as! String] = ABMultiValueGetIndexForIdentifier(multiRecord, valueIdentifier)

    }

    return false

}

Я могу сказать, что не хватает многих частей — возможно ли вообще сжать это в словарь?

Заранее спасибо (и 100 репутации тому, кто предоставит полный и правильный ответ).


person 5813    schedule 05.08.2015    source источник
comment
Именно то, что я тоже ищу ... Ресурсы Apple кажутся скудными (и Objective-C-y), когда дело доходит до мира AB.   -  person Randoms    schedule 05.08.2015


Ответы (2)


Используя ответ Вадиана в качестве отправной точки, я составил следующее, которое соберет и скопирует в словарь почти всю информацию, которую может выбрать пользователь (и некоторую информацию, на которую пользователь не может щелкнуть — имя, фамилию, организацию -автоматически).

Это незавершенная работа, которую я буду обновлять по мере добавления поддержки дополнительных свойств, но в настоящее время она работает для имени, фамилии, электронной почты, номеров телефонов, адреса и некоторых профилей в социальных сетях.

В некоторых случаях мне приходилось использовать косвенные методы: например, хранить телефонные номера, метки которых не имеют назначенного ключа kAB_Labels, и они еще не принимают метку адреса электронной почты.

С s по типу Dictionary<String, AnyObject> вот так:

func personViewController(personViewController: ABPersonViewController!, shouldPerformDefaultActionForPerson person: ABRecord!, property: ABPropertyID, identifier: ABMultiValueIdentifier) -> Bool {

    addPropertyForKey("kABPersonFirstNameProperty", person : person, property: kABPersonFirstNameProperty)
    addPropertyForKey("kABPersonLastNameProperty", person : person, property: kABPersonLastNameProperty)
    addPropertyForKey("kABPersonOrganizationProperty", person: person, property: kABPersonOrganizationProperty)

    if (property == kABPersonAddressProperty) {
        let multiRecord : ABMultiValueRef = ABRecordCopyValue(person, property).takeUnretainedValue()
        let index = ABMultiValueGetIndexForIdentifier(multiRecord, identifier)
        let addressRecord :AnyObject = ABMultiValueCopyValueAtIndex(multiRecord, index).takeUnretainedValue()
        addValuesFromRecord(addressRecord, forKeys:["Street", "City", "State", "ZIP", "Country", "CountryCode"])

    }

    if (property == kABPersonEmailProperty) {

        let multiRecord: ABMultiValueRef = ABRecordCopyValue(person, property).takeUnretainedValue()
        let index = ABMultiValueGetIndexForIdentifier(multiRecord, identifier)
        let email = ABMultiValueCopyValueAtIndex(multiRecord, index).takeUnretainedValue() as! String

        if (s["kABPersonEmailProperty(1)"] == nil) {

            s["kABPersonEmailProperty(1)"] = email

        } else {

            s["kABPersonEmailProperty(2)"] = email

        }

    }

    if (property == kABPersonSocialProfileProperty) {

        let multiRecord: ABMultiValueRef = ABRecordCopyValue(person, property).takeUnretainedValue()
        let index = ABMultiValueGetIndexForIdentifier(multiRecord, identifier)
        let profile = ABMultiValueCopyValueAtIndex(multiRecord, index).takeUnretainedValue()
        let profileType = profile["service"] as! String
        let profileName = profile["username"] as! String

        switch profileType {
            case "facebook" : s["kABPersonSocialProfileServiceFacebook"] = profileName
            case  "twitter" : s["kABPersonSocialProfileServiceTwitter"] = profileName
            case "sinaweibo": s["kABPersonSocialProfileServiceSinaWeibo"] = profileName
            default: break
        }



    }

    if (property == kABPersonPhoneProperty) {

        let multiRecord : ABMultiValueRef = ABRecordCopyValue(person, property).takeUnretainedValue()
        let index = ABMultiValueGetIndexForIdentifier(multiRecord, identifier)
        let number = ABMultiValueCopyValueAtIndex(multiRecord, index).takeUnretainedValue() as! String

        let locLabel: CFStringRef = (ABMultiValueCopyLabelAtIndex(multiRecord, index) != nil) ? ABMultiValueCopyLabelAtIndex(multiRecord, index).takeUnretainedValue() as CFStringRef : ""
        let customLabel = String (stringInterpolationSegment: ABAddressBookCopyLocalizedLabel(locLabel))

        var cfStr:CFTypeRef = locLabel
        var nsTypeString = cfStr as! NSString
        var a:String = nsTypeString as String

        var b = a

        if (a.rangeOfString("_$!<") != nil) {

            b = a.substringFromIndex(a.rangeOfString("_$!<")!.endIndex)

            b = b.substringToIndex(b.rangeOfString(">!$_")!.startIndex)

        }

        switch b {

        case "Mobile" : s["kABPersonPhoneMobileLabel"] = number
        case "iPhone" : s["kABPersonPhoneIPhoneLabel"] = number
        case "Main" : s["kABPersonPhoneMainLabel"] = number
        case "Home" : s["kABHomeLabel"] = number
        case "Work" : s["kABWorkLabel"] = number
        case "Other" : s["kABOtherLabel"] = number
        default: break

        }

    }

    println(s)

    return false
}

Пожалуйста, любой может свободно копировать любые/все части, которые могут быть полезны.

person 5813    schedule 06.08.2015

Я боюсь, что не может быть общего метода для извлечения информации из AddressBook, потому что существует слишком много различных типов коллекций и свойств.

Это пример получения информации first name, last name и address, когда пользователь нажимает на поле адреса.

Предполагается, что словарь s объявлен как

var s = Dictionary<String, AnyObject>()

 func personViewController(personViewController: ABPersonViewController!, shouldPerformDefaultActionForPerson person: ABRecord!, property: ABPropertyID, identifier: ABMultiValueIdentifier) -> Bool {

    addPropertyForKey("FirstName", person : person, property: kABPersonFirstNameProperty)
    addPropertyForKey("LastName", person : person, property: kABPersonLastNameProperty)

    if (property == kABPersonAddressProperty) {
      let multiRecord : ABMultiValueRef = ABRecordCopyValue(person, property).takeUnretainedValue()
      let index = ABMultiValueGetIndexForIdentifier(multiRecord, identifier)
      let addressRecord :AnyObject = ABMultiValueCopyValueAtIndex(multiRecord, index).takeUnretainedValue()
      addValuesFromRecord(addressRecord, forKeys:["Street", "City", "State", "ZIP", "Country", "CountryCode"])

      println(s)
    }

    return false
  }

  func addPropertyForKey(key : String, person: ABRecord, property : ABPropertyID)
  {
    let value : AnyObject = ABRecordCopyValue(person, property).takeUnretainedValue()
    s[key] = value
  }

  func addValuesFromRecord(record : AnyObject,  forKeys keys : [String])
  {
    for key in keys {
      if let value : AnyObject = record[key] {
        s[key] = value
      }
    }
  }

чтобы быть как можно более общим, все значения объявляются как AnyObject

person vadian    schedule 06.08.2015