Pushing NContactViewController results in black navigationbar. Why?
Pushing NContactViewController results in black navigationbar. Why?
I have been trying to solve this problem for a while, so here is my question :
I want to create an unknown contact with a given set of values as you may say:
fileprivate func showUnknownContactViewController() {
let aContact = CNMutableContact()
let newEmail = CNLabeledValue(label: CNLabelWork, value: email! as NSString)
aContact.emailAddresses.append(newEmail)
let workPhone = CNLabeledValue(label: CNLabelWork, value: CNPhoneNumber(stringValue : phone!))
aContact.phoneNumbers.append(workPhone)
let ucvc = CNContactViewController(forUnknownContact: aContact)
ucvc.delegate = self
ucvc.allowsEditing = true
ucvc.allowsActions = true
ucvc.alternateName = firstName! + " " + lastName!
ucvc.title = "Company"
ucvc.message = UserDefaults.standard.string(forKey: "company")!
ucvc.contactStore = self.store //needed for editing/adding contacts?
self.navigationController?.pushViewController(ucvc, animated: true)
}
I also called the delegate function, which I am not sure has any effect:
func contactViewController(_ viewController: CNContactViewController, shouldPerformDefaultActionFor property: CNContactProperty) -> Bool {
return true
}
When pushing ucvc my navigationbar becomes black, while this tutorial which i followed doesn't. Note: I dont use a tableview, i just used the showUnknownContactViewController function.
import UIKit
import Contacts
import ContactsUI
enum ActionType: Int {
case pickContact = 0
case createNewContact
case displayContact
case editUnknownContact
}
// Height for the Edit Unknown Contact row
let kUIEditUnknownContactRowHeight: CGFloat = 81.0
class ViewController: UITableViewController, CNContactPickerDelegate, CNContactViewControllerDelegate {
fileprivate var store: CNContactStore!
fileprivate var menuArray: NSMutableArray?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
store = CNContactStore()
checkContactsAccess()
}
fileprivate func checkContactsAccess() {
switch CNContactStore.authorizationStatus(for: .contacts) {
// Update our UI if the user has granted access to their Contacts
case .authorized:
self.accessGrantedForContacts()
// Prompt the user for access to Contacts if there is no definitive answer
case .notDetermined :
self.requestContactsAccess()
// Display a message if the user has denied or restricted access to Contacts
case .denied,
.restricted:
let alert = UIAlertController(title: "Privacy Warning!",
message: "Permission was not granted for Contacts.",
preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
fileprivate func requestContactsAccess() {
store.requestAccess(for: .contacts) {granted, error in
if granted {
DispatchQueue.main.async {
self.accessGrantedForContacts()
return
}
}
}
}
// This method is called when the user has granted access to their address book data.
fileprivate func accessGrantedForContacts() {
// Load data from the plist file
let plistPath = Bundle.main.path(forResource: "Menu", ofType:"plist")
self.menuArray = NSMutableArray(contentsOfFile: plistPath!)
self.tableView.reloadData()
}
//MARK: Table view methods
override func numberOfSections(in tableView: UITableView) -> Int {
return self.menuArray?.count ?? 0
}
// Customize the number of rows in the table view.
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
// Customize the appearance of table view cells.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let DefaultCellIdentifier = "DefaultCell"
let SubtitleCellIdentifier = "SubtitleCell"
var aCell: UITableViewCell?
// Make the Display Picker and Create New Contact rows look like buttons
if indexPath.section < 2 {
aCell = tableView.dequeueReusableCell(withIdentifier: DefaultCellIdentifier)
if aCell == nil {
aCell = UITableViewCell(style: .default, reuseIdentifier: DefaultCellIdentifier)
}
aCell!.textLabel?.textAlignment = .center
} else {
aCell = tableView.dequeueReusableCell(withIdentifier: SubtitleCellIdentifier)
if aCell == nil {
aCell = UITableViewCell(style: .subtitle, reuseIdentifier: SubtitleCellIdentifier)
aCell!.accessoryType = .disclosureIndicator
aCell!.detailTextLabel?.numberOfLines = 0
}
// Display descriptions for the Edit Unknown Contact and Display and Edit Contact rows
aCell!.detailTextLabel?.text = (self.menuArray![indexPath.section] as AnyObject).value(forKey: "description") as! String?
}
aCell!.textLabel?.text = (self.menuArray![indexPath.section] as AnyObject).value(forKey: "title") as! String?
return aCell!
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let actionType = ActionType(rawValue: indexPath.section) {
switch actionType {
case .pickContact:
self.showContactPickerController()
case .createNewContact:
showNewContactViewController()
case .displayContact:
showContactViewController()
case .editUnknownContact:
showUnknownContactViewController()
}
} else {
self.showContactPickerController()
}
}
//MARK: TableViewDelegate method
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// Change the height if Edit Unknown Contact is the row selected
return (indexPath.section == ActionType.editUnknownContact.rawValue) ? kUIEditUnknownContactRowHeight : tableView.rowHeight
}
//MARK: Show all contacts
// Called when users tap "Display Picker" in the application. Displays a list of contacts and allows users to select a contact from that list.
// The application only shows the phone, email, and birthdate information of the selected contact.
fileprivate func showContactPickerController() {
let picker = CNContactPickerViewController()
picker.delegate = self
// Display only a person's phone, email, and birthdate
let displayedItems = [CNContactPhoneNumbersKey, CNContactEmailAddressesKey, CNContactBirthdayKey]
picker.displayedPropertyKeys = displayedItems
// Show the picker
self.present(picker, animated: true, completion: nil)
}
//MARK: Display and edit a person
// Called when users tap "Display and Edit Contact" in the application. Searches for a contact named "Appleseed" in
// in the address book. Displays and allows editing of all information associated with that contact if
// the search is successful. Shows an alert, otherwise.
fileprivate func showContactViewController() {
// Search for the person named "Appleseed" in the Contacts
let name = "Appleseed"
let predicate: NSPredicate = CNContact.predicateForContacts(matchingName: name)
let descriptor = CNContactViewController.descriptorForRequiredKeys()
let contacts: [CNContact]
do {
contacts = try store.unifiedContacts(matching: predicate, keysToFetch: [descriptor])
} catch {
contacts =
}
// Display "Appleseed" information if found in the address book
if !contacts.isEmpty {
let contact = contacts[0]
let cvc = CNContactViewController(for: contact)
cvc.delegate = self
// Allow users to edit the person’s information
cvc.allowsEditing = true
//cvc.contactStore = self.store //seems to work without setting this.
self.navigationController?.pushViewController(cvc, animated: true)
} else {
// Show an alert if "Appleseed" is not in Contacts
let alert = UIAlertController(title: "Error",
message: "Could not find (name) in the Contacts application.",
preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
//MARK: Create a new person
// Called when users tap "Create New Contact" in the application. Allows users to create a new contact.
fileprivate func showNewContactViewController() {
let npvc = CNContactViewController(forNewContact: nil)
npvc.delegate = self
//npvc.contactStore = self.store //seems to work without setting this.
let navigation = UINavigationController(rootViewController: npvc)
self.present(navigation, animated: true, completion: nil)
}
//MARK: Add data to an existing person
// Called when users tap "Edit Unknown Contact" in the application.
fileprivate func showUnknownContactViewController() {
let aContact = CNMutableContact()
let newEmail = CNLabeledValue(label: CNLabelOther, value: "John-Appleseed@mac.com" as NSString)
aContact.emailAddresses.append(newEmail)
let ucvc = CNContactViewController(forUnknownContact: aContact)
ucvc.delegate = self
ucvc.allowsEditing = true
ucvc.allowsActions = true
ucvc.alternateName = "John Appleseed"
ucvc.title = "John Appleseed"
ucvc.message = "Company, Inc"
ucvc.contactStore = self.store //needed for editing/adding contacts?
self.navigationController?.pushViewController(ucvc, animated: true)
}
//MARK: CNContactPickerDelegate methods
// The selected person and property from the people picker.
func contactPicker(_ picker: CNContactPickerViewController, didSelect contactProperty: CNContactProperty) {
let contact = contactProperty.contact
let contactName = CNContactFormatter.string(from: contact, style: .fullName) ?? ""
let propertyName = CNContact.localizedString(forKey: contactProperty.key)
let message = "Picked (propertyName) for (contactName)"
DispatchQueue.main.async {
let alert = UIAlertController(title: "Picker Result",
message: message,
preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
// Implement this if you want to do additional work when the picker is cancelled by the user.
func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
picker.dismiss(animated: true, completion: {})
}
//MARK: CNContactViewControllerDelegate methods
// Dismisses the new-person view controller.
func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) {
//
self.dismiss(animated: true, completion: nil)
}
func contactViewController(_ viewController: CNContactViewController, shouldPerformDefaultActionFor property: CNContactProperty) -> Bool {
return true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I have tried to change the navigationcontroller of the ucvc like this:
ucvc.navigationController?.navigationBar.backgroundColor = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 1)
I have also tried to set the backgroundImage to an empty image:
ucvc.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
Something interesting I see when I load the ucvc, I get this from console log:
Access to PassKit Shared Cache file denied. Please verify sandbox exceptions and/or file a Radar.
But it still turns out black. What am I doing wrong and how would I prevent the black navigationbar? It looks like this:
Navigation bar
Just let me know if I am posting to much code, I think its better with too much than too little:)
1 Answer
1
Have you tried to see how the storyboard on the tutorial is, compared to yours?
@Testtester Well, I have noe clue. I need to reproduce your issue to find out the problem here.
– Elias Knudsen
Jul 1 at 15:05
Ok, I hope I figure this out soon.
– Test tester
Jul 1 at 15:06
I am sorry, but i cant figure it out, maybe someone else can.
– Elias Knudsen
Jul 1 at 19:02
Ok, hopefully, someone else sees this question and answers. Have been trying to find different solutions, but can't find any.
– Test tester
Jul 1 at 19:04
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Yes, I have, there is no difference, except the colour of the navbar.
– Test tester
Jul 1 at 15:02