I want to add a contact (just the name and phone number) programatically in Swift. I've found some Objective-C examples but I didn't get them to work, not even in Objective-C. I don't want this to involve AddressBookUI, because I want to get the values from my own UI.
Here's a quick method to add a contact in Swift. I verified it on my iPhone 5 iOS 7.1 as I've found the simulator doesn't always match the same results as my phone does for AB stuff.
You can add a button and point to this method:
@IBAction func createContact(sender: AnyObject) {
var newContact:ABRecordRef! = ABPersonCreate().takeRetainedValue()
var success:Bool = false
var newFirstName:NSString = "AA"
var newLastName = "a"
//Updated to work in Xcode 6.1
var error: Unmanaged<CFErrorRef>? = nil
//Updated to error to &error so the code builds in Xcode 6.1
success = ABRecordSetValue(newContact, kABPersonFirstNameProperty, newFirstName, &error)
println("setting first name was successful? \(success)")
success = ABRecordSetValue(newContact, kABPersonLastNameProperty, newLastName, &error)
println("setting last name was successful? \(success)")
success = ABAddressBookAddRecord(adbk, newContact, &error)
println("Adbk addRecord successful? \(success)")
success = ABAddressBookSave(adbk, &error)
println("Adbk Save successful? \(success)")
}//createContact
btw-it assumes you've already got an addressbook var assigned, which you can on opening the view by overriding viewDidAppear. It does the security prompt as well:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if !self.authDone {
self.authDone = true
let stat = ABAddressBookGetAuthorizationStatus()
switch stat {
case .Denied, .Restricted:
println("no access")
case .Authorized, .NotDetermined:
var err : Unmanaged<CFError>? = nil
var adbk : ABAddressBook? = ABAddressBookCreateWithOptions(nil, &err).takeRetainedValue()
if adbk == nil {
println(err)
return
}
ABAddressBookRequestAccessWithCompletion(adbk) {
(granted:Bool, err:CFError!) in
if granted {
self.adbk = adbk
} else {
println(err)
}//if
}//ABAddressBookReqeustAccessWithCompletion
}//case
}//if
}//viewDidAppear
Swift 4 & 5
import ContactsUI
Inherit this class CNContactViewControllerDelegate
@IBOutlet var contactNameTxt: UITextField!
@IBOutlet var phoneNumberTxt: UITextField!
@IBAction func saveActionBtn(_ sender: UIButton) {
let store = CNContactStore()
let contact = CNMutableContact()
// Name
contact.givenName = contactNameTxt.text ?? ""
// Phone
contact.phoneNumbers.append(CNLabeledValue(
label: "mobile", value: CNPhoneNumber(stringValue: phoneNumberTxt.text ?? "")))
// Save
let saveRequest = CNSaveRequest()
saveRequest.add(contact, toContainerWithIdentifier: nil)
try? store.execute(saveRequest)
}
Here's a quick method to add a contact in Swift. I verified it on my iPhone 5 iOS 7.1 as I've found the simulator doesn't always match the same results as my phone does for AB stuff.
You can add a button and point to this method:
@IBAction func createContact(sender: AnyObject) {
var newContact:ABRecordRef! = ABPersonCreate().takeRetainedValue()
var success:Bool = false
var newFirstName:NSString = "AA"
var newLastName = "a"
//Updated to work in Xcode 6.1
var error: Unmanaged<CFErrorRef>? = nil
//Updated to error to &error so the code builds in Xcode 6.1
success = ABRecordSetValue(newContact, kABPersonFirstNameProperty, newFirstName, &error)
println("setting first name was successful? \(success)")
success = ABRecordSetValue(newContact, kABPersonLastNameProperty, newLastName, &error)
println("setting last name was successful? \(success)")
success = ABAddressBookAddRecord(adbk, newContact, &error)
println("Adbk addRecord successful? \(success)")
success = ABAddressBookSave(adbk, &error)
println("Adbk Save successful? \(success)")
}//createContact
btw-it assumes you've already got an addressbook var assigned, which you can on opening the view by overriding viewDidAppear. It does the security prompt as well:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if !self.authDone {
self.authDone = true
let stat = ABAddressBookGetAuthorizationStatus()
switch stat {
case .Denied, .Restricted:
println("no access")
case .Authorized, .NotDetermined:
var err : Unmanaged<CFError>? = nil
var adbk : ABAddressBook? = ABAddressBookCreateWithOptions(nil, &err).takeRetainedValue()
if adbk == nil {
println(err)
return
}
ABAddressBookRequestAccessWithCompletion(adbk) {
(granted:Bool, err:CFError!) in
if granted {
self.adbk = adbk
} else {
println(err)
}//if
}//ABAddressBookReqeustAccessWithCompletion
}//case
}//if
}//viewDidAppear
ABAddressBookCreateWithOptions
, though, your err
is unmanaged, so unless you call takeRetainedValue()
for the err, this will leak. Likewise, where you're setting the properties of the ABRecordRef
, (a) I think you can eliminate that UnsafeMutablePointer
and just use var error: Unmanaged<CFErrorRef>?
; and (b) if any of these lines generate an error, you'll want to likewise want to takeRetainedValue
. –
Magnetize Add contact with a button click using swift 3
Add this row in project plist
Privacy - Contacts Usage Description
then
import AddressBook
import Contacts
On button click, you add the following
let newContact = CNMutableContact()
newContact.givenName = "Your Name"
newContact.jobTitle = "CTO xyz Company"
let workEmail = CNLabeledValue(label:CNLabelWork, value:"[email protected]" as NSString)
newContact.emailAddresses = [workEmail]
newContact.phoneNumbers = [CNLabeledValue(
label:CNLabelPhoneNumberiPhone,
value:CNPhoneNumber(stringValue:"0123456789"))]
do {
let saveRequest = CNSaveRequest()
saveRequest.add(newContact, toContainerWithIdentifier: nil)
try AppDelegate.getAppDelegate().contactStore.execute(saveRequest)
} catch {
AppDelegate.getAppDelegate().showMessage("Unable to save the new contact.")
}
On app delegate add some custom class
// MARK: Custom functions
class func getAppDelegate() -> AppDelegate {
return UIApplication.shared.delegate as! AppDelegate
}
func showMessage(_ message: String) {
let alertController = UIAlertController(title: "Birthdays", message: message, preferredStyle: UIAlertControllerStyle.alert)
let dismissAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default) { (action) -> Void in
}
alertController.addAction(dismissAction)
let pushedViewControllers = (self.window?.rootViewController as! UINavigationController).viewControllers
let presentedViewController = pushedViewControllers[pushedViewControllers.count - 1]
presentedViewController.present(alertController, animated: true, completion: nil)
}
func requestForAccess(_ completionHandler: @escaping (_ accessGranted: Bool) -> Void) {
let authorizationStatus = CNContactStore.authorizationStatus(for: CNEntityType.contacts)
switch authorizationStatus {
case .authorized:
completionHandler(true)
case .denied, .notDetermined:
self.contactStore.requestAccess(for: CNEntityType.contacts, completionHandler: { (access, accessError) -> Void in
if access {
completionHandler(access)
}
else {
if authorizationStatus == CNAuthorizationStatus.denied {
DispatchQueue.main.async(execute: { () -> Void in
let message = "\(accessError!.localizedDescription)\n\nPlease allow the app to access your contacts through the Settings."
self.showMessage(message)
})
}
}
})
default:
completionHandler(false)
}
}
You are done; test the project and check the contact app.
I used the following lines of code
var addressBook : ABAddressBookRef = ABAddressBookCreate()
var contactPerson : ABRecordRef = ABPersonCreate()
ABRecordSetValue(contactPerson, kABPersonFirstNameProperty, txtFirstName.text, nil);
ABRecordSetValue(contactPerson, kABPersonLastNameProperty, txtLastName.text, nil);
But when the record that gets inserted contains "nil"
while reading contacts from address book the following snippet helped
var firstName: NSString! = Unmanaged<CFString>.fromOpaque(ABRecordCopyValue(contactPerson, kABPersonFirstNameProperty).toOpaque()).takeUnretainedValue().__conversion()
ABAddressBookCreate()
is deprecated. You really should use ABAddressBookCreateWithOptions()
. For example, let addressBook:ABAddressBookRef! = ABAddressBookCreateWithOptions(nil, &error).takeRetainedValue()
. 2. In the latest betas, the fromOpaque
/toOpaque
dance is no longer needed. For example, let first = ABRecordCopyValue(person, kABPersonFirstNameProperty).takeRetainedValue() as String
. –
Magnetize © 2022 - 2024 — McMap. All rights reserved.
ABAddressBookCreateWithOptions
, though, yourerr
is unmanaged, so unless you calltakeRetainedValue()
for the err, this will leak. Likewise, where you're setting the properties of theABRecordRef
, (a) I think you can eliminate thatUnsafeMutablePointer
and just usevar error: Unmanaged<CFErrorRef>?
; and (b) if any of these lines generate an error, you'll want to likewise want totakeRetainedValue
. – Magnetize