Area:
Contacts Framework
Summary:
When attempting to save a contact that has populated Social Profile data the following error is encountered: This is seen in iOS 11.3.1
In AddressBook on a device, I have a record linked to the Facebook and Twitter contact record. I fetch it into CNContact with CNContactFetchRequest, for detail code please find code :
@IBAction func btnSaveClick(_ sender: Any) {
//Create
if txtFname.text == "" {
Global.singleton.showWarningAlert(withMsg: "Please Enter First name")
return
}
else if txtName.text == "" {
Global.singleton.showWarningAlert(withMsg: "Please Enter Last name")
return
}
else if (txtCompany.text == "") {
Global.singleton.showWarningAlert(withMsg: "Please Enter Company name")
return
}
else if (txtTitle.text == "") {
Global.singleton.showWarningAlert(withMsg: "Please Enter Position")
return
}
var stop : Int = 0
for i in (0..<arrEmails.count){
let indexpath : IndexPath = IndexPath(row: i, section: 1)
let cell : EmailCell? = self.tblCreateContact.cellForRow(at: indexpath) as! EmailCell?
if (cell?.txtEmail.text != "") {
if !Global.singleton.validateEmail(strEmail: (cell?.txtEmail.text!)!){
Global.singleton.showWarningAlert(withMsg: "Please Enter proper email")
stop = 1
break
}
}
}
if stop == 1 {
return
}
var stopUrl : Int = 0
for i in (0..<arrURLs.count){
let indexpath : IndexPath = IndexPath(row: i, section: 2)
let cell : URLCell? = self.tblCreateContact.cellForRow(at: indexpath) as! URLCell?
if (cell?.txtURL.text != "") {
if cell!.txtURL.text!.range(of: "http") == nil {
cell!.txtURL.text = "http://\(cell!.txtURL.text!)"
}
if(self.validateUrl(stringURL: (cell?.txtURL.text)!)){
print("candidate is a well-formed url with")
} else {
stopUrl = 1
Global.singleton.showWarningAlert(withMsg: "Please Enter proper URL")
break
}
}
}
if stopUrl == 1 {
return
}
var stopCountry : Int = 0
for i in (0..<arrAddress.count){
let indexpath : IndexPath = IndexPath(row: i, section: 5)
let cell : AddressCell? = self.tblCreateContact.cellForRow(at: indexpath) as! AddressCell?
if cell?.txtCountry.text != "" {
if (self.isValidCountryInput(Input: (cell?.txtCountry.text!)!)){
}
else {
stopCountry = 1
Global.singleton.showWarningAlert(withMsg: "Please Enter proper Country Name")
break
}
}
}
if stopCountry == 1 {
return
}
let contact : CNMutableContact = CNMutableContact()
contact.givenName = txtName.text!
contact.familyName = txtFname.text!
contact.jobTitle = txtTitle.text!
contact.organizationName = txtCompany.text!
contact.emailAddresses = []
contact.phoneNumbers = []
for i in (0..<arrPhones.count){
let indexpath : IndexPath = IndexPath(row: i, section: 0)
let cell : PhoneCell? = self.tblCreateContact.cellForRow(at: indexpath) as! PhoneCell?
let shrO : ContactShare = arrPhones.object(at: i) as! ContactShare
if (cell?.txtPhone.text) != "" {
shrO.strValue = (cell?.txtPhone.text)!
shrO.strtype = (cell?.btnType.titleLabel?.text)!
if (i == 0) {
contact.phoneNumbers.append(CNLabeledValue(
label:CNLabelPhoneNumberMain,
value:CNPhoneNumber(stringValue:(cell?.txtPhone.text)!)))
}
else if (i==1) {
contact.phoneNumbers.append(CNLabeledValue(
label:CNLabelPhoneNumberMobile,
value:CNPhoneNumber(stringValue:(cell?.txtPhone.text)!)))
}
else {
contact.phoneNumbers.append(CNLabeledValue(
label:CNLabelPhoneNumberiPhone,
value:CNPhoneNumber(stringValue:(cell?.txtPhone.text)!)))
}
}
}
for i in (0..<arrEmails.count){
let indexpath : IndexPath = IndexPath(row: i, section: 1)
let cell : EmailCell? = self.tblCreateContact.cellForRow(at: indexpath) as! EmailCell?
if cell?.txtEmail.text != "" {
if !Global.singleton.validateEmail(strEmail: (cell?.txtEmail.text!)!){
Global.singleton.showSuccessAlert(withMsg: "Please Enter proper email")
break
}
}
let shrO : ContactShare = arrEmails.object(at: i) as! ContactShare
if (cell?.txtEmail.text) != nil {
shrO.strValue = (cell?.txtEmail.text)!
shrO.strtype = (cell?.btnType.titleLabel?.text)!
if shrO.strtype == "Work" {
let workEmail1 = CNLabeledValue(label:"WorkEmail", value:(cell?.txtEmail.text ?? "") as NSString)
contact.emailAddresses.append(workEmail1)
}
else{
let workEmail1 = CNLabeledValue(label:"Home", value:(cell?.txtEmail.text ?? "") as NSString)
contact.emailAddresses.append(workEmail1)
}
}
}
for i in (0..<arrURLs.count){
let indexpath : IndexPath = IndexPath(row: i, section: 2)
let cell : URLCell? = self.tblCreateContact.cellForRow(at: indexpath) as! URLCell?
let shrO : ContactShare = arrURLs.object(at: i) as! ContactShare
if (cell?.txtURL.text) != nil {
shrO.strValue = (cell?.txtURL.text)!
shrO.strtype = (cell?.btnType.titleLabel?.text)!
let workURL = CNLabeledValue(label:"URL", value:(cell?.txtURL.text ?? "") as NSString)
contact.urlAddresses.append(workURL)
}
}
for i in (0..<arrSocials.count){
let indexpath : IndexPath = IndexPath(row: i, section: 3)
let cell : SocialCell? = self.tblCreateContact.cellForRow(at: indexpath) as! SocialCell?
let shrO : ContactShare = arrSocials.object(at: i) as! ContactShare
if (cell?.txtSocial.text) != nil {
shrO.strValue = (cell?.txtSocial.text)!
shrO.strtype = (cell?.btnType.titleLabel?.text)!
if (shrO.strtype == "Facebook") {
let facebookProfile = CNLabeledValue(label: "Facebook", value: CNSocialProfile(urlString: shrO.strValue, username: "", userIdentifier: "", service: CNSocialProfileServiceFacebook))
contact.socialProfiles.append(facebookProfile)
}
else {
let twitterProfile = CNLabeledValue(label: "Twitter", value: CNSocialProfile(urlString: shrO.strValue, username: "", userIdentifier: "", service: CNSocialProfileServiceTwitter))
contact.socialProfiles.append(twitterProfile)
}
}
}
for i in (0..<arrInstantMsg.count){
let indexpath : IndexPath = IndexPath(row: i, section: 4)
let cell : InstantMsgCell? = self.tblCreateContact.cellForRow(at: indexpath) as! InstantMsgCell?
let shrO : ContactShare = arrInstantMsg.object(at: i) as! ContactShare
if (cell?.txtMessage.text) != nil {
shrO.strValue = (cell?.txtMessage.text)!
shrO.strtype = (cell?.btnType.titleLabel?.text)!
if (shrO.strtype == "Skype") {
let skypeProfile = CNLabeledValue(label: "Skype", value: CNInstantMessageAddress(username: shrO.strValue, service: CNInstantMessageServiceSkype))
contact.instantMessageAddresses.append(skypeProfile)
}
else if (shrO.strtype == "WhatsApp") {
let whatsAppProfile = CNLabeledValue(label: "WhatsApp", value: CNInstantMessageAddress(username: shrO.strValue, service: CNInstantMessageServiceFacebook))
contact.instantMessageAddresses.append(whatsAppProfile)
}
else {
let messagesProfile = CNLabeledValue(label: "Messages", value: CNInstantMessageAddress(username: shrO.strValue, service: CNInstantMessageServiceMSN))
contact.instantMessageAddresses.append(messagesProfile)
}
}
}
for i in (0..<arrAddress.count){
let indexpath : IndexPath = IndexPath(row: i, section: 5)
let cell : AddressCell? = self.tblCreateContact.cellForRow(at: indexpath) as! AddressCell?
let shrO : ContactAddressShare = arrAddress.object(at: i) as! ContactAddressShare
shrO.strLine1 = (cell?.txtAddressLine1.text)!
shrO.strLine2 = (cell?.txtAddressLine2.text)!
shrO.strCity = (cell?.txtCity.text)!
shrO.strState = (cell?.txtState.text)!
shrO.strCountry = (cell?.txtCountry.text)!
let homeAddress = CNMutablePostalAddress()
homeAddress.street = "\(shrO.strLine1)"
homeAddress.subLocality = "\(shrO.strLine2)"
homeAddress.city = shrO.strCity
homeAddress.state = shrO.strState
homeAddress.postalCode = ""
homeAddress.country = shrO.strCountry
contact.postalAddresses = [CNLabeledValue(label:CNLabelHome, value:homeAddress)]
}
for i in (0..<arrAboutMe.count){
if i == 0 {
let indexpath : IndexPath = IndexPath(row: i, section: 6)
let cell : AboutMeCell? = self.tblCreateContact.cellForRow(at: indexpath) as! AboutMeCell?
let shrO : ContactAboutMeShare = arrAboutMe.object(at: i) as! ContactAboutMeShare
if (cell?.txtAboutMe.text != "") {
shrO.strAboutMe = (cell?.txtAboutMe.text)!
contact.note = (cell?.txtAboutMe.text)!
}
else{
shrO.strAboutMe = ""
contact.note = ""
}
}
}
var vcard: String? = "BEGIN:VCARD\r\nVERSION:3.1"
let strName : String = "N:\(txtName.text ?? "")\n"
let strFullName : String = "FN:\(txtFname.text ?? "")\n"
let strOrgName : String = "ORG:\(txtTitle.text ?? "")\n"
let strposition : String = "TITLE:\(txtCompany.text ?? "")\n"
vcard = "\(vcard ?? "")\(strName)\(strFullName)\(strOrgName)\(strposition)"
for shrObjPhone in arrPhones {
let shrO : ContactShare = shrObjPhone as! ContactShare
vcard = "\(vcard ?? "")\n TEL;\(shrO.strtype):\(shrO.strValue)\n"
}
for shrObjEmail in arrEmails {
let shrO : ContactShare = shrObjEmail as! ContactShare
vcard = "\(vcard ?? "")\n EMAIL;\(shrO.strtype):\(shrO.strValue)\n"
}
for shrObjEmail in arrURLs {
let shrO : ContactShare = shrObjEmail as! ContactShare
vcard = "\(vcard ?? "")\n URL;\(shrO.strtype):\(shrO.strValue)\n"
}
for shrObjEmail in arrSocials {
let shrO : ContactShare = shrObjEmail as! ContactShare
vcard = "\(vcard ?? "")\n LABEL;TYPE=\(shrO.strtype):\(shrO.strValue)\n"
}
for shrObjEmail in arrInstantMsg {
let shrO : ContactShare = shrObjEmail as! ContactShare
vcard = "\(vcard ?? "")\n LABEL;TYPE=\(shrO.strtype):\(shrO.strValue)\n"
}
for shrObjadd in arrAddress {
let shrO : ContactAddressShare = shrObjadd as! ContactAddressShare
vcard = "\(vcard ?? "")\n ADR;WORK;POSTAL=\(shrO.strLine1);\(shrO.strLine2);\(shrO.strCity);\(shrO.strState);\(shrO.strCountry)\n"
}
for shrObjabout in arrAboutMe {
let shrO : ContactAboutMeShare = shrObjabout as! ContactAboutMeShare
vcard = "\(vcard ?? "")\n NOTE=\(shrO.strAboutMe)\n"
}
vcard = "\(vcard ?? "")END:VCARD"
print("vcard data=\(vcard ?? "")")
do {
let saveRequest = CNSaveRequest()
saveRequest.add(contact, toContainerWithIdentifier: contactStore.defaultContainerIdentifier())
try contactStore.execute(saveRequest)
Global.singleton.saveToUserDefaults(value: contactStore.defaultContainerIdentifier(), forKey: "MyCardContactId")
let vcardFromContacts = try? CNContactVCardSerialization.data(with: [contact]) as NSData
var vCardData: Data? = try? CNContactVCardSerialization.data(with: ([contact]))
let vCardNote: String? = contact.note
if vCardNote == "" {
} else {
vCardData = CNContactVCardSerialization.vcardDataAppendingNote(vcard: vcardFromContacts! as Data, noteasString:vCardNote!)
}
Global.singleton.saveToUserDefaultsWithContactObject(contact: vCardData!, forKey: Global.kQRAppSettingKeys.MyContactDetail)
} catch {
print("\(error.localizedDescription)")
if error.localizedDescription == "Access Denied" {
Global.singleton.showWarningAlert(withMsg:"Unable to save the new contact. Please grant your contact permission. You have \(error.localizedDescription) your contact permission.")
} else {
Global.singleton.showWarningAlert(withMsg:"Unable to save the new contact. \(error.localizedDescription)")
}
return
}
do {
let vcardFromContacts = try CNContactVCardSerialization.data(with: [contact]) as NSData
//var error: Error? = nil
var vCardData: Data? = try? CNContactVCardSerialization.data(with: ([contact]))
let vCardNote: String? = contact.note
if vCardNote == "" {
} else {
vCardData = CNContactVCardSerialization.vcardDataAppendingNote(vcard:vcardFromContacts as Data, noteasString:vCardNote!)
}
let lastSavedContact = String(data: vCardData ?? Data(), encoding: .utf8)!
print("added contact = \(String(describing: lastSavedContact))")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController1 : CreateVCardVC = storyboard.instantiateViewController(withIdentifier :"CreateVCardVC") as! CreateVCardVC
viewController1.lastSavedContact = lastSavedContact
viewController1.lastSavedCON = contact
Global.singleton.saveToUserDefaults(value: lastSavedContact, forKey: Global.myBusinessCard)
Global.singleton.saveToUserDefaults(value: "1", forKey: Global.IsCreatedBusinessCard)
self.navigationController?.pushViewController(viewController1 , animated: true)
} catch {
Global.singleton.showWarningAlert(withMsg:"Error \(error.localizedDescription)" )
}
}
On execute executeSaveRequest, I caught an error:
NSError with domain: CNErrorDomain, error:500
The question: Is it possible to modify the linked contact (not unified), and if it is, what I do wrong?
If I modifying not linked contact - all OK!
Expected Results:
- Need to save in iOS contact list
Actual Results:
- CNErrorDomain, code:500