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
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With