I am trying to append values to an array inside a function and call that updated array in another function but it is not printing the new appended values.
I am using firebase and getting a snapshot of the database, sorting it, finding value of keys, and appending to hDates
var hDates:Array = [""]
getHistoryPGE() { hDates in
print(hDates)
self.hDates = [hDates]
}
func getHistoryPGE(completion: #escaping (String)->()) {
let userID = Auth.auth().currentUser?.uid
let ref = Database.database().reference().child("users").child(userID!)
ref.child("PostGameEval").observe(.value, with: { (snapshot) in
if let dict = snapshot.value as? [String : [String: [String: Any]]] {
let keys = Array(dict.keys)
var num : Int = 7
for i in 0..<keys.count {
if let innerDict = dict[keys[i]] {
let innerKeys = Array((innerDict).keys)
let sortedInnerKeys = innerKeys.sorted(by: { $0 > $1} )
while (sortedInnerKeys.count < num){
num -= 1
}
for j in 0..<num {
if let tempDict = innerDict[sortedInnerKeys[j]] {
print(tempDict["1abA"] as! String)
}
}
}
}
}})
}
func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int {
let dateString = self.dateFormatter.string(from: date)
if self.hDates.contains(dateString) {
return 1
}
return 0
}
Related
I am using an array named PosterEmail to search for a document field name "First Name" in my Firestore Database.
Here you can see my database set up.
FirebaseSetup
enter image description here
As you can see my Database is Public then in the document I have the user's email as the document name and in that document I have their information such as their first name, last name, and profile photo url.
I search for the document id using an Array
The PosterEmail array is
PosterEmail = ["chainsawloco#yahoo.com", "allmight#gmail.com", "allmight#gmail.com", "chainsawloco#yahoo.com"]
I am going through my PosterEmail index by setting a variable "profilecount" to 0 and adding 1 to it everytime to go through the PosterArray
let docRef = db.collection("Public").document("\(self.PosterEmail[self.profilecount])")
But it seems that the code above never searches for the Firebase document named after the second item in my Array
The result is just
["Irving ", "Irving ", "Irving ", "Irving "]
The result should end up as [Irving, Allmight, Allmight, Irving]
Is there something I"m doing wrong?
Below is where I call my getPosteInformation() in another method called getDatFromFirestore() (ehhh I know my method name has a typo but I can fix that later)
if let postedBy = document.get("postedBy") as? String {
print("Postby = document.get(postedby = \(postedBy)")
self.PosterEmail.append(postedBy)
if self.PosterEmail.count > 0 {
self.getPosteInformation()
}
}
}
}
}
Below you can see my full code.
func getDatFromFirestore() {
let firestoreDatabase = Firestore.firestore()
firestoreDatabase.collection("Posts").order(by: "Date" , descending : true).getDocuments { (snapshot, error) in
if error != nil {
print(error?.localizedDescription ?? "Connection Error")
} else {
self.userPostImageArray.removeAll(keepingCapacity: false)
self.userCommentArray.removeAll(keepingCapacity: false)
self.userCommentArray.removeAll(keepingCapacity: false)
self.likeArray.removeAll(keepingCapacity: false)
self.PosterEmail.removeAll(keepingCapacity: false)
self.userProfilePhotoArray.removeAll(keepingCapacity: false)
self.PosterFirstNameArray.removeAll(keepingCapacity: false)
self.PosterLastNameArray.removeAll(keepingCapacity: false)
for document in snapshot!.documents {
let documentID = document.documentID
self.documentIDArray.append(documentID)
if let postDescription = document.get("PostDescription") as? String {
self.userPostDescription.append(postDescription)
}
if let imageUrl = document.get("imageUrl") as? String {
self.userPostImageArray.append(imageUrl)
}
if let PostLikes = document.get("Likes") as? Int {
self.likeArray.append(PostLikes)
}
if let postTimeStamp = document.get("Date") as? Timestamp {
let date = postTimeStamp.dateValue()
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm MM/dd/yyyy"
let dateString = formatter.string(from: date)
let timeStampAsString = dateString
self.postDate.append(timeStampAsString)
}
if let postedBy = document.get("postedBy") as? String {
print("Postby = document.get(postedby = \(postedBy)")
self.PosterEmail.append(postedBy)
if self.PosterEmail.count > 0 {
self.getPosteInformation()
}
}
}
}
}
self.VidaFeed.reloadData()
}
func getPosteInformation() {
print("")
print(PosterEmail[profilecount])
print(profilecount)
print("")
print(PosterEmail)
let docRef = db.collection("Public").document("\(self.PosterEmail[self.profilecount])")
docRef.getDocument { (document, error) in
if let document = document, document.exists {
let dataDescription = document.data().map(String.init(describing:)) ?? "nil"
print("Document data: \(dataDescription)")
if self.profilecount < self.PosterEmail.count {
if let PosterFirstName = document.get("First Name") as? String {
self.PosterFirstNameArray.append(PosterFirstName)
print(self.PosterFirstNameArray)
print("\(self.profilecount)")
if self.PosterEmail.count > self.profilecount {
self.profilecount = self.profilecount + 1
}
}
}
} else {
print("Document does not exist")
}
}
}
if let postedBy = document.get("postedBy") as? String {
print("Postby = document.get(postedby = \(postedBy)")
self.PosterEmail.append(postedBy)
self.PosterFirstNameArray.append("")
if self.PosterEmail.count > 0 {
self.getPosteInformation(profCount: self.profileCount)
}
if self.PosterEmail.count > self.profilecount {
self.profilecount = self.profilecount + 1
}
}
And now if you could modify this method like this:
func getPosteInformation(profCount:Int) {
//and inside the async call back instead of the following try
/*if let PosterFirstName = document.get("First Name") as? String {
self.PosterFirstNameArray.append(PosterFirstName)
print(self.PosterFirstNameArray)
print("\(self.profilecount)")
if self.PosterEmail.count > self.profilecount {
self.profilecount = self.profilecount + 1
}
}*/
if let PosterFirstName = document.get("First Name") as? String {
self.PosterFirstNameArray[profCount] = PosterFirstName
print(self.PosterFirstNameArray)
print("\(profCount)")
}
}
My JSON data look like this image below. Now I wanna merge the value of Shop Type and Promotion into one to use as collection view data. How can I do that?
I just filter the response data from the server like this:
var dataBanDau: [SDFilterModel] = []
var quickData: [SDFilterModel] = []
let filters: [SDFilterModel] = data
self.filterEntries = filters
//let nsarray = NSArray(array: self.filterEntries! , copyItems: true)
// self.filterEntriesStoreConstant = nsarray as! Array
self.dataBanDau = filters
for i in 0..<self.dataBanDau.count {
if self.dataBanDau[i].search_key.count == 0 {
self.quickData.append(self.dataBanDau[i])
}
}
self.quickData = self.quickData.filter {
$0.type != "range"
}
DispatchQueue.main.async {
//Note: Reload TableView
self.quickFilterCollection.reloadData()
completed(true)
}
}
the class SDFilterModel:
class SDFilterModel: DSBaseModel {
var name = String()
var type = String()
var is_expanded = Int()
var search_key = String()
var filterEntries : [SDFilterModel]?
override func copy(with zone: NSZone? = nil) -> Any {
// This is the reason why `init(_ model: GameModel)`
// must be required, because `GameModel` is not `final`.
let copy = SDFilterModel(dict: self.dictionary)
if let arrAttribute = NSArray(array: self.value , copyItems: true) as? [AttributeValueModel] {
copy.value = arrAttribute
}
return copy
}
override init(dict: Dictionary<String, Any>) {
super.init(dict: dict);
value = self.valueParse()
name = dict.getString(forKey: "name")
type = dict.getString(forKey: "type")
search_key = dict.getString(forKey: "search_key")
is_expanded = dict.getInt(forKey: "is_expanded")!
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
var value: [AttributeValueModel] = [];
func valueParse()-> [AttributeValueModel] {
guard let childs = (self.dictionary["value"]) as? [Dictionary<String, AnyObject>]
else { return [] }
var output: [AttributeValueModel] = [];
for aDict in childs {
let item = AttributeValueModel(dict:aDict);
// if type == .Range && item.option_id == "0" {
// item.setRangeOptionID(aValue: item.option_name!)
// }
//
output.append(item);
}
return output;
}
Let be Assume you have let myArray = [1,2,3,4,5,6,7,8]
Now you wanted to square of each and every element in the array,
With for loop you do like this
for item in myArray {
print(item * item)
}
Now assume item = $0
With for map you jus do
myArray.map({ $0 * $0 })
Both will gave same output.
map : Use to do same operation on every element of array.
flatmap : It is used to flattern the array of array.
let myArr = [[1,2,3],[4,5,6,7]]
and you want o/p as [1,2,3,4,5,6,7]
So can get above output with myArr.flatMap({$0})
Now back to your question.
let reqArray = myModel.data.map({ $0.value }).flatMap({ $0 })
First, map gaves you array-of-array of key value but you need a single array, so for that you need to use flatmap.
You can take ref : https://medium.com/#Dougly/higher-order-functions-in-swift-sorted-map-filter-reduce-dff60b5b6adf
Create the models like this
struct Option {
let name: String
let searchKey: String
let id: String
}
struct Model {
let type: String
let name: String
let isExpanded: Bool
let value: [Option]
}
You should get the options array values and join all the arrays
let models:[Model] = //...
let collectionViewArray = models.map { $0.value }.reduce([Option](), +)
Using for loop
var collectionViewArray = [Option]()
for model in models {
collectionViewArray.append(contentsOf: model.value)
}
I have a certain model in the form of a structure:
struct ContactsModel {
let name: String
let status: String
let number: String
let onlineStatus: Bool
}
And there is a method that parses the array of names and adds them to the new collection.
var contactsDictionary = [String: [String]]()
var contactNameSectionTitles = [String]()
var names = [String]()
var contactsArray = [ContactsModel(name: "Test", status: "Test", number: "+7 999 999 99 99", onlineStatus: true)]
func configurateDictionary() {
names = contactsArray.map {$0.name}
for value in names {
let nameKey = String(value.prefix(1))
if var namePrefix = contactsDictionary[nameKey] {
namePrefix.append(value)
contactsDictionary[nameKey] = namePrefix
} else {
contactsDictionary[nameKey] = [value]
}
}
contactNameSectionTitles = [String](contactsDictionary.keys)
contactNameSectionTitles = contactNameSectionTitles.sorted(by: { $0 < $1 })
}
How do I do so in the method so that it returns not a string, but a model? I want the collection to be type
var contactsDictionary = [String: [ContactsModel]]()
There is an API to group an array to a dictionary
var contactsDictionary = [String:[ContactsModel]]()
var contactNameSectionTitles = [String]()
func configurateDictionary() {
contactsDictionary = Dictionary(grouping: contactsArray, by: { $0.prefix(1).uppercased() })
contactNameSectionTitles = contactsDictionary.keys.sorted()
}
You need Dictionary grouping by , e.x to group the array by name do
let arr = [ContactsModel]
let res = Dictionary(grouping: arr, by: { $0.name }) // [String:[ContactsModel]]
https://developer.apple.com/documentation/swift/dictionary/3127163-init
This method will return a dictionary of [String: ContactsModel]
func configurateDictionary() -> [String: ContactsModel] {
let result = contactsArray.reduce( [String: ContactsModel](), { (d, e) -> [String: ContactsModel] in
var dict = d
dict[e.name] = e
return dict
})
return result
}
If you want to change the configurateDictionary method to return [String: [ContactsModel]], create a temporary dictionary inside the function and return it at the end of the function
class ViewController: UIViewController {
var contactsDictionary = [String: [ContactsModel]]()
var contactNameSectionTitles = [String]()
var names = [String]()
var contactsArray = [ContactsModel(name: "Test", status: "Test", number: "+7 999 999 99 99", onlineStatus: true)]
override func viewDidLoad() {
super.viewDidLoad()
contactsDictionary = configurateDictionary()
}
func configurateDictionary() -> [String: [ContactsModel]] {
names.removeAll()
contactNameSectionTitles.removeAll()
var temp = [String: [ContactsModel]]()
for contact in contactsArray {
names.append(contact.name)
let nameKey = String(contact.name.prefix(1))
temp[nameKey, default: []].append(contact)
}
contactNameSectionTitles = [String](contactsDictionary.keys).sorted()
return temp
}
}
I am trying to append an object ViewingPost to an array of these objects. It works when I do what is shown here:
for (_,post) in snap {
let posst = ViewingPost()
if let totLikes = post["likes"] as? Int, let pathToImage = post["pathToImage"] as? String, let postID = post["postID"] as? String {
let postNum = "post" + postID
posst.pathToImage = pathToImage
posst.postID = postID
posst.likes = totLikes
self.posts.append(posst)
for key in 1 ... arr.count {
let isEq = arr[key - 1] == postNum
print(isEq)
if isEq {
ref.child(formattedDateD).child(postNum).observeSingleEvent(of: .value, with: { (snapsh) in
let snapshP = snapsh.value as! Int
})
}
}
}
}
Though when I move the part in which it appends the object to the array to where I want it to be, it stops working:
for (_,post) in snap {
let posst = ViewingPost()
if let totLikes = post["likes"] as? Int, let pathToImage = post["pathToImage"] as? String, let postID = post["postID"] as? String {
let postNum = "post" + postID
for key in 1 ... arr.count {
let isEq = arr[key - 1] == postNum
print(isEq)
if isEq {
ref.child(formattedDateD).child(postNum).observeSingleEvent(of: .value, with: { (snapsh) in
let snapshP = snapsh.value as! Int
posst.pathToImage = pathToImage
posst.postID = postID
posst.likes = totLikes
self.posts.append(posst)
})
}
}
}
}
Can someone please help?
I currently have my set-up as followed:
I am running a query in Firebase to extract all of the genres within an array of genres, like so:
var genresLabelIndex : [String] = ["Horror", "Fiction", "Romance"]
Then I am creating a blank arrays for each of the genres to be able to store the information of the genres within each of the areas like so:
var horrorData = [InformationForFeed]()
var fictionData = [InformationForFeed]()
var romanceData = [InformationForFeed]()
InformationForFeed looks like so:
class InformationForFeed {
fileprivate var _uploadKey:String!
fileprivate var _userKey:String!
fileprivate var _imageURL:String!
fileprivate var _socialMedia:[String]
var uploadKey:String!{
return _uploadKey
}
var userKey:String!{
return _userKey
}
var imageURL:String!{
return _imageURL
}
init(dictionary:Dictionary<String,AnyObject>, socials: [String]) {
_socialMedia = socials
if let uploadKey = dictionary["upload_key"] as? String {
self._uploadKey = uploadKey
}
if let userKey = dictionary["user_key"] as? String {
self._userKey = userKey
}
if let imageURL = dictionary["imageUrl"] as? String {
self._imageURL = imageURL
}
}
}
I am then creating an Array of the list of genres arrays like so:
1) First I am creating an empty array of arrays like this:
var genreArrayIndex : [[InformationForFeed]] = []
2) Then within my init() of the UIView I am setting what will be in the array like this:
genreArrayIndex = [self.horrorData, self.fictionData, self.romanceData]
I then will run a function called getData() that will run my query and start storing the information.
I store my information of each genre in a tempArray, and then I set the genreArrayIndex[index] to equal the tempArray and then clear the tempArray as seen in getData below.
func getData() {
for genre in genresLabelIndex {
let dbReference = Database.database().reference().child("genres").child(genre)
let query = dbReference.queryLimited(toLast: 6)
query.observeSingleEvent(of: .value, with: { (snapshot : DataSnapshot) in
if snapshot.childrenCount > 0 {
for s in snapshot.children.allObjects as! [DataSnapshot] {
let item = s.value as! Dictionary<String,AnyObject?>
let facebook = (s.childSnapshot(forPath: "social_links").value as? NSDictionary)?["facebook_link"]
let audible = (s.childSnapshot(forPath: "social_links").value as? NSDictionary)?["audible_link"]
let amazon = (s.childSnapshot(forPath: "social_links").value as? NSDictionary)?["amazon_link"]
var socialsArray = [String]()
if facebook != nil {
socialsArray.append(facebook! as! String)
} else {
socialsArray.append("nil")
}
if audible != nil {
socialsArray.append(audible! as! String)
} else {
socialsArray.append("nil")
}
if amazon != nil {
socialsArray.append(amazon! as! String)
} else {
socialsArray.append("nil")
}
let data = InformationForFeed(dictionary: item as Dictionary<String,AnyObject>, socials: socialsArray)
self.newArray.append(data)
}
}
self.genreArrayIndex[self.genreArrayIndexCount] = self.newArray
self.genreArrayIndexCount = self.genreArrayIndexCount + 1
self.newArray.removeAll()
self.internalIndex = self.internalIndex + 1
if self.internalIndex == self.genresLabelIndex.count {
self.tableView.reloadData()
}
})
}
}
My tempArray looks like this:
var newArray = [InformationForFeed]()
The index looks like this:
var genreArrayIndexCount : Int = 0
Now comes the issue....
All of the information is properly being stored in the genreArrayIndex .....but... it is not actually storing the information in the arrays that being stored in genreArrayIndex.
So in other words if you were to print(self.genreArrayIndex) it would be fully populated. But if you were to print(self.fictionData) it would be blank.
How can I resolve this?
Array is a value type. That means its contents are copies. Initializing genreArrayIndex with empty horrorData, (and others) and then filling it with getData() does not also copy the data back into horrorData. I would recommend eliminating
genreArrayIndex = [self.horrorData, self.fictionData, self.romanceData]
and replacing horrorData, fictionData, ... with computed properties. Perhaps like this.
var horrorData: [InformationFeed] {
return genreArrayIndex[0]
}