Swift: Copy Information Selected by User in Abpersonviewcontroller to Dictionary

Swift: Copy Information Selected by User in ABPersonViewController to Dictionary

Using vadian's answer as a starting point, I compiled the following, which will gather and copy to a dictionary almost all of the information a user can select (and some information which a user can't click on—first name, last name, organization—automatically).

It's a work in progress, which I'll update as I continue to add support for more properties, but at present it works for first name, last name, email, phone numbers, address, and some social profiles.

I had to use indirect methods in some cases: storing phone numbers whose labels didn't have a designated key as kAB_Labels, for example, and it doesn't yet take the label of an email address.

With s as of type Dictionary<String, AnyObject>, here it is:

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
}

Please, anyone should feel free to copy any/all parts of it which would be helpful.

Optional Type 'String??' Not Unwrapped

Dictionary<T1, T2>[key] returns T2?. This is to return nil in case key doesn't exist.

So if T2 is String?, s[key] returns String??
You cannot pass String?? as String?

You can call like this to unwrap and prepare for non-existing key as well

var text = combine(s["kABPersonFirstNameProperty"] ?? nil, lastname: s["kABPersonLastNameProperty"] ?? nil)

By the way, code below will not set value to nil but remove the entire entry from the dictionary

s[key] = nil

If you want the value to be nil instead of removing entry, you will have to do this

s[key] = nil as String?

MKAnnotationView Push to View Controller when DetailDesclosure Button is Clicked

If you are using storyboards and have a segue from your current scene to your destination scene, you can just respond to calloutAccessoryControlTapped. For example:

- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
[self performSegueWithIdentifier:@"Details" sender:view];
}

Obviously, you can check for the type of annotation associated with that view, etc., if you have different segues you want to call for different annotation types.

And, of course, if you want to pass any information to that next scene in prepareForSegue like usual.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:@"Details"])
{
MKAnnotationView *annotationView = sender;
[segue.destinationViewController setAnnotation:annotationView.annotation];
}
}

As you can see, I pass the annotation object to my next view. If you have additional fields in your JSON structure that are associated with each annotation, one easy solution is to add properties to your custom view associated for each of the fields you want to track. Just go to the .h for your annotation custom class and add the properties you need. And then when you create your custom annotations (to be added to the map), just set these properties, too. Then, when you pass this annotation to the next view controller, all of your desired properties will be available there.


Clearly, if you're using NIBs, just do the NIB equivalents of whatever you want for instantiating the next view controller, setting whatever properties you want, and either pushing to it or presenting it modally, e.g.:

- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
DetailsViewController *controller = [[DetailsViewController alloc] initWithNibName:nil
bundle:nil];
controller.annotation = annotationView.annotation;
[self.navigationController pushViewController:controller animated:YES]; // or use presentViewController if you're using modals
}

Table View Cell Stays Highlighted

in didSelectRowAtIndexPath you just need to make a call to deselect the row

    [self.tableView deselectRowAtIndexPath:indexPath animated:YES];


Related Topics



Leave a reply



Submit