Reputation: 4914
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
Upvotes: 7
Views: 27507
Reputation: 547
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.
Upvotes: 10
Reputation: 271040
The dictionary type in Swift is called Dictionary
. However, it is generic, meaning that you need to add <>
after the type name to specify what type of dictionary you want it to be. In this case, it is Dictionary<Int, String>
. This is because the variable that you are passing to the method (visitorDict
) is of type Dictionary<Int, String>
.
Write your function header like this:
func makeAndAddVisitorRecord2(visitorDict: Dictionary<Int, String>) -> ABRecordRef <AnyObject, AnyObject> {
If you want to go one step further, you can use the shorthand type name for dictionary:
func makeAndAddVisitorRecord2(visitorDict: [Int: String]) -> ABRecordRef <AnyObject, AnyObject> {
Also, if your keys for the dictionary are sequential, like 1, 2, 3, 4 ,5 etc, you can use an array instead:
func makeAndAddVisitorRecord2(visitorDict: Array<String>) -> ABRecordRef <AnyObject, AnyObject> {
And the shorthand for arrays is:
func makeAndAddVisitorRecord2(visitorDict: [String]) -> ABRecordRef <AnyObject, AnyObject> {
Upvotes: 6
Reputation: 32786
ABRecordRef is not generic, thus you cannot use like you did. Most likely you wanted to add the generic declaration to the Dictionary parameter.
Upvotes: 0
Reputation: 5123
You have to specify what type of dictionary it is in swift, like so:
func makeAndAddVisitorRecord2(visitorDict: [Int: String]) -> 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
}
Then you can use makeAndAddVisitorRecord2(visitorDict)
and everything should work.
You collection types apple doc has more in-depth examples.
Upvotes: 2