Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do i pass a dictionary as a function parameter?

I am trying to pass a dictionary as a function parameter. I have the following function

func makeAndAddVisitorRecord2(visitorDict: Dictionary) -> ABRecordRef <AnyObject, AnyObject> {
    let visitorRecord: ABRecordRef = ABPersonCreate().takeRetainedValue()
    ABRecordSetValue(visitorRecord, kABPersonFirstNameProperty, visitorDict[1], nil)
    ABRecordSetValue(visitorRecord, kABPersonLastNameProperty, visitorDict[2], nil)
    //ABRecordSetValue(visitorRecord, kABPersonEmailProperty, visitorDict[5], nil)

    let phoneNumbers: ABMutableMultiValue =
    ABMultiValueCreateMutable(ABPropertyType(kABMultiStringPropertyType)).takeRetainedValue()
    ABMultiValueAddValueAndLabel(phoneNumbers, visitorDict["visitorPhone"], kABPersonPhoneMainLabel, nil)
    ABRecordSetValue(visitorRecord, kABPersonPhoneProperty, phoneNumbers, nil)

    ABAddressBookAddRecord(addressBookRef, visitorRecord, nil)
    saveAddressBookChanges()

    return visitorRecord
}

Which i like to trigger by

func addVisitorToContacts(sender: AnyObject) {
    //let visitor = ListVisitors[visitorButton.tag]
    var visitorDict:[Int:String] = [1:"\(visitorName)", 2:"\(visitorCompany)", 3:"\(visitorCity)",
        4:"\(visitorPhone)", 5:"\(visitorEmail)"]

    let visitorRecord: ABRecordRef = makeAndAddVisitorRecord2(visitorDict)
    let contactAddedAlert = UIAlertController(title: "\(visitorName) was successfully added.",
        message: nil, preferredStyle: .Alert)
    contactAddedAlert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
    presentViewController(contactAddedAlert, animated: true, completion: nil)
}

But makeAndAddVisitorRecord2 compiles an error

 Cannot specialize non-generic type 'ABRecordRef' (aka 'AnyObject')

[EDIT 1] workable solution but not optimal as i am not using my Visitor struct

func makeAndAddVisitorRecord2(visitorDict: Dictionary <Int, String>) -> ABRecordRef  {

[EDIT 2] as @rsmoz pointed out i should use my Visitor struct

class Visitor {

var visitorName : String
var visitorCompany : String
var visitorPlace : String
var visitorPhone : String
var visitorEmail : String

init(visitorName: String, visitorCompany: String, visitorPlace: String, visitorPhone: String, visitorEmail: String) {
    self.visitorName = visitorName
    self.visitorCompany = visitorCompany
    self.visitorPlace = visitorPlace
    self.visitorPhone = visitorPhone
    self.visitorEmail = visitorEmail
}

}

So i have a ListVisitors class which generates some Visitors and looks like

class ListVisitors{
    static var sharedInstance = [Visitor]()

static func load()
    {
        // @todo: stored and loaded data
        var visitor = Visitor(visitorName: "From Class Matt", visitorCompany: "Google", visitorPlace: "San Diego", visitorPhone: "94888484", visitorEmail: "[email protected]")
        sharedInstance = [visitor]

        visitor = Visitor(visitorName: "From Class John", visitorCompany: "nike", visitorPlace: "New York", visitorPhone: "94888484", visitorEmail: "[email protected]")
        //        ListVisitors.sharedInstance += [visitor]
        sharedInstance += [visitor]
...
}
}

And in my main controller i have a table view and a selected row sends the visitor details to detailcontroller (HOW can i have the selected visitor struct in detail view controller?? Should i pass let selectedVisitor to the detail view controller?)

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?){
if (segue.identifier == "visitorDetails") {

            if let indexPath = tableView.indexPathForCell(sender as! UITableViewCell) {

                let selectedVisitor = lVisitors[indexPath.row] as Visitor

                let detailVC = segue.destinationViewController as! DetailViewController

                detailVC.visitorName = selectedVisitor.visitorName
                detailVC.visitorCompany = selectedVisitor.visitorCompany
                detailVC.visitorPlace = selectedVisitor.visitorPlace
                detailVC.visitorPhone = selectedVisitor.visitorPhone
                detailVC.visitorEmail = selectedVisitor.visitorEmail

            } // .end accessory select

        } // .end segue
like image 523
alex Avatar asked Jan 03 '16 11:01

alex


People also ask

Can a dictionary be a parameter?

Functions with kwargs can even take in a whole dictionary as a parameter; of course, in that case, the keys of the dictionary must be the same as the keywords defined in the function. You cannot directly send a dictionary as a parameter to a function accepting kwargs.

How do you grab a value from a dictionary?

You can use the get() method of the dictionary ( dict ) to get any default value without an error if the key does not exist. Specify the key as the first argument. The corresponding value is returned if the key exists, and None is returned if the key does not exist.

Can you pass function as parameter in Python?

Because functions are objects we can pass them as arguments to other functions. Functions that can accept other functions as arguments are also called higher-order functions. In the example below, a function greet is created which takes a function as an argument.


1 Answers

I'm not sure what you're trying to do with ABRecordRef <AnyObject, AnyObject>, but the <> syntax is for specifying a generic type. Like, an array that holds strings is Array<String>. ABRecordRef is not a generic type.

The Dictionary needs to have the types it holds specified in the parameter: Dictionary<String, Int>

Also, you're treating a dictionary like an array. Better to use a dictionary as it's meant to be used. Instead of [1:"\(visitorName)"], why not ["visitorName":visitorName]? That way you can access it like dict["visitorName"] You also don't need to do "\(visitorName)" if visitorName is a String to begin with. Just use the variable directly.

It would be even better, though, to represent a Visitor as a struct, not an array or dictionary:

struct Visitor {
    let name: String
    let company: String
    let city: String
    let phone: String //Yes, this should be a String and not an Int
    let email: String
}

And you could set it like this:

let v = Visitor(name: "Joe", company: "A Corp", city: "New York", phone: "+44 392 39275 22", email: "[email protected]")

And access it like this:

v.name

And that's just so much cleaner and safer. Now your code won't have any errors from accidentally accessing the wrong key on a dictionary.

Oh, and you should be using the Contacts framework these days, not ABAddressBook.

like image 127
rsmoz Avatar answered Oct 29 '22 12:10

rsmoz