I am trying to download information from a Firebase Firestore document that is then appended to an array in realtime. Everytime I add a document, delete or edit a document I would like the app to update and sync the array to match the data. I was able to retrieve the data with the following code:
database.collection("_Products").getDocuments(completion: { (snapshot, error) in
if error != nil {
print(error as Any)
}else{
for document in (snapshot?.documents)! {
let Name = document.data()["Item Name"] as! String
let Price = document.data()["Item Price"] as! String
let Number = document.data()["Item Number"] as! String
let Brand = document.data()["Item Brand"] as! String
let Quantity = document.data()["Quantity"] as! String
let Category = document.data()["Item Category"] as! String
DispatchQueue.main.async {
if instoreCheckOutArray.contains(where: {$0.Number == Number && $0.Brand == Brand}){
return
}else{
instoreCheckOutArray.append(checkOutArrayInfo(Brand: Brand, Name: Name, Number: Number, Price: Price, Quantity: Quantity, Category: Category))
self.searchForCoupon()
}
}
}
}
})
I then use the following code to run the function every second to fetch the data from the database:
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateCart), userInfo: nil, repeats: true)
Running the previous code perfectly fetches me new data but I cannot get the app to update the existing array to match the database and when I remove a document from the database it stays in the array.
Thank you in advanced.
1.Declare scrollingTimer variable
var scrollingTimer = Timer()
2.Initialize scrollingTimer with your function
scrollingTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateCart), userInfo: nil, repeats: true)
3.Fire the scrollingTimer(fire any where you want)
scrollingTimer.fire()
To stop the scrolling timer use the below line(Stop any where you want)
scrollingTimer.invalidate()
If any Please refer the link (DevelopersDocument)
i have a problem when i typed my code as is bellow but i got error ?!
i want user if typed code = 4234 on textFields and tap on "ADD" = "https://pastebin.com/raw/4234"
else = any url "http://www.example.com/"
#IBAction func btnPlusPressed(_ sender: UIButton)
{
let alert = UIAlertController(title: "Provider M3U URL", message: "Add Provided URL to add you M3U Plailist", preferredStyle: .alert)
let loginAction = UIAlertAction(title: "ADD", style: .default, handler: { (action) -> Void in
var url = alert.textFields![0]
if (url.text == "535" as String ){
let strURLl : String = "https://pastebin.com/raw/\(url.text!)"
}else{
let strURLl : String = "\(url.text!)"
}
UserDefaults .standard .set(strURLl, forKey: "URL")
let channelsVC = self.storyboard!.instantiateViewController(withIdentifier: "ChannelsViewController") as! ChannelsViewController
channelsVC.strURL = strURLl!
self.navigationController?.pushViewController(channelsVC, animated: true)
})
why error appear like this : (Use of unresolved identifier 'strURLl')
Here you are defining the constant strURLl within the scope of the IF statement.
It means you cannot use it once outside of those { } around it
if (url.text == "535" as String ){
let strURLl : String = "https://pastebin.com/raw/\(url.text!)"
} else {
let strURLl : String = "\(url.text!)"
}
Same problem with the else statement.
Solution
Simply declare the constant outside of the IF scope
let strURLl: String
if (url.text == "535" as String ){
strURLl = "https://pastebin.com/raw/\(url.text!)"
} else {
strURLl = "\(url.text!)"
}
Below is my code to fetch images from icloudkit however now I have to click the UIbutton "getAlbum" 2 times for the images to be displayed in the table view. so did I add tableview.reload()m in a wrong place? please advise
#IBAction func getAlbum(_ sender: AnyObject) {
//Below line to dismiss the keyboard.
textEntercode.resignFirstResponder()
if (self.textEntercode.text == "")
{
let alert = UIAlertController(title: "No Code Entered", message: "Please enter photos code", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil));
//event handler with closure
present(alert, animated: true, completion: nil);
}
else //G
{
// let code: Int64 = Int64(self.textEntercode.text!)!
var photoCode = textEntercode.text!
// convert the characters to upper case before getting data from database
photoCode = photoCode.uppercased()
var count = 0
let Container = CKContainer.default()
let database = Container.publicCloudDatabase
let predicate = NSPredicate(value: true)
let query = CKQuery(recordType: "Photos", predicate: predicate) //Photos is table name in cloudkit server
//-------Fetch the data---------------------
database.perform(query, inZoneWith: nil) { //A
records, error in
if error != nil { //B
print(error?.localizedDescription ?? 10)
} // B
else { //C
count = (records?.count)!
print("countttttt \(count)")
for myrecord in records!
{ //D
self.Saveddata.append(myrecord as CKRecord)
//self.tableview.reloadData()
} //D
let Queue = OperationQueue.main
Queue.addOperation() { //E
self.tableview.reloadData()
} //E
} //C
} //A
} //G
My ViewController wants to display some data based on a CloudKit query.
My CloudKit code is all in a separate class. That class has a function called loadExpenses() that fetches some Expenses entities from CK.
I want to be able to call loadExpenses() from the VC, so I need a completion block provided by the function to update the UI from the VC.
This is what loadExpenses() looks like:
func loadExpenses() {
let pred = NSPredicate(value: true)
let sort = NSSortDescriptor(key: "creationDate", ascending: true)
let query = CKQuery(recordType: "Expense", predicate: pred)
query.sortDescriptors = [sort]
let operation = CKQueryOperation(query: query)
operation.desiredKeys = ["person", "action", "amount", "timestamp"]
operation.resultsLimit = 50
var newExpenses = [Expense]()
operation.recordFetchedBlock = { (record) in
let recordID = record.recordID
let person = record["person"] as! String
let action = record["action"] as! String
let amount = record["amount"] as! Double
let timestamp = record["timestamp"] as! NSDate
let expense = Expense(person: person, action: action, amount: amount, timestamp: timestamp)
newExpenses.append(expense)
}
// This is the part that needs to be changed
operation.queryCompletionBlock = { [unowned self] (cursor, error) in
dispatch_async(dispatch_get_main_queue()) {
if error == nil {
self.objects = newExpenses
self.tableView.reloadData()
self.refreshRealmDataFromCK()
} else {
let ac = UIAlertController(title: "Fetch failed", message: "There was a problem fetching the list of expenses; please try again: \(error!.localizedDescription)", preferredStyle: .Alert)
ac.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
self.presentViewController(ac, animated: true, completion: nil)
}
}
}
CKContainer.defaultContainer().privateCloudDatabase.addOperation(operation)
}
Obviously the last part won't execute, considering all those self.property belong to the VC (I kept them just to show what I need to do in the VC).
As I said, I want to be able to call this function from the VC and get/use a completion block to update those properties. How do I do that?
You need to pass a block as a parameter to the loadExpenses() function. So it should actually be defined something like loadExpenses(completionBlock:([whatever parameters you need in here])->Void).
Then, you can call the passed completionBlock block (with appropriate parameters) from within the operation.queryCompletionBlock block.
EDIT:
So this is not tested at all of course, but you could give it a shot:
func loadExpenses(completionBlock:([Expense])->Void) {
let pred = NSPredicate(value: true)
let sort = NSSortDescriptor(key: "creationDate", ascending: true)
let query = CKQuery(recordType: "Expense", predicate: pred)
query.sortDescriptors = [sort]
let operation = CKQueryOperation(query: query)
operation.desiredKeys = ["person", "action", "amount", "timestamp"]
operation.resultsLimit = 50
var newExpenses = [Expense]()
operation.recordFetchedBlock = { (record) in
let recordID = record.recordID
let person = record["person"] as! String
let action = record["action"] as! String
let amount = record["amount"] as! Double
let timestamp = record["timestamp"] as! NSDate
let expense = Expense(person: person, action: action, amount: amount, timestamp: timestamp)
newExpenses.append(expense)
}
// This is the part that needs to be changed
operation.queryCompletionBlock = { [unowned self] (cursor, error) in
completionBlock(newExpenses)
}
CKContainer.defaultContainer().privateCloudDatabase.addOperation(operation)
}
And then call it like this:
loadExpenses({ (newExpenses:[Expense]) -> Void in {
dispatch_async(dispatch_get_main_queue()) {
if error == nil {
self.objects = newExpenses
self.tableView.reloadData()
self.refreshRealmDataFromCK()
} else {
let ac = UIAlertController(title: "Fetch failed", message: "There was a problem fetching the list of expenses; please try again: \(error!.localizedDescription)", preferredStyle: .Alert)
ac.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
self.presentViewController(ac, animated: true, completion: nil)
}
}
}
I have added the ABPeoplePickerNavigationController into my first view controller. I want that when I select a contact show the info to show in other view controller, but I'm trying use my code and this not show never when I click in a contact. This only open the contact into native app ABPeoplePickerNavigationController.
var people = ABPeoplePickerNavigationController()
var addressBook: ABAddressBookRef?
func extractABAddressBookRef(abRef: Unmanaged<ABAddressBookRef>!) -> ABAddressBookRef? {
if let ab = abRef {
self.view.addSubview(people.view)
return Unmanaged<NSObject>.fromOpaque(ab.toOpaque()).takeUnretainedValue()
}
return nil
}
I tried this function
func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController!,didSelectPerson person: ABRecordRef!) {
var unmanagedEmails = ABRecordCopyValue(people, kABPersonEmailProperty)
let emailObj: ABMultiValueRef = Unmanaged.fromOpaque(unmanagedEmails.toOpaque()).takeUnretainedValue() as NSObject as ABMultiValueRef
var index = 0 as CFIndex
var unmanagedEmail = ABMultiValueCopyValueAtIndex(emailObj, index)
var emailAddress:String = Unmanaged.fromOpaque(unmanagedEmail.toOpaque()).takeUnretainedValue() as NSObject as String
println(emailAddress)
}
Thanks!
Here is the latest framework for iOS 9 - ContactsUI
import ContactsUI
Conform to the CNContactPickerDelegate (No required methods)
Create a contacts picker object and present it:
let peoplePicker = CNContactPickerViewController()
peoplePicker.delegate = self
self.presentViewController(peoplePicker, animated: true, completion: nil)
Dismiss the CNContactPickerViewController in the contactPickerDidCancel delegate function
func contactPickerDidCancel(picker: CNContactPickerViewController) {
picker.dismissViewControllerAnimated(true, completion: nil)
}
Here is how I Accessed a contacts name, phone numbers, phone number labels, and photo using the didSelectContact delegate function:
func contactPicker(picker: CNContactPickerViewController, didSelectContact contact: CNContact) {
//Dismiss the picker VC
picker.dismissViewControllerAnimated(true, completion: nil)
//See if the contact has multiple phone numbers
if contact.phoneNumbers.count > 1 {
//If so we need the user to select which phone number we want them to use
let multiplePhoneNumbersAlert = UIAlertController(title: "Which one?", message: "This contact has multiple phone numbers, which one did you want use?", preferredStyle: UIAlertControllerStyle.Alert)
//Loop through all the phone numbers that we got back
for number in contact.phoneNumbers {
//Each object in the phone numbers array has a value property that is a CNPhoneNumber object, Make sure we can get that
if let actualNumber = number.value as? CNPhoneNumber {
//Get the label for the phone number
var phoneNumberLabel = number.label
//Strip off all the extra crap that comes through in that label
phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("_", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("$", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("!", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("<", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString(">", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
//Create a title for the action for the UIAlertVC that we display to the user to pick phone numbers
let actionTitle = phoneNumberLabel + " - " + actualNumber.stringValue
//Create the alert action
let numberAction = UIAlertAction(title: actionTitle, style: UIAlertActionStyle.Default, handler: { (theAction) -> Void in
//Create an empty string for the contacts name
var nameToSave = ""
//See if we can get A frist name
if contact.givenName == "" {
//If Not check for a last name
if contact.familyName == "" {
//If no last name set name to Unknown Name
nameToSave = "Unknown Name"
}else{
nameToSave = contact.familyName
}
}else{
nameToSave = contact.givenName
}
// See if we can get image data
if let imageData = contact.imageData {
//If so create the image
let userImage = UIImage(data: imageData)
}
//Do what you need to do with your new contact information here!
//Get the string value of the phone number like this:
actualNumber.stringValue
})
//Add the action to the AlertController
multiplePhoneNumbersAlert.addAction(numberAction)
}
}
//Add a cancel action
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: { (theAction) -> Void in
//Cancel action completion
})
//Add the cancel action
multiplePhoneNumbersAlert.addAction(cancelAction)
//Present the ALert controller
self.presentViewController(multiplePhoneNumbersAlert, animated: true, completion: nil)
}else{
//Make sure we have at least one phone number
if contact.phoneNumbers.count > 0 {
//If so get the CNPhoneNumber object from the first item in the array of phone numbers
if let actualNumber = contact.phoneNumbers.first?.value as? CNPhoneNumber {
//Get the label of the phone number
var phoneNumberLabel = contact.phoneNumbers.first!.label
//Strip out the stuff you don't need
phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("_", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("$", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("!", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("<", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString(">", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
//Create an empty string for the contacts name
var nameToSave = ""
//See if we can get A frist name
if contact.givenName == "" {
//If Not check for a last name
if contact.familyName == "" {
//If no last name set name to Unknown Name
nameToSave = "Unknown Name"
}else{
nameToSave = contact.familyName
}
}else{
nameToSave = contact.givenName
}
// See if we can get image data
if let imageData = contact.imageData {
//If so create the image
let userImage = UIImage(data: imageData)
}
//Do what you need to do with your new contact information here!
//Get the string value of the phone number like this:
actualNumber.stringValue
}
}else{
//If there are no phone numbers associated with the contact I call a custom funciton I wrote that lets me display an alert Controller to the user
self.displayAlert("Missing info", message: "You have no phone numbers associated with this contact")
}
}
}
A couple of thoughts:
Have you set the peoplePickerDelegate property of the people picker controller? If you don't do that, it won't know to try to call these methods in your class. Thus:
people.peoplePickerDelegate = self
presentViewController(people, animated: true, completion: nil)
Your example method is referencing people when you call ABRecordCopyValue. That's your picker controller. I assume you meant to reference person, the ABRecordRef! that was passed as a parameter.
You might also want to make sure you actually have an email address before trying to access it. You can use ABMultiValueGetCount.
I also think you can also eliminate that fromOpaque/toOpaque dance.
This yields:
func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController, didSelectPerson person: ABRecord) {
let emails: ABMultiValueRef = ABRecordCopyValue(person, kABPersonEmailProperty).takeRetainedValue()
if ABMultiValueGetCount(emails) > 0 {
let index = 0 as CFIndex
let emailAddress = ABMultiValueCopyValueAtIndex(emails, index).takeRetainedValue() as! String
print(emailAddress)
} else {
print("No email address")
}
}
If you need to support iOS 7, too, use:
func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController, shouldContinueAfterSelectingPerson person: ABRecord, property: ABPropertyID, identifier: ABMultiValueIdentifier) -> Bool {
let multiValue: ABMultiValueRef = ABRecordCopyValue(person, property).takeRetainedValue()
let index = ABMultiValueGetIndexForIdentifier(multiValue, identifier)
let email = ABMultiValueCopyValueAtIndex(multiValue, index).takeRetainedValue() as! String
print("email = \(email)")
peoplePicker.dismissViewControllerAnimated(true, completion: nil)
return false
}
You might, though, rather than assuming the user only wanted the first email address, instead, let them click through and pick one of the possible multiple email addresses the contact had. So, first, you might want to eliminate some of the "noise", by telling the picker that you only want to see email addresses:
people.peoplePickerDelegate = self
people.displayedProperties = [NSNumber(int: kABPersonEmailProperty)]
presentViewController(people, animated: true, completion: nil)
And then, remove the prior method we've been discussing, and instead implement:
func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController!, didSelectPerson person: ABRecordRef!, property: ABPropertyID, identifier: ABMultiValueIdentifier) {
let multiValue: ABMultiValueRef = ABRecordCopyValue(person, property).takeRetainedValue()
let index = ABMultiValueGetIndexForIdentifier(multiValue, identifier)
let email = ABMultiValueCopyValueAtIndex(multiValue, index).takeRetainedValue() as String
println("email = \(email)")
}
And to support iOS 7,0, too, you'd add:
func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController, shouldContinueAfterSelectingPerson person: ABRecord, property: ABPropertyID, identifier: ABMultiValueIdentifier) -> Bool {
let multiValue: ABMultiValueRef = ABRecordCopyValue(person, property).takeRetainedValue()
let index = ABMultiValueGetIndexForIdentifier(multiValue, identifier)
let email = ABMultiValueCopyValueAtIndex(multiValue, index).takeRetainedValue() as! String
print("email = \(email)")
peoplePicker.dismissViewControllerAnimated(true, completion: nil)
return false
}
By the way, iOS 8 offers a feature to control whether a contact is enabled or not. Since you're supporting iOS 7 and 8, you'd want to employ that conditionally, such as:
if people.respondsToSelector(Selector("predicateForEnablingPerson")) {
people.predicateForEnablingPerson = NSPredicate(format: "emailAddresses.#count > 0")
}
This gives the user visual indication whether there is even an email address for the individual, and prevents them from selecting entry without email address.
Obviously, if using iOS 9 and later, you should retire all of this and use the ContactsUI framework, which simplifies the code further.
SWIFT3 IOS10
Working version of Jon Vogel for Swift 3 and IOS 10 and support to multiple contacts selection.
//
// Created by JEFFERSON A NEITZKE on 30/01/17.
// Copyright © 2017 JEFFERSON A NEITZKE. All rights reserved.
//
import UIKit
import ContactsUI
class Principal: UIViewController, CNContactPickerDelegate {
var numeroADiscar: String = ""
var userImage: UIImage? = nil
var nameToSave = ""
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let peoplePicker = CNContactPickerViewController()
peoplePicker.delegate = self
self.present(peoplePicker, animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
picker.dismiss(animated: true, completion: nil)
}
func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) {
// I only want single selection
if contacts.count != 1 {
return
} else {
//Dismiss the picker VC
picker.dismiss(animated: true, completion: nil)
let contact: CNContact = contacts[0]
//See if the contact has multiple phone numbers
if contact.phoneNumbers.count > 1 {
//If so we need the user to select which phone number we want them to use
let multiplePhoneNumbersAlert = UIAlertController(title: "Which one?", message: "This contact has multiple phone numbers, which one did you want use?", preferredStyle: UIAlertControllerStyle.alert)
//Loop through all the phone numbers that we got back
for number in contact.phoneNumbers {
//Each object in the phone numbers array has a value property that is a CNPhoneNumber object, Make sure we can get that
let actualNumber = number.value as CNPhoneNumber
//Get the label for the phone number
var phoneNumberLabel = number.label
//Strip off all the extra crap that comes through in that label
phoneNumberLabel = phoneNumberLabel?.replacingOccurrences(of: "_", with: "")
phoneNumberLabel = phoneNumberLabel?.replacingOccurrences(of: "$", with: "")
phoneNumberLabel = phoneNumberLabel?.replacingOccurrences(of: "!", with: "")
phoneNumberLabel = phoneNumberLabel?.replacingOccurrences(of: "<", with: "")
phoneNumberLabel = phoneNumberLabel?.replacingOccurrences(of: ">", with: "")
//Create a title for the action for the UIAlertVC that we display to the user to pick phone numbers
let actionTitle = phoneNumberLabel! + " - " + actualNumber.stringValue
//Create the alert action
let numberAction = UIAlertAction(title: actionTitle, style: UIAlertActionStyle.default, handler: { (theAction) -> Void in
//See if we can get A frist name
if contact.givenName == "" {
//If Not check for a last name
if contact.familyName == "" {
//If no last name set name to Unknown Name
self.nameToSave = "Unknown Name"
}else{
self.nameToSave = contact.familyName
}
} else {
self.nameToSave = contact.givenName
}
// See if we can get image data
if let imageData = contact.imageData {
//If so create the image
self.userImage = UIImage(data: imageData)!
}
//Do what you need to do with your new contact information here!
//Get the string value of the phone number like this:
self.numeroADiscar = actualNumber.stringValue
})
//Add the action to the AlertController
multiplePhoneNumbersAlert.addAction(numberAction)
}
//Add a cancel action
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: { (theAction) -> Void in
//Cancel action completion
})
//Add the cancel action
multiplePhoneNumbersAlert.addAction(cancelAction)
//Present the ALert controller
self.present(multiplePhoneNumbersAlert, animated: true, completion: nil)
} else {
//Make sure we have at least one phone number
if contact.phoneNumbers.count > 0 {
//If so get the CNPhoneNumber object from the first item in the array of phone numbers
let actualNumber = (contact.phoneNumbers.first?.value)! as CNPhoneNumber
//Get the label of the phone number
var phoneNumberLabel = contact.phoneNumbers.first!.label
//Strip out the stuff you don't need
phoneNumberLabel = phoneNumberLabel?.replacingOccurrences(of: "_", with: "")
phoneNumberLabel = phoneNumberLabel?.replacingOccurrences(of: "$", with: "")
phoneNumberLabel = phoneNumberLabel?.replacingOccurrences(of: "!", with: "")
phoneNumberLabel = phoneNumberLabel?.replacingOccurrences(of: "<", with: "")
phoneNumberLabel = phoneNumberLabel?.replacingOccurrences(of: ">", with: "")
//Create an empty string for the contacts name
self.nameToSave = ""
//See if we can get A frist name
if contact.givenName == "" {
//If Not check for a last name
if contact.familyName == "" {
//If no last name set name to Unknown Name
self.nameToSave = "Unknown Name"
}else{
self.nameToSave = contact.familyName
}
} else {
nameToSave = contact.givenName
}
// See if we can get image data
if let imageData = contact.imageData {
//If so create the image
self.userImage = UIImage(data: imageData)
}
//Do what you need to do with your new contact information here!
//Get the string value of the phone number like this:
self.numeroADiscar = actualNumber.stringValue
} else {
//If there are no phone numbers associated with the contact I call a custom funciton I wrote that lets me display an alert Controller to the user
let alert = UIAlertController(title: "Missing info", message: "You have no phone numbers associated with this contact", preferredStyle: UIAlertControllerStyle.alert)
let cancelAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alert.addAction(cancelAction)
present(alert, animated: true, completion: nil)
}
}
}
}
}