Swift UIActivityViewController only showing one item when exporting as text - swift

I'm trying to allow the user to export a list of items to notes but for some reason, it's only exporting the first item and not the entire list like I would hope it was going to. This is my attempt at doing this...
guard let listId = list?.id else { return }
let ref = Database.database().reference().child("lists").child(listId).child("list-items")
ref.observe(.value) { (snapshot) in
guard let dict = snapshot.value as? [String: Any] else { return }
dict.forEach({ (key, value) in
let itemRef = Database.database().reference().child("items").child(key)
itemRef.observeSingleEvent(of: .value, with: { (snapshot) in
guard let dictionary = snapshot.value as? [String: Any] else { return }
guard let itemName = dictionary["item"] as? String else { return }
let activityController = UIActivityViewController(activityItems: [itemName], applicationActivities: nil)
self.present(activityController, animated: true, completion: nil)
})
})
}

Related

Pagination not working in Swift with Firebase

I am trying to paginate my data pull. But somehow it is not working and I am not sure what I am doing wrong.
In my viewDidLoad I call this function:
var currentKey: String?
func fetchNotifications() {
guard let currentUid = Auth.auth().currentUser?.uid else { return }
if currentKey == nil {
//initial data pull
NOTIFICATIONS_REF.child(currentUid).queryLimited(toLast: 16).observeSingleEvent(of: .value) { (snapshot) in
guard let first = snapshot.children.allObjects.first as? DataSnapshot else { return }
guard let allObjects = snapshot.children.allObjects as? [DataSnapshot] else { return }
allObjects.forEach({ (snapshot) in
let notificationId = snapshot.key
guard let dictionary = snapshot.value as? Dictionary<String, AnyObject> else { return }
guard let uid = dictionary["uid"] as? String else { return }
Database.fetchUser(with: uid, completion: { (user) in
// if notification is for post
if let postId = dictionary["postId"] as? String {
Database.fetchPost(with: postId, completion: { (post) in
let notification = Notification(user: user, post: post, dictionary: dictionary)
if notification.notificationType == .Comment {
self.getCommentData(forNotification: notification)
}
self.notifications.append(notification)
self.notifications.sort { (notification1, notification2) in
return notification1.creationDate > notification2.creationDate
}
self.tableView.reloadData()
})
} else {
let notification = Notification(user: user, dictionary: dictionary)
self.notifications.append(notification)
self.notifications.sort { (notification1, notification2) in
return notification1.creationDate > notification2.creationDate
}
self.tableView.reloadData()
self.tableView.refreshControl?.endRefreshing()
}
})
})
self.tableView.refreshControl?.endRefreshing()
}
} else {
NOTIFICATIONS_REF.child(currentUid).queryOrderedByKey().queryEnding(atValue: self.currentKey).queryLimited(toLast: 3).observeSingleEvent(of: .value) { (snapshot) in
guard let first = snapshot.children.allObjects.first as? DataSnapshot else { return }
guard let allObjects = snapshot.children.allObjects as? [DataSnapshot] else { return }
allObjects.forEach({ (snapshot) in
let notificationId = snapshot.key
guard let dictionary = snapshot.value as? Dictionary<String, AnyObject> else { return }
guard let uid = dictionary["uid"] as? String else { return }
Database.fetchUser(with: uid, completion: { (user) in
if notificationId != self.currentKey {
// if notification is for post
if let postId = dictionary["postId"] as? String {
Database.fetchPost(with: postId, completion: { (post) in
let notification = Notification(user: user, post: post, dictionary: dictionary)
if notification.notificationType == .Comment {
self.getCommentData(forNotification: notification)
}
self.notifications.append(notification)
self.notifications.sort { (notification1, notification2) in
return notification1.creationDate > notification2.creationDate
}
self.tableView.reloadData()
})
} else {
let notification = Notification(user: user, dictionary: dictionary)
self.notifications.append(notification)
self.notifications.sort { (notification1, notification2) in
return notification1.creationDate > notification2.creationDate
}
self.tableView.reloadData()
self.tableView.refreshControl?.endRefreshing()
}
}
})
})
}
}
}
I am populating the currentKey so it is no longer nil. The idea is that the else-statement then comes into place. But the else-statement is not being called .. I was also printing the currentKey after the initial data pull, so I know it is being populated, but still the else does not come into action.

Google maps API Swift; Nil maneuver response

I am trying to get the maneuver data for the given route from Google Maps' API. Running the code gives me nil values.
Here is the code I am running to get the maneuver data:
func getRouteSteps(source: CLLocationCoordinate2D,destination: CLLocationCoordinate2D) {
let session = URLSession.shared
let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(source.latitude),\(source.longitude)&destination=\(destination.latitude),\(destination.longitude)&sensor=false&mode=driving&key=\(APIKey)")!
let task = session.dataTask(with: url, completionHandler: {
(data, response, error) in
guard error == nil else {
print(error!.localizedDescription)
return
}
guard let jsonResult = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any] else {
print("error in JSONSerialization")
return
}
guard let routes = jsonResult["routes"] as? [Any] else { return }
guard let route = routes[0] as? [String: Any] else { return }
guard let legs = route["legs"] as? [Any] else { return }
guard let leg = legs[0] as? [String: Any] else { return }
guard let steps = leg["steps"] as? [Any] else { return }
guard let duration = leg["duration"] as? [String: Any] else { return }
guard let distance = leg["distance"] as? [String: Any] else { return }
RouteData.append(RouteInfo(Time: String(describing: duration["text"]! as Any), Distance: String(describing: distance["text"]! as Any)))
for item in steps {
guard let step = item as? [String: Any] else { return }
guard let stepTurns = step["html_instructions"] as? String else { return }
guard let stepDistance = step["distance"] as? [String: Any] else { return }
guard let stepTime = step["duration"] as? [String: Any] else { return }
guard let polyline = step["polyline"] as? [String: Any] else { return }
guard let polyLineString = polyline["points"] as? String else { return }
guard let maneuver = step["maneuver"] as? Any else { return }
print(maneuver)
Here are the results:
nil
nil
Optional(turn-right)
Optional(turn-left)
Optional(ramp-left)
Optional(ramp-right)
Optional(straight)
Optional(turn-slight-left)
Optional(turn-slight-left)
Optional(turn-left)

Swift - Remove key and values from dictionary [String : Any]

I am trying to removed block users from a dictionary [String : Any] that I am grabbing from the database. At first I grab the list of UID's that the current user has blocked:
var updatedBlockList: Any?
func findBlockUsers() {
// find current users list of blocked users
guard let currentUserUid = Auth.auth().currentUser?.uid else { return }
let blockedUsers = Database.database().reference().child("users").child(currentUserUid)
blockedUsers.observeSingleEvent(of: .value, with: { (snapshot) in
guard let userIdsDictionary = snapshot.value as? [String: Any] else { return }
userIdsDictionary.forEach({ (key, value) in
guard let userDictionary = value as? [String: Any] else { return }
var blockedList : Any
blockedList = userDictionary.keys
print(blockedList)
self.updateBlockList(blockedList: blockedList)
})
})
}
func updateBlockList(blockedList: Any) {
updatedBlockList = blockedList
print(updatedBlockList)
}
If I print updatedBlockList I get: ["gdqzOXPWaiaTn93YMJBEv51UUUn1", "RPwVj59w8pRFLf55VZ6LGX6G2ek2", "xmigo8CPzhNLlXN4oTHMpGo7f213"]
I now want to take those UID's (which will be the key in UserIdsDictionary and remove them after I pull ALL the users:
fileprivate func fetchAllUserIds() {
let ref = Database.database().reference().child("users")
ref.observeSingleEvent(of: .value, with: { (snapshot) in
guard let userIdsDictionary = snapshot.value as? [String: Any] else { return }
userIdsDictionary.forEach({ (key, value) in
// attempting to remove the blocked users here without any luck
var updatedKey = key as String?
updatedKey?.remove(at: self.updatedBlockList as! String.Index)
print(updatedKey!)
guard let userDictionary = value as? [String: Any] else { return }
let user = User(uid: key, dictionary: userDictionary)
self.fetchPostsWithUser(user: user)
})
}) { (err) in
print("Failed to fetch following user ids:", err)
}
}
I get this error when trying to remove: Could not cast value of type 'Swift.Dictionary.Keys' (0x1de2f6b78) to 'Swift.String.Index'
I'm sure i'm going about this the wrong way, but I know i'm close. The end goal is to take the blocked users UID's and remove them from the dictionary. Any help would be very much appreciated!!
Your forEach loop on userIdsDictionary is the wrong approach here so rather than trying to fix that code I would use a different approach and loop over the updatedBlockList
for item in updatedBlockList {
if let userID = item as? String {
userIdsDictionary.removeValue(forKey: userID)
}
}
For anyone wondering, here is the final changes that were made to make it work.
var updatedBlockList = [String]()
func findBlockUsers() {
// find current users list of blocked users
guard let currentUserUid = Auth.auth().currentUser?.uid else { return }
let blockedUsers = Database.database().reference().child("users").child(currentUserUid)
blockedUsers.observeSingleEvent(of: .value, with: { (snapshot) in
guard let userIdsDictionary = snapshot.value as? [String: Any] else { return }
userIdsDictionary.forEach({ (key, value) in
guard let userDictionary = value as? [String: Any] else { return }
let blockedList = Array(userDictionary.keys)
print(blockedList)
self.updateBlockList(blockedList: blockedList)
})
})
}
func updateBlockList(blockedList: [String]) {
updatedBlockList = blockedList
print(updatedBlockList)
}
fileprivate func fetchAllUserIds() {
let ref = Database.database().reference().child("users")
ref.observeSingleEvent(of: .value, with: { [weak self] (snapshot) in
guard var userIdsDictionary = snapshot.value as? [String: Any], let self = self else { return }
for item in self.updatedBlockList {
userIdsDictionary.removeValue(forKey: item)
}
userIdsDictionary.forEach({ (key, value) in
guard let userDictionary = value as? [String: Any] else { return }
let user = User(uid: key, dictionary: userDictionary)
self.fetchPostsWithUser(user: user)
})
}) { (err) in
print("Failed to fetch following user ids:", err)
}
}

I cant see values from firebase swift

Screen Shot 2019-04-01 at 4.45.08 PMenter image description hereI want to get the value from firebase that is stored I want to print it into a text label,
func fetchData(){
var ref: DatabaseReference!
ref = Database.database().reference()
guard let currentUid = Auth.auth().currentUser?.uid else {return}
Database.database().reference().child("users").child(currentUid).observeSingleEvent(of: .value, with: { (snapshot) in
guard let dictionary = snapshot.value as? Dictionary<String , AnyObject> else {return}
let uid = snapshot.value
let user = User(uid:uid as! String, dictionary: dictionary)
self.user = user
}) { (error) in
print(error.localizedDescription)
}
}
This is my another code to set the text label
func fetchData(){
var ref: DatabaseReference!
ref = Database.database().reference()
guard let currentUid = Auth.auth().currentUser?.uid else {return}
Database.database().reference().child("users").child(currentUid).observeSingleEvent(of: .value, with: { (snapshot) in
guard let dictionary = snapshot.value as? Dictionary<String , AnyObject> else {return}
let uid = snapshot.value
let user = User(uid:uid as! String, dictionary: dictionary)
self.userNameLabel.text = user.username
self.user = user
print(snapshot)
}) { (error) in
print(error.localizedDescription)
}
}
extra code to understand what I am doing
// user info stored
let userID = Auth.auth().currentUser?.uid
let userData = ["userName": userName,
"userAge ": userAge] as [String? : Any]
let values = [userID: userData]
let ref = Database.database().reference()
ref.child("users").childByAutoId().setValue(values)
}
I think you should use callbacks to communicate asynchronously with your controller.
In your example you get the uid by using "snpashot.value" but you should take the key of your dictionary instead.
Here is a similar example :
///Function that returns as callback the user stored in Firebase with a certain id.
func getUserFor(id: String, callback: #escaping (Bool, User?) -> Void) {
//Get the user in Firebase "user" collection with the specific id.
ref.child(Constants.userKey).child(id).observeSingleEvent(of: .value, with: { (userSnapshot) in
guard let userDictionnary = userSnapshot.value as? [String:Any] else { return callback(false, nil) }
let userId = userSnapshot.key
let userEmail = userDictionnary[Constants.emailKey] as? String
let user = User(id: userId, email: userEmail)
return callback(true, user)
}) { (error) in
print(error.localizedDescription)
return callback(false, nil)
}
}
I have found the answer I wasn't setting the user stored info in the firebase the right way.
let userID = Auth.auth().currentUser?.uid
let userData = ["userName": userName,
"userAge ": userAge] as [String? : Any]
let ref = Database.database().reference()
ref.child("users/\(userID ?? "")").setValue(userData)
}
//ref.child("users/(userID??"")").setValue(userData) // this was the error

How to stop observe

I have this code for retrieving data from Firebase database. The code works fine, but it retrieves the same data multiple times.
How do I stop observe so that the data will only be called once
My code
self.eventGalleryImage.child("event")
.child(self.eventName.text!)
.child("EventImages")
.observeSingleEvent(of: .value, with: { (snapshot) in
if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] {
for child in snapshots {
if let dict = child.value as? Dictionary<String, Any> {
if let userGallery = dict["Text"] as? String {
self.postsFindGallery.insert(galleryStruct(gallery: userGallery), at: 0)
self.collectionView.reloadData()
}
}
}
}
})
A lesson to be learnt. Do all you can to avoid using for loops when observing data. This is what you'll need to do to get all of the data inside that database path ONCE:
self.eventGalleryImage.child("event")
.child(self.eventName.text!)
.child("EventImages")
.observe(.childAdded, with: { (snapshot) in
guard let dictionary = snapshot.value as? [String: AnyObject] else { return }
if let userGallery = dictionary["Text"] as? String {
self.postsFindGallery.insert(galleryStruct(gallery: userGallery), at: 0)
self.collectionView.reloadData()
}
}, withCancel: nil)
You may also want to try:
DispatchQueue.main.async {
self.collectionView.reloadData()
}