How to extract name from a contact in iOS? - ios

I have picked up a contact from the address book
Now I need to display the name to the text view UI in the same view controller.
How to extract the name from the ABRecord?
This is my code.
#IBAction func addContact(sender: AnyObject) {
var peoplePicker = ABPeoplePickerNavigationController()
peoplePicker.peoplePickerDelegate = self
self.presentViewController(peoplePicker, animated: true, completion: nil)
}
func peoplePickerNavigationControllerDidCancel(peoplePicker: ABPeoplePickerNavigationController!) {
dismissViewControllerAnimated(true, completion: nil)
}
func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController!, didSelectPerson person: ABRecord!) {
var name : String! = ABRecordCopyCompositeName(person)
}
Here the function ABRecordCopyCompositeName return unmanaged I can't force cast to String. It says not convertible.
I'm new to iOS dev. please help.

Use takeUnretainedValue() and takeRetainedValue() to get CFString object and cast it to NSString
func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController!, didSelectPerson person: ABRecord!) {
let nameCFString : CFString = ABRecordCopyCompositeName(person).takeRetainedValue()
let name : NSString = nameCFString as NSString
}

You can also check KBContactsSelection which allows you to search and select multiple contacts and is easily customizable using elegant Builder Pattern.

Related

Swift get value data from protocol

i need help with my code for swift 5,
so i make a struct and protocol to store list from uitextfield and now i wanna show that data in a UiTextView in another view controller
struct PatientNote {
var note : String
init(note :String) {
self.note = note
}
}
protocol AddNotesDelegate {
func AddNotes(controller : UIViewController, notes: PatientNote)
}
class AddNotesController: UIViewController {
var delegate : AddNotesDelegate!
#IBOutlet weak var Notes: UITextView!
#IBAction func addNotes(_ sender: Any) {
if let notes = self.Notes.text {
let patientNote = PatientNote(note: notes)
self.delegate.AddNotes(controller: self, notes: patientNote)
print(patientNote.note)
}
}
}
and now i wanna show in my view controller but i get this error of "Cannot convert value of type 'PatientNote' to expected argument type 'String'" in this viewController
class NotePatientController: UIViewController, AddNotesDelegate{
func AddNotes(controller: UIViewController, notes: PatientNote) {
let NotesPatient = PatientNote(note: notes) *this is where i get the error
}
var delegate : AddNotesDelegate!
var pasien : PatientNote!
override func viewDidLoad() {
super.viewDidLoad()
PatientTextView.text = pasien.note
}
#IBOutlet weak var PatientTextView: UITextView!
//in this ibaction i edit the notes that i get from the first Vc which is AddNotesController
#IBAction func Save(_ sender: UIButton) {
if let notes = self.PatientTextView.text {
let pasienNotes = PatientNote(note: notes)
self.delegate.AddNotes(controller: self, notes: pasienNotes)
}
}
}
i try to show the note from the AddNotesController to the NotePatientController, and in the NotePatientController i can edit and save the notes in UiTextView.
so i know i must be using the protocol in a wrong way, can someone help me how should i use it? im still kinda new in swift so could probably use any help i can get, Cheer!
Change let notesPatient = PatientNote(note: notes) to let notesPatient = PatientNote(note: notes.note)
It appears PatientNote takes a String as an argument but you passed an already created PatientNote to it instead. The below syntax, using notes.note would be a cleaner solution without involving initialising a new PatientNote.
func AddNotes(controller: UIViewController, notes: PatientNote) {
print(notes.note) // access the note String like this
}

How can you customize UIActivityViewController to ONLY include custom UIActivity types?

I'm trying to customize the native ios UIActivityViewController so it will restrict every UIActivity except for the custom UIActivity types that I initialize the UIActivityViewController with.
Essentially, I only want the user to see my four custom UIActivitys.
let items = ["Hello world"]
let activitySheet = CustomUIActivityViewController(
activityItems: items,
applicationActivities: [
CustomMailUIActivity(),
CustomMessagesUIActivity(),
CustomTwitterUIActivity(),
CustomFacebookUIActivity()
]
)
I understand that you can use activitySheet.excludedActivityTypes = [] to exclude types that you do not need, however you are not able to exclude third party applications such as Slack.
I was wondering if there was any way to get around that and ONLY include custom applicationActivies. It would also be great to remove the "More" button that appears on the share sheet as well. Any help would be greatly appreciated.
This is what I'm trying to achieve.
screenshot
My colleague was able to figure this out. For anyone wondering how to display only the applicationActivities (custom activities) on the share sheet, this is how I did it.
For activityItems rather than creating an array of strings, create an array of your custom data objects. Then override the canPerform(withActivityItems activityItems: [Any]) method in your custom UIActivity (subclass of UIActivity) to return true if activityItems[o] is CustomItem. Since your activityItems are custom, system will not display other apps on the share sheet. That's it.
In the example below, only your CustomUIActivity will be displayed on the share sheet.
let items = [CustomItem("Hello world")]
let activitySheet = UIActivityViewController(
activityItems: items,
applicationActivities: [
CustomUIActivity()
]
)
class CustomItem {
let value: String
required init(value: String) {
self.value = value
}
func getValue() -> String {
return self.value
}
}
#objc(CustomUIActivity)
class CustomUIActivity: UIActivity {
override class var activityCategory: UIActivity.Category {
return .share
}
override var activityType: UIActivity.ActivityType? {
return .customuiactivity
}
override var activityTitle: String? {
return "Custom"
}
override var activityImage: UIImage? {
return UIImage(named: "custom-icon")
}
override func canPerform(withActivityItems activityItems: [Any]) -> Bool {
if activityItems.count == 1 && activityItems[0] is CustomItem {
return true
}
return false
}
var textToShare: String?
override func prepare(withActivityItems activityItems: [Any]) {
if let activityItem = activityItems.first as? CustomItem {
self.textToShare = activityItem.getValue
}
}
override func perform() {
// perform your custom activity with `textToShare`
activityDidFinish(true)
}
}
extension UIActivity.ActivityType {
static let customuiactivity =
UIActivity.ActivityType("com.ceylonese.mobile.customuiactivity")
}

Value of type 'UIViewController' has no member 'newExerciseDelegate'

I've searched for a solution to this problem, even tried following a few tutorials to try to solve this, but for some reason I'm ending up with the same issue. I'm attempting to pass a custom object to a different view controller, but every time I try I get the error "Value of type 'UIViewController' has no member 'newExerciseDelegate'"
My delegate:
protocol exerciseDelegate {
func savedExercise(newExercise: Exercise)
}
my sending VC uses the following code:
var newExerciseDelegate: exerciseDelegate!
.
.
.
#IBAction func saveExerciseWasPressed(_ sender: UIButton) {
if (checkFields() == true){
newExercise = Exercise(name: exerciseNameField.text!, weight: Int32(weightField.text!)!, reps: Int32(numberOfRepsField.text!)!, sets: Int32(numberOfSetsField.text!)!, muscleGroupFocus: .cardio)
newExerciseDelegate.savedExercise(newExercise: newExercise)
dismiss(animated: false, completion: nil)
}
}
My receiving VC uses the following code:
#IBAction func addExerciseBtnWasPressed(_ sender: Any) {
guard let newExerciseVC = storyboard?.instantiateViewController(withIdentifier: "NewExerciseVC") else { return }
newExerciseVC.newExerciseDelegate = self // error present on this line
presentDetail(newExerciseVC)
}
I'm sure it's a stupid mistake, but I'm not seeing it. Any help is appreciated, thank you.
You should specify which class it is.After the code know which class actually it is, then you can access it's public objects, methods, variables etc.
#IBAction func addExerciseBtnWasPressed(_ sender: Any) {
guard let newExerciseVC = storyboard?.instantiateViewController(withIdentifier: "NewExerciseVC") as? NewExerciseViewController else { return }
newExerciseVC.newExerciseDelegate = self
presentDetail(newExerciseVC)
}
If you are accessing that delegate which is declared in your ViewController then you should call in the below way.
let childOne = self.storyboard?.instantiateViewController(withIdentifier:"WhatsNewViewController") as? WhatsNewViewController
You have to downcast the instantiated view controller to your custom view controller class:
guard let newExerciseVC = storyboard?.instantiateViewController(withIdentifier: "NewExerciseVC") as? YourViewControllerClass else { return }
newExerciseVC.newExerciseDelegate = self
Also you should use a capital E for your protocol's name.

How to print a UIWebView via UIActivityViewController?

I have a view controller containing a UIWebView and a toolbar with an action/share button. This initializes and presents a UIActivityViewController object. Depending on whether I supply the activityItems parameter with either the web view's URL or the URL's corresponding absoluteString, different actions are offered, but the Print option is never shown (nor offered in the "more" section).
I do know how to print the web view contents explicitly using UIPrintInfo and UIPrintInteractionController, but that would be a separate toolbar button whereas I want to simply include the system's Print option into the activity button row. I assume printing a web view does not need any explicit coding.
What can I do?
You can create Custom Activity For UIActivityCotnroller like this,
import UIKit
protocol CustomActivityDelegate : NSObjectProtocol
{
func performActionCompletion(actvity: CustomActivity)
}
class CustomActivity: UIActivity {
var delegate: CustomActivityDelegate?
override class var activityCategory: UIActivityCategory {
return .action
}
override var activityType: UIActivityType? {
guard let bundleId = Bundle.main.bundleIdentifier else {return nil}
return UIActivityType(rawValue: bundleId + "\(self.classForCoder)")
}
override var activityTitle: String? {
return "You title"
}
override var activityImage: UIImage? {
return <Your activity image >
}
override func canPerform(withActivityItems activityItems: [Any]) -> Bool {
return true
}
override func prepare(withActivityItems activityItems: [Any]) {
//
}
override func perform() {
self.delegate?.performActionCompletion(actvity: self)
activityDidFinish(true)
}
}
You can initialize this activity some thing like this
let customActivity = CustomActivity()
customActivity.delegate = self
And you can add this custom activity while preparing UIActivityController
let activityViewController : UIActivityViewController = UIActivityViewController(activityItems: [customActivity], applicationActivities: nil)
and you will also need to implement the call back method
func performActionCompletion(actvity: CustomActivity)
{
//Perform you task
}
Note : This is just pseudo code, might contain error or syntax problems

Static cell contact picker

I am trying to accomplish the following:
1. my tableview consists of two static cells
2. the cells have an initial text of "select contact"
3. a modal should pop-up with a contact picker
4. the user should pick a contact
5. the static cell's text should be updated to match the contact's name
I'm having the following problems. If I assign the delegate to my tableviewcontroller, I can't seem to get it to work with two contacts (without having to write separate functions for each).
I would very much like a single function which returns a contact.
I have been experimenting, and this is the best I can come up with (its a partial implementation of didSelectRowAtIndexPath which should open a contact-modal. However, it does not appear to follow the delegate's functions.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
class PeoplePickerDelegate:NSObject, ABPeoplePickerNavigationControllerDelegate {
func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController!, didSelectPerson person: ABRecord!) {
let firstName: ABMultiValueRef = ABRecordCopyValue(person, kABPersonFirstNameProperty).takeRetainedValue()
let lastName: ABMultiValueRef = ABRecordCopyValue(person, kABPersonLastNameProperty).takeRetainedValue()
println("name is \(firstName) \(lastName)")
}
func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController!, shouldContinueAfterSelectingPerson person: ABRecordRef!) -> Bool {
peoplePickerNavigationController(peoplePicker, didSelectPerson: person)
peoplePicker.dismissViewControllerAnimated(true, completion: nil)
return false;
}
func peoplePickerNavigationControllerDidCancel(peoplePicker: ABPeoplePickerNavigationController!) {
peoplePicker.dismissViewControllerAnimated(true, completion: nil)
}
}
var peoplePickerDelegate:PeoplePickerDelegate?
let picker = ABPeoplePickerNavigationController()
picker.peoplePickerDelegate = peoplePickerDelegate
presentViewController(picker, animated: true, completion: nil)
}
Any help would be much appreciated, I'm a novice and trying really hard to grasp this.

Resources