Code for extracting CNContactLabels from the IOS contact store - ios

I am trying to extract a list of available labels for phone numbers in the IOS contact store so that when the user adds a new number to a contact he/she can select a label from a table list for that number.
I have no problem with retrieving and writing contact numbers but the listing of available labels is eluding me.
What I am really trying to achieve is to extract the array of labels for phone numbers as in :
var phoneNumbers : [CNLabeledValue<CNPhoneNumber>] = []
but I can't find out where to extract values for phoneNumbers.

Please check this code for CNLabeledValue, its working for me.
for phoneNumber in contact.phoneNumbers {
if let number = phoneNumber.value as? CNPhoneNumber,
let label = phoneNumber.label {
let localizedLabel = CNLabeledValue.localizedStringForLabel(label)
print("\(localizedLabel) \(number.stringValue)")
}
}

In the end I extracted a list of label constants from the documentation and did:
let arrLab = [CNLabelPhoneNumberHomeFax, CNLabelPhoneNumberMain,CNLabelPhoneNumberMobile,CNLabelPhoneNumberOtherFax, CNLabelPhoneNumberPager, CNLabelPhoneNumberWorkFax,CNLabelPhoneNumberiPhone,CNLabelOther ]
for bod in arrLab {
let label = CNLabeledValue<NSString>.localizedString(forLabel: bod)
arr1.append(label)
}
Not ideal because if Apple decides to add a new constant the app would require maintenance. It would be better to be able to extract the constants directly from the device.
Also, if there are custom labels my code would miss those.

Related

retrieve data from firebase and set VC to match users preferences

I have a viewController that is very similar to tinder. A user can swipe left or right depending on how many values are stored in firebase. Every value from firebase shows on the users VC no matter if it matches their preferences or not. I wanted to allow users to have preferences (again, very similar to tinder.) and only values that fall within those limits to show on the viewController. The way I am fetching all of the values from firebase is
func fetchPost() {
topCardView = nil
var previousCardView: CardView?
Database.database().reference().child("Post").observe(.childAdded, with: { (snapshot) in
if let userDictionary = snapshot.value as? [String: AnyObject] {
let poster = Poster(dictionary: userDictionary as [String : AnyObject])
let cardView = self.setupCardFromUser(poster: poster)
self.cardViewModels.append(poster.toCardViewModel())
if let currentUser = Auth.auth().currentUser?.uid,
currentUser == poster.fromId {
cardView.removeFromSuperview()
} else if self.topCardView == nil {
self.topCardView = cardView
}
previousCardView?.nextCardView = cardView
previousCardView = cardView
}
}, withCancel: nil)
}
The code above, allows the user to see every single value from firebase. but the preferences I want to manipulate this is cost and skills.
is there a simple way for me to only show the values from firebase if they match the users preferences?
in firebase, the usersPreferences tree is set up as
users
|______ usersUID
|______ minSeekingCost
|______ maxSeekingCost
|______ skills1
and how the postings are set up look like
post
|____ usersUID
|____ category
|____ cost
I want the users to find postings that are within the min&maxSeekingCost, and match their skills. Say if a post matches one of their skills, and the price is not within their limits, then it is not fetched. Same for if post does not match and the price is in their limits.
would I have to fetch the users preferences inside of the fetchPost? or can I manipulate the fetchPost itself to have these called.
You're looking for queries, which allow you to order and filter data.
But Firebase Database queries can only order/filter on a single property. In certain cases it is possible to combine the values you want to filter on into a single (synthetic) property. For an example of this and other approaches, see my answer here: Query based on multiple where clauses in Firebase

How physical it is to change structure in firebase

If I am storing employee data in firebase which has 3 fields and in future if I want add or remove a field then how physical it is in firebase ? and how can I do it?
I want to use Firebase for one of my iOS project(Swift 4) which I am going to start working on soon so I want to clear the above mentioned concern.
While Lance's answer works - here's a simple alternative. Assume you want to remove an age 'field' from Firebase. Given a structrue
employees
employee_0
name: "Steve"
age: "42"
employee_1
name: "Hank"
age: "37"
if you want to remove the age node from all employee nodes, this will do it
let employeesRef = Database.database().reference().child("employees")
employeesRef.observe(.childAdded, with: { snapshot in
let key = snapshot.key
let refToRemove = employeesRef.child(key).child("age")
refToRemove.removeValue()
})
Adding a field (child node) is even simpler as child node values cannot be nil so when you write the data, it's added to the node
employeesRef.child(employee_key).child("favorite_food").setValue("pizza")
will add a favorite food node with a value of pizza to an employee node.
Note that there are no 'fields' in Firebase, only parent and child nodes which are key: value pairs.
Jay’s answer is the better way to accomplish what you are asking but this is an alternative. If your a beginner this might be easier to understand and start with. As you advance use Jay’s code.
Seems like you want to do something like this.
Your database structure in Firebase is:
root
|
#-012345 // eg. employeeId
|-"firstName": "Hello"
|-"lastName": "World"
|-"age": "25"
You want to add or remove a field there are several ways to do it but this way it's easy. All you have to to is keep track of the original values then add those plus the new values to a Dictionary and exclude whatever you don't want to send to Firebase using the .setValue() method :
// class properties
let rootRef: DatabaseReference? = Database.database().reference()
let employedID = "012345"
let firstName = "Hello" // original value you want to keep
let lastName = "World" // original value you want to keep
let age = "25" // original value you want to REMOVE
lat gender = "female" // NEW value you want ADDED
// press the button to send the write the values to Firebase
#IBAction fileprivate func updateEmployeeButton(_ sender: UIButton) {
// add the values to a dictionary
let dict = [String:Any]()
dict.(firstName, forKey: "firstName")
dict.(lastName, forKey: "lastName")
dict.(gender, forKey: "gender")
let employeeIdRef = rootRef?.child(employedID)
employeeIdRef?.setValue(dict) // call Firebase's .setValue method and pass the dict as an argument
}
Your database structure will now look like this:
root
|
#-012345
|-"firstName": "Hello"
|-"lastName": "World"
|-"gender": "female"
Notice the way I’m proposing complete overwrites what was at that node but Jay’s way keeps what was there but still gets you the changes you want to make.

Phone number format from country code on iOS

I need to display phone number format as placeholder in UITextField. How can I do that?
For country selection I'm using below mentioned library and it provides me country flag and country code against user selected country.
https://github.com/NikKovIos/NKVPhonePicker
After selecting a country I need to display phone number format for that selected country and on submission of that phone number I have to validate the phone number.
I also find that third party (PhoneNumberKit) which is inspired by google's libphonenumber but it is for validating, it do not provide expected phone number format against country code. Below is the link.
https://github.com/marmelroy/PhoneNumberKit
Update 1:
Tried this and getting Generic parser error
let phoneNumberKit = PhoneNumberKit()
do {
let phoneNumber = try phoneNumberKit.parse("+921230123456")
}
catch {
print("Generic parser error")
}
Update 2:
Updated code, still getting exception
let phoneNumberKit = PhoneNumberKit()
do {
let phoneNumber = try phoneNumberKit.parse("1230123456", withRegion: "FR", ignoreType: false)
let formatedNumber = phoneNumberKit.format(phoneNumber, toType: .international)
print(formatedNumber)
}
catch {
print("Generic parser error")
}
I don't know whether this is a valid solution or not, you could try this
Say let your placeholder be 012345679 what I believe you could do is
Create a variable to store this placeholder
Parse this placeholder against the country that the user selects.
Set the parsed one as the placeholder in the textfield.
For those who wanna do the same thing, I used two different 3rd parties to achieve the functionality.
NKVPhoneNumber
SHSPhoneComponent
NKVPhoneNumber is used to select country code, i've modified it a bit a introduced phone_format in the Meta Data. Once selected a country from the list it return a Country object which includes Code, Extension, Flag and format_placeholder
SHSPhoneComponent then use that format_placeholder for validation of the format.
import SHSPhoneComponent
import NKVPhonePicker
#IBOutlet weak var phoneTF: SHSPhoneTextField!
#IBOutlet weak var phoneFlag: NKVPhonePickerTextField!
#IBOutlet weak var lblCountryCode: UILabel!
//MARK: - NKV callback delegates
func countriesViewController(_ sender: CountriesViewController, didSelectCountry country: Country) {
//
phoneTF.formatter.setDefaultOutputPattern(country.formatPattern)
phoneTF.text = ""
phoneTF.placeholder = country.formatPatternPlaceHolder
countryCode = "+\(country.phoneExtension)"
lblCountryCode.text = countryCode
}
Note: I've converted NVKPhoneNumber to Swift 4.0,

How to Make a Struct Version of the NSCountedSet Class?

I am developing an app in which I need to take two arrays, both holding the same custom data type, MenuItem.
I need to compare them and find the common elements of both arrays.
I compare the two arrays by converting them both to sets and then using the compare function of the set struct.
However, I then need to convert the array of common elements to a Counted Set so that I can find how many of each element exist in the group of common elements.
The problem I am having is with converting the the array of common elements to a Counted Set. In Swift, there is an NSCountedSet class but no CountedSet struct like there are for most built-in swift Data Types:
let groups = Array(self.menu.keys)
//menu and cart are dictionaries the structure [MenuGroup: [MenuItem]]
let cartGroups = Array(self.cart.keys)
let group = groups[indexPath.section]
if cartGroups.contains(group) {
let items = menu[group] as [MenuItem]!
let cartItems = cart[group]
let itemsSet = Set<MenuItem>(items!)
let cartItemsSet = Set<MenuItem>(cartItems!)
let similarSet = itemsSet.intersection(cartItemsSet)
let similarArray = NSMutableArray(Array(similarSet))
let similarCounterSet = NSCountedSet(array: similarArray)
}
I want to create a struct based off the NSCountedSet class so that I can convert the array of common elements to a counted set.
The if statement is for something else, it does not pertain to this question.
Any thoughts on how to do this? If anybody has a different approach to this problem feel free to mention that too.
Thanks,
Simon
Thanks to Martin R I Found An Example of How to do This:
There are various CountedSet implementation available, e.g. https://github.com/0x7fffffff/CountedSet.

Firebase overwriting entries

I am new to Firebase and not sure how to best explain this but I will try.
I am trying to have my app create an entry for each user. Then each user entry has multiple (0 through n) sub-entries where each sub-entry is a simple string. Basically there is a user-id (the main entry) and their tasks are the sub-entries.
Now my problem is whenever I push data (the sub-entries) to the main entries, all of the previous sub-entries are deleted and only the most recent one is pushed. I have been looking through the documentation and Googling like crazy but nothing seems to work.
I have tried this:
#IBAction func testWrite(sender: AnyObject) {
let def = NSUserDefaults.standardUserDefaults()
let uid = def.valueForKey("uid")
let root = Firebase(url: getFirebaseURL())
let text = self.tempText.text!
let dataRef = root.childByAppendingPath(uid as! String)
let data = ["test": String(text)]
dataRef.setValue(data)
}
Which appends to the user-id entry fine, with a key of "test" and a value of the 'text'
So then I kill the app and change it to:
#IBAction func testWrite(sender: AnyObject) {
let def = NSUserDefaults.standardUserDefaults()
let uid = def.valueForKey("uid")
let root = Firebase(url: getFirebaseURL())
let text = self.tempText.text!
let dataRef = root.childByAppendingPath(uid as! String)
let data = ["CHANGED": String(text)]
dataRef.setValue(data)
}
And it pushes fine, but then the previous entry was just deleted and the only entry left is this one.
What I am trying to do is maybe incrementally (having a numbered key possibly?) add items one by one without having other entries deleted.
I hope this makes sense :P and any help is greatly appreciated!
What is happening here is, you are setting the entire branch (Users/UserID##), to a value, and that value is a single node Changed:<somestring>
Conceptually, it may help to think of the key you want to set as being just another branch e.g (Users/UserID##/TaskID##)
So conceptually, instead of approaching it like this:
Users/UserID = Key:Value
Approach it like this:
Users/UserID/Key = Value
Note: the branch Users/UserID/Key does not have to exist prior to you assigning it a value.
e.g you could change your reference to point at the subkey you want to add or change:
let dataRef = root.childByAppendingPath(uid as! String + "/Task001")
dataref.setValue(String(text))
I concur that what you are doing is a great way to start learning Firebase, and how it works. But once you get going, instead of generating and using your own key for your list of subtasks, do look into childByAutoId, it will automatically create the subkeys for you, plus much more, and is much easier to manage and code.
Documentation Here
Edit: Suggest referring to Frank's better answer below.
An alternative to #MtlDev's answer would be to use updateChildValues():
let data = ["CHANGED": String(text)]
dataRef.updateChildValues(data)
While setValue() replaces the current data with the new value, updateChildValues() updates it in place.
See the Firebase documentation on updating saved data.

Resources