How to retrieve phone number from Contacts framework - swift

New to contacts trying to retrieve Mobile Phone number. I have address name email but cannot figure out mobile phone. This is what I got. The portion marked with ** is where I am going wrong.
if let oldContact = self.contactItem {
let store = CNContactStore()
do {
let mykeysToFetch = [CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName), CNContactEmailAddressesKey, CNContactPostalAddressesKey,CNContactImageDataKey, CNContactImageDataAvailableKey,CNContactPhoneNumbersKey]
let contact = try store.unifiedContactWithIdentifier(oldContact.identifier, keysToFetch: mykeysToFetch)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
if contact.imageDataAvailable {
if let data = contact.imageData {
self.contactImage.image = UIImage(data: data)
}
}
self.fullName.text = CNContactFormatter().stringFromContact(contact)
self.email.text = contact.emailAddresses.first?.value as? String
self.phoneNumber.text = contact.phoneNumbers.first?.value as? String
**if contact.isKeyAvailable(CNContactPhoneNumbersKey){
if let phoneNum = contact.phoneNumbers.first?.value as? String {
self.phoneNumber.text = phoneNum as String
}
}**
if contact.isKeyAvailable(CNContactPostalAddressesKey) {
if let postalAddress = contact.postalAddresses.first?.value as? CNPostalAddress {
self.address.text = CNPostalAddressFormatter().stringFromPostalAddress(postalAddress)
} else {
self.address.text = "No Address"
}
}
})
} catch {
print(error)
}
}

If you want a list of the mobile phones for a contact, you look at phoneNumbers which is an array of CNLabeledValue, and find those with a label of CNLabelPhoneNumberMobile or CNLabelPhoneNumberiPhone.
For example, you could do something like:
let mobilePhoneLabels = Set<String>(arrayLiteral: CNLabelPhoneNumberMobile, CNLabelPhoneNumberiPhone, "cell", "mobile") // use whatever you want here; you might want to include a few strings like shown here to catch any common custom permutations user may have used
let mobileNumbers = contact.phoneNumbers.filter { mobilePhoneLabels.contains($0.label) && $0.value is CNPhoneNumber }
.map { ($0.value as! CNPhoneNumber).stringValue }
So if you want the first one:
let mobileNumber = mobileNumbers.first ?? "" // or use `if let` syntax
Or if you want a string representation of the list of them:
let mobileNumberString = mobileNumbers.joinWithSeparator(" ; ")
What you do with this array of mobile numbers is up to you, but hopefully this illustrates the basic idea.

Related

How to get an Dictionary from Firebase Firestore in Swift

I wonder how to get an Dictionary from my Firestore. For normal Arrays I've done it like that:
func returnArray(){
let newpath = Firestore.firestore().collection(path)
newpath.addSnapshotListener { (querySnapshot, error) in
guard let documents = querySnapshot?.documents else {
return
}
self.Array = documents.map { (queryDocumentSnapshot) -> String in
let data = queryDocumentSnapshot.data()
let Name = data["myField"] as? String ?? ""
return Name
}
}
}
That works perfectly fine. My question is now how I have to change my code that its getting an Array out of the Firebase. I had an idea, but it doesn't work:
func returnDictionary(){
let newpath = Firestore.firestore().collection(path)
newpath.addSnapshotListener { (querySnapshot, error) in
guard let documents = querySnapshot?.documents else {
return
}
self.Dictionary = documents.map { (queryDocumentSnapshot) -> // I don't know what to fill here
in
let data = queryDocumentSnapshot.data()
let Name = data["AnzeigeName"] as? String ?? ""
let ID = data["selfID"] as? String ?? ""
return ID: Name
}
}
}
What can I try next?
.map is going to give you an array, but you can use Dictionary's init(uniqueKeysWithValues:) to turn this into a Dictionary:
let dictionary : Dictionary<String,String> = .init(uniqueKeysWithValues: documents.compactMap { queryDocumentSnapshot -> (String,String)? in
let data = queryDocumentSnapshot.data()
if let name = data["AnzeigeName"] as? String, let id = data["selfID"] as? String {
return (id, name)
}
return nil
})
It's important to know that uniqueKeysWithValues will crash if the keys are not in fact unique, so you'd want to check for that first (look at #New Dev's comment about init(_:uniquingKeysWith:) to handle this). I'm also using compactMap to get rid of nil values.
(Note: In Swift, generally variable names are lowercased and type names are uppercased. Going against that pattern can make your code challenging to read for others)
Firestore Example
{
name: "Anonymous"
pet {
name: "Max"
age: "3"
}
}
Query
Firebase.firestore().collection(path).getDocuments { querySnapshot, error in
if let error = error {
print(error.localizedDescription)
} else {
for document in querySnapshot!.documents {
let data = document.data()
let name = data["name"]
let pet = data["pet"] as! Dictionary<String, String>
print("Name: \(name)")
print("Pet-name: \(pet["name"]!)")
print("Pet-age: \(pet["age"]!)")
}

Parse Alamofire result swift

I'm very lost parsing the following response from an AF request – let json = result as! NSDictionary – in Swift:
{
errors = (
);
get = statistics;
parameters = {
country = germany;
};
response = (
{
cases = {
"1M_pop" = 14303;
active = 317167;
critical = 4179;
new = "+15161";
recovered = 863300;
total = 1200006;
};
continent = Europe;
country = Germany;
day = "2020-12-08";
deaths = {
"1M_pop" = 233;
new = "+380";
total = 19539;
};
population = 83900328;
tests = {
"1M_pop" = 347331;
total = 29141172;
};
time = "2020-12-08T09:15:08+00:00";
}
);
results = 1;
}
Any idea how to get the actual case numbers, i.e. for example the number of new cases?
So far I have tried the following (error throwing) approach:
if let responseDict = result as? NSDictionary {
if let data = responseDict.value(forKey: "response") as?
[NSDictionary] {
// Get case numbers
guard let cases = data[0]["cases"] else { return }
guard let casesPerOneMil = cases[0] as! Int else { return }
print(casesPerOneMil)
}
}
Basically don't use NS... collection types in Swift at all, use native types.
And don't use value(forKey, use key subscription.
And you have to conditional downcast Any to the expected concrete type.
There is another mistake: The object for cases is a dictionary, note the {} and you have to get the value for casesPerOneMil with key subscription, too
if let responseDict = result as? [String:Any],
let dataArray = responseDict["response"] as? [[String:Any]],
let firstDataItem = dataArray.first {
// Get case numbers
guard let cases = firstDataItem["cases"] as? [String:Any] else { return }
guard let casesPerOneMil = cases["1M_pop"] as? Int else { return }
print(casesPerOneMil)
}
}

Swift code problem - trying to cast objects out from a NSMutableArray as a custom object

Here is my code and it fails to execute as noted below.
I am trying to cast an object to my custom data type called UserData.
First problem I have is don't understand how to get the value out of the array correctly
Second I cannot seem to cast the object as the type I need, UserData. What I am doing wrong?
func parseJSON(_ data:Data) {
var jsonResult = NSArray()
var users = NSMutableArray();
do{
jsonResult = try JSONSerialization.jsonObject(with: data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSArray
} catch let error as NSError {
print(error)
}
var jsonElement = NSDictionary()
for i in 0 ..< jsonResult.count {
print("loop count :", i );
jsonElement = jsonResult[i] as! NSDictionary
let user = UserData()
//the following insures none of the JsonElement values are nil through optional binding
if let UserID = jsonElement["Userid"] as? String,
let firstName = jsonElement["First_Name"] as? String,
let lastName = jsonElement["Last_Name"] as? String,
let userSessionID = jsonElement["Session_ID"] as? String
{
user.UserID = UserID
user.FirstName = firstName
user.LastName = lastName
user.UserSessionID = userSessionID
print("users firstName:", user.FirstName ?? "blank");
}
users.add(user)
}
print("users size:", users.count); // this shows 2
// So i know I have data loaded... BUT when i try and
// get it then it all goes to heck. See below
// NOT SURE what I am doing here...
// Thought it was java like where I could just get a
// item from the NSMutableArray using an index value
// then cast it as my UserData object
// and print the output... but this does not work
// Why is this so hard??
let userDataVal = users.index(of: 0) as! UserData;
print("firstName:", userDataVal.FirstName);
}
Below is how I would write this function. Some comments
No NS... classes used, instead I use native arrays and dictionaries
If JSONSerialization.jsonObject generates an error the function is exited
Local variables are define as close as possible to as where they are used
Create an init method for your UserData struct/class that takes the values as parameters so you can do let user = UserData(userId: UserId, firstName:... instead.
Name local variables and properties with a first lowercase character, it makes it easier to read the code
func parseJSON(_ data:Data) {
var jsonResult: [[String: Any]]?
do {
jsonResult = try JSONSerialization.jsonObject(with: data, options:JSONSerialization.ReadingOptions.allowFragments) as? [[String: Any]]
} catch let error as NSError {
print(error)
return
}
guard let result = jsonResult else {
return
}
var users = [UserData]()
for jsonElement in result {
if let UserID = jsonElement["Userid"] as? String,
let firstName = jsonElement["First_Name"] as? String,
let lastName = jsonElement["Last_Name"] as? String,
let userSessionID = jsonElement["Session_ID"] as? String
{
var user = UserData()
user.UserID = UserID
user.FirstName = firstName
user.LastName = lastName
user.UserSessionID = userSessionID
users.append(user)
}
}
for user in users {
print("firstName:", user.FirstName);
}
}
Better approach would be to use JSONDecoder() instead of a JSONSerailizer. Try using the following code.
struct User: Codable {
var userId, firstName, lastName, userSessionId: String
enum CodingKeys: String, CodingKey {
case userId = "Userid"
case firstName = "First_Name"
case lastName = "Last_Name"
case userSessionId = "Session_ID"
}
}
func parseJSON(_ data: Data) {
do {
let users = try JSONDecoder().decode([User].self, from: data)
users.forEach { user in
print("users first name:", user.firstName)
}
} catch {
print(error.localizedDescription)
}
}

Showing just one image at the time from database (Swift and Firebase)

First of all, I am new in this, so please do not make fun of me :)
Basically, I am trying to show and Image of a product but if the client refuses the product this item will not appear on his account. That is why I am creating another table Rejected (setAcceptedOrRejected) where I put the ID of the product and the Id of the client so I wont see the item he rejected before.
What I tried here it was to get the List (Good) with all the items and the (Bad) with the rejected items. Then compare it to display the picture of the item again.
My problem is that I want to show only 1 picture at the time, if the client refuses then it will show the next one and so on but it wont show that picture again.
I hope you can really help me with this one.
Thank you
func updateImage() {
createListProductsBad ()
var badnot = ""
for bad2 in listProductsBad{
badnot = bad2
}
Database.database().reference().child("Products").child(bad2)queryOrderedByKey().observe(.childAdded, with: { snapshot in
let userInfo = snapshot.value as! NSDictionary
let storageRef = Storage.storage().reference(forURL: profileUrl)
storageRef.downloadURL(completion: { (url, error) in
do {
let data = try Data(contentsOf: url!)
let image = UIImage(data: data as Data)
self.productPhoto.image = image
}
catch _ {
print("error")
}
})
})
}
func setAcceptedOrRejected() {
let notThankyou = [ "ProductID": ProductId,
"UserID": userUID
] as [String : Any]
self.storyboard?.instantiateViewController(withIdentifier: "Home")
self.refProducts.child("Rejected").childByAutoId().setValue(notThankyou)
}
func createListProductsGood () {
Database.database().reference().child("Products").queryOrderedByKey().observe(.childAdded, with: { snapshot in
if !snapshot.exists() { return }
let userInfo = snapshot.value as! NSDictionary
let goodID = String(snapshot.key)
for prod in self.listProductsBad{
if (prod == goodID){
print("Not good **********************")
}else{
if (goodID != "" ){
self.listProductsGood.append(prod)
}
}
}
})
}
func createListProductsBad () {
Database.database().reference().child("Rejected").queryOrderedByKey().observe(.childAdded, with: { snapshot in
let userInfo = snapshot.value as! NSDictionary
let currentID = userInfo["UserID"] as! String
let badProduct = userInfo["ProductID"] as! String
if (self.userUID == currentID ){
self.listProductsBad.append(badProduct)
}
})
}
}
//These can also be swift's dictionaries, [String: AnyObject] or possibility arrays if done correctly. All depends on your style of programming - I prefer NSDictionaries just because.
let availableKeys: NSMutableDictionary = [:]
let rejectedKeys: NSMutableDictionary = [:]
//Might be a better way for you. Depends on what you are looking for.
func sortItems2() -> NSMutableDictionary{
for rejKey in rejectedKeys.allKeys{
//Removes if the rejected key is found in the available ones
availableKeys.remove(rejKey)
}
return availableKeys
}

Duplicates in accessing address book

For some reason, I keep getting duplicates on a lot of the contacts that I'm able to access with my code. Any reason why?
var error: Unmanaged<CFError>?
addressBook = ABAddressBookCreateWithOptions(nil, &error).takeRetainedValue()
if let people = ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(self.addressBook, nil, ABPersonSortOrdering(kABPersonSortByFirstName)).takeRetainedValue() as? NSArray {
for record in people {
//var contactPerson: ABRecordRef = record
var contactName: String = ABRecordCopyCompositeName(record).takeRetainedValue() as String
var number = ""
var phones: ABMultiValueRef = ABRecordCopyValue(record, kABPersonPhoneProperty).takeRetainedValue()
for j in 0..<ABMultiValueGetCount(phones) {
number = ABMultiValueCopyValueAtIndex(phones, j).takeRetainedValue() as! String
break
}
if (number != "") {
var newPerson = personInfo(name: contactName, number: number)
allContacts.append(newPerson)
}
self.tableView.reloadData()
}
}
James Richards Please Use the Contacts frame work instead of using address book.
First you shoud add Contacts framework through Build Phases->Link Binary with Libraries->add(click +)->choose contacts framework
import Contacts
Then
let status = CNContactStore.authorizationStatusForEntityType(.Contacts)
if status == .Denied || status == .Restricted {
// user previously denied, so tell them to fix that in settings
return
}
// open it
let store = CNContactStore()
store.requestAccessForEntityType(.Contacts) { granted, error in
guard granted else {
dispatch_async(dispatch_get_main_queue()) {
// user didn't grant authorization, so tell them to fix that in settings
print(error)
}
return
}
// get the contacts
var contacts = [CNContact]()
let request = CNContactFetchRequest(keysToFetch:[CNContactIdentifierKey, CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName)])
do {
try store.enumerateContactsWithFetchRequest(request) { contact, stop in
contacts.append(contact)
}
}
catch {
print(error)
}
// do something with the contacts array (e.g. print the names)
let formatter = CNContactFormatter()
formatter.style = .FullName
for contact in contacts {
print(formatter.stringFromContact(contact))
}
}
The Output Results
Optional("John Appleseed")
Optional("Kate Bell")
Optional("Anna Haro")
Optional("Daniel Higgins Jr.")
Optional("David Taylor")
Optional("Hank M. Zakroff")
Link 1
Apple Document
Contacts