I am reading data from a firebase DB and storing it in a message object, How can I then access each element in that array? i.e how can I use the City string as I wish to assign that to a label. Same with each other element in the array.
firebaseDB.collection("user").document(key).collection("address").getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
}
else {
self.dataArr.removeAll()
for document in querySnapshot!.documents {
//print("\(document.documentID) => \(document.data())")
let msgdata = document.data() as! [String:Any]
var msgObj = Details()
if let city = msgdata["city"] as? String {
msgObj.city = city
}
if let country = msgdata["country"] as? String {
msgObj.country = country
}
if let county = msgdata["county"] as? String {
msgObj.county = county
}
if let lineOne = msgdata["lineOne"] as? String {
msgObj.lineOne = lineOne
}
if let lineTwo = msgdata["lineTwo"] as? String {
msgObj.lineTwo = lineTwo
}
if let postCode = msgdata["postCode"] as? String {
msgObj.postCode = postCode
}
self.dataArr.append(msgObj)
}
}
}
I will need to access each element as I have another function which will take each element and place it on a label in my ViewController
Something like this is what I wish to have
func DisplayAddress(){
city.text = city
postCode.text = postCode
}
I may be totally reading the question wrong but in trying to read into your question, I think the terminology may be where clarification is needed; Object vs Array
An object has properties - lets examine the Details() object
var msgObj = Details()
which contains address information for one user. So conceptually this is how it would be represented in FireStore
users
this_user
address
city: "some city"
country: "some country"
county: "some county"
line1: "line one"
the 'documents' are the items stored within the address collection
city: "some city"
country: "some country"
county: "some county"
line1: "line one"
and your Details() object has properties that correspond to those documents and stores them as properties within the object; city, county etc
msgObj.city = city
msgObj.country = country
On the other hand, an array contains a series of objects, not properties. e.g. an array would generally not contain city, country etc, but it would contain a series of Details() objects and each of those Detail() objects has it's properties of city, country etc. For example, suppose you want to work with addresses of several different users - you would create a Details() object for each user, which contains their address information and append each one to an array.
self.dataArry[0] = the Details() objects of one user
self.dataArry[1] = the Details() object of another user
self.dataArry[2] = the Details() object of a third user
You could then, for example, display the users within a certain radius of this user, or send them all an email etc.
To answer your question, if you are working with a single users address information there is no need for an array, you can simply store it as a single Details() object variable within the class.
class ViewController: UIViewController {
var myUserAddress = Details()
func to get this users address documents from FireStore {
if let city = msgdata["city"] as? String {
self.myUserAddress.city = city
}
if let country = msgdata["country"] as? String {
self.myUserAddress.country = country
}
//remember that the properties are only valid from here on
//as FireStore is asychronous
self.DisplayCity()
self.DisplayLocation()
}
//and then later on when you want to display those properties
func DisplayCity() {
let city = self.myUserAddress.city
print(city)
}
func DisplayLocation() {
let lon = self.myUserAddress.logitude
let lat = self.myUserAddress.latitude
//show the location on a map via lon & lat
}
Related
I have this data structure and I can't extract the right value:
users
private
userID
birthday: "birthdayValue"
username: "nathan"
firstName: "Nathan"
etc...
I'm making a search feature in my app to search for users via their username through the firebase realtime database:
let reference = Database.database().reference()
if(searchText != ""){
reference.child("users").child("private").queryOrdered(byChild: "username").queryStarting(atValue: searchText).queryEnding(atValue: searchText + "\u{f8ff}").observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.value is NSNull{
//handles errors
return
}
else{
if let user = snapshot.value as? NSDictionary {
for child in user{
print(child.key)
print(child.value)
}
}
else{
//null
}
}
})
at the moment the two print statements are printing these two results in the console every time I search:
wnszfmHilqNl6PG9khWtWkKUPtF3
{
birthday = 100;
dateCreated = "1579543450313.94";
description = nil;
email = "email#email.com";
firstName = Nathan;
instagramLink = nil;
lastLogin = "1579543450313.988";
lastName = Ellis;
profilePicURL = "url";
twitchLink = nil;
username = nathan;
youtubeLink = nil;
}
Which is expected, it prints the usersID (the key) and the value of the snapshot as a NSDictonary. I'm only interested in getting the username, nothing else. How would I extract the username out of this firebase snapshot so I can add their username as a string to an array for my search controller?
Obviously it needs to be dynamic as the userID will always be different.
Would I need to change my data model?
Your child.value seems to be a dictionary as well, so you can access it by:
if let valueDict = child.value as? [String: AnyObject] {
if let username = valueDict["username"] as? String {
// append username to results
print(username)
}
}
To print just the username, the smallest possible change is:
print(resultsLocalArray["username"])
This will fine, but will still retrieve the entire user node to the client, which uses more bandwidth than strictly needed.
If you find yourself frequently needing just the username of a user, or maybe even a list of username values across users, you might want to consider storing a node with just user names. So something like:
users
userID: "nathan"
But in your current setup you only retrieve the node for a single user, so I doubt the bandwidth savings are worth the additional complexity.
The Apple documentation suggests using CNPostalAddressFormatter to display addresses as a formatted string, which helps immensely with internationalization.
This code:
let postalString = CNPostalAddressFormatter.string(from: postalAddress.value, style: .mailingAddress)
yields this work address for the John Appleseed contact on the simulator:
3494 Kuhl Avenue
Atlanta GA 30303
The address is missing the comma between city and state.
Is there a way for CNPostalAddressFormatter to insert the comma? The documentation doesn't list anything.
If not, doesn't this mean you must manually format addresses for each locality, and are unable to use CNPostalAddressFormatter for localization?
Here is my snippet to add "," after city for US addresses.
#if canImport(Contacts)
import Contacts
public extension CLPlacemark {
/// Get a formatted address.
var formattedAddress: String? {
guard let postalAddress = postalAddress else {
return nil
}
let updatedPostalAddress: CNPostalAddress
if postalAddress.isoCountryCode == "US" {
// add "," after city name
let mutablePostalAddress = postalAddress.mutableCopy() as! CNMutablePostalAddress
mutablePostalAddress.city += ","
updatedPostalAddress = mutablePostalAddress
} else {
updatedPostalAddress = postalAddress
}
return CNPostalAddressFormatter.string(from: updatedPostalAddress, style: .mailingAddress)
}
}
#endif
might sound like a basic question--but I'm not seeing where I am going wrong..
I end up with either of these two scenarios:
I keep getting the error "Could not cast value of type __NSCFNumber to NSSTring". if I use extractedSku = skuList[i]!.value["sku"] as! String
If I remove as! String it saves it, but it isn't saved as a string. How do I get this to be saved as a string?
I have appended data from firebase into an array
skuArray = [AnyObject?]()
in viewDidLoad, I am iterating skuArray to extract the 'sku' and store into a variable.
var skuArray = [AnyObject?]()
var productDetailArray = [AnyObject?]()
data stored in Sku Array is:
[Optional(Snap (aRandomKey) {
active = 1;
sku = 888888;
})]
viewDidLoad:
let skuList = self.skuArray
for var i = 0; i < skuList.count ; ++i{
let extractedSku = skuList[i]!.value["sku"] as! String
// go into database and extract "products" details by sku
self.databaseRef.child("products/\(extractedSku)").observeEventType(.ChildAdded, withBlock: { (snapshot:FIRDataSnapshot) in
self.productDetailArray.append(snapshot)
})
Since the underlying type is NSNumber, use the stringValue property to get a String:
if let extractedSku = (skuList[i]?.value["sku"] as? NSNumber)?.stringValue {
// use extractedSku which is of type String
}
I am working on iOS application using swift, and I have the following data in firebase dashboard of the application
Users =
{
"07a5fa11-2a09-455b-92bf-a86dcd9d3e3e" =
{
Name = "Hissah";
Category = "Art & Designe";
City = "Riyadh";
Email = "H#him.fm";
ShortDescription = "";
};
"08e5443c-cdde-4fda-8733-8c4fce75dd34" =
{
Name = "Sara";
Category = "Cheefs";
City = "Dubai";
Email = "Sara#gmail.com";
ShortDescription = "best cake ever . ";
};
How can I retrieve the (Name) of the users whose (City) is "Riyadh" to a table view?
Thanks in advance.
Tossing this in the ring as it's a straightforward answer and addresses a dataSource that can be used to populate a tableView
let ref = Firebase(url:"https://your-app.firebaseio.com/users")
ref.queryOrderedByChild("City").queryEqualToValue("Riyadh")
.observeEventType(.Value, withBlock: { snapshot in
//iterate over all the values read in and add each name
// to an array
for child in snapshot.children {
let name = child.value["Name"] as! NSString
self.tableViewDataSourceArray.append(name)
}
//the tableView uses the tableViewDataSourceArray
// as it's dataSource
self.tableView.reloadData()
})
Edit: A follow up comment asked how to add the text to a NSTextView
ref.queryOrderedByChild("City").queryEqualToValue("Riyadh")
.observeEventType(.Value, withBlock: { snapshot in
//iterate over all the values and add them to a string
var s = String()
for child in snapshot.children {
let name = child.value["Name"] as! NSString
s += name + "\n" // the \n puts each name on a line
}
//add the string we just build to a textView
let attrString = NSAttributedString(string: s)
self.myTextView.textStorage?.appendAttributedString(attrString)
})
With your current node "Users" you would have to download all users and individually check to see which ones have the city "Riyadh". This would be a waste because you would be reading a lot of data you might not need.
If searching for users by city is a main feature of your app I would make another node "Cities" which would contain a list of cities. Each city node would then contain a list of all the users in that city and you could query that node. Then if you need more information on those users you know which specific people to look up in your "Users" node. You could then use this information however you see fit in your table view.
Cities:
{
"Riyadh":
{
"07a5fa11-2a09-455b-92bf-a86dcd9d3e3e":true
},
"Dubai":
{
"08e5443c-cdde-4fda-8733-8c4fce75dd34":true
}
},
Users:
{
"07a5fa11-2a09-455b-92bf-a86dcd9d3e3e":
{
Name: "Hissah";
Category: "Art & Designe";
City: "Riyadh";
Email: "H#him.fm";
ShortDescription: "";
};
"08e5443c-cdde-4fda-8733-8c4fce75dd34":
{
Name: "Sara";
Category: "Cheefs";
City: "Dubai";
Email: "Sara#gmail.com";
ShortDescription: "best cake ever . ";
};
Further reading here, where it talks about denormalizing data:
https://www.firebase.com/docs/web/guide/structuring-data.html
How do I access the read-only and/or mutable contact records pertaining to what I believe to be custom labeled relationship contact data?
For instance I have Daughter-In-Law, Husband or Son custom labels associated with a contact Do I need CNLabeledValue CNLabelContactRelationChild? What do I need to read these or get these custom labels from contact data?
Here is what I managed to do in order to assign a relation to a contact and be able to fetch it using the relation
var myNewContact = CNMutableContact()
let myRelation = CNContactRelation(name: "mommy")
let myMom = CNLabeledValue(label: CNLabelContactRelationMother, value: myRelation)
myNewContact.contactRelations.append(myMom)
// add additional info to your contact such as name, email, family
// save your contact
let keysToFetch = [CNContactGivenNameKey, CNContactRelationsKey, CNContactEmailAddressesKey]
let text = "mommy"
let request = CNContactFetchRequest(keysToFetch: keysToFetch)
do {
try store.enumerateContactsWithFetchRequest(request) {
contact, stop in
for var i = 0; i < contact.contactRelations.count; i++ {
if (contact.contactRelations[i].valueForKey("value")?.valueForKey("name")!)! as? String == text
{
print(contact.givenName)
print(contact.identifier)
}
}
}
} catch let err{
print(err)
}
}