How to remove a firebase child node from a specific UICollectionViewCell - Swift - ios

I have a UICollectionView which looks like this image and have the following data structure in Firebase.
I would like for the user to be able to delete individual posts from the collection view and subsequently from firebase. I have seen on other stackoverflow posts that say I must use the .removeValue from firebase, but don't know how to get the reference to the random child in order to delete it.
How can I access the autoId value from each post e.g "LPmNrvzu-aXsw_u-rEF " so I can remove that child node from Firebase?
Here's the path I was using to load all the user's posts from Firebase:
#objc func observeUserPosts() {
let uid = Auth.auth().currentUser?.uid
let postsRef = Database.database().reference().child("posts").queryOrdered(byChild: "author/userid")
postsRef.queryEqual(toValue: uid!).observe(.value) { (snapshot) in
}
}
This is the extension where I'm loading all the UICollectionView code
//extension - UICollectionView for user's posts
extension ProfileViewController: UICollectionViewDataSource,UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return postsuser.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: PostsCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "postsCell", for: indexPath) as! PostsCollectionViewCell
cell.set(post: postsuser[indexPath.row])
cell.deletePostButton.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
cell.deletePostButton.tag = indexPath.row
return cell
}
#objc func buttonAction(sender: UIButton) {
Database.database().reference().child("posts").queryOrdered(byChild: "author/userid").observe(.value) { (snapshot) in
if let posts = snapshot.value as? [String: AnyObject] {
for (key, _) in posts {
// NOW HOW DO I REFERENCE THE CELL THAT THE USER CLICKS TO DELETE?
}
}
}
// postsuser[sender.tag]
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let vc = storyboard?.instantiateViewController(withIdentifier: "profileUsersSelectedPostViewController") as? ProfileUsersSelectedPostViewController
self.navigationController?.pushViewController(vc!, animated: true)
vc?.selectedpostsuser = postsuser[indexPath.row]
}
}

This is how I managed to solve the question I had asked.... hope it helps :)
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: PostsCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "postsCell", for: indexPath) as! PostsCollectionViewCell
cell.set(post: postsuser[indexPath.row])
cell.deletePostButton.addTarget(self, action: #selector(buttonAction(sender:)), for: .touchUpInside)
cell.deletePostButton.tag = indexPath.row
return cell
}
#objc func buttonAction(sender: UIButton) {
ProgressHUD.show("Un momento", interaction: true)
let uid = Auth.auth().currentUser?.uid
Database.database().reference().child("posts").queryOrdered(byChild: "author/userid").queryEqual(toValue: uid!).observe(.value) { (snapshot) in
if let posts = snapshot.value as? [String: AnyObject] {
if let posts = snapshot.value as? [String: AnyObject] {
for (key, postReference) in posts {
if let post = postReference as? [String: Any], let timestamp = post["timestamp"] as? TimeInterval, timestamp == self.postsuser[sender.tag].timestampDouble {
Database.database().reference().child("posts").child(key).removeValue(completionBlock: { (error, _) in
DispatchQueue.main.async {
ProgressHUD.showSuccess("Tu imagen ha sido borrada...")
self.postsuser.remove(at: sender.tag)
self.postsCollectionView.reloadData()
self.refresher.endRefreshing()
}
})
}
}
}
}
}
}

Related

Even if only other users click on the profile, only my profile is visible

Even if you click on someone else's profile, only users who are currently logged in are displayed. A few similar questions have been asked, but
I ask because the language and environment are different.
To solve the problem, the displayed ID is printed, but the printed ID is displayed as a different user. So maybe there's a problem with the profile controller, right? Or is there a problem somewhere else?
FeedCellDelegate:
protocol FeedCellDelegate: class {
func cell(_ cell: FeedCell, wantsToShowCommentsFor post: Post)
func cell(_ cell: FeedCell, didLike post: Post)
func cell(_ cell: FeedCell, wantsToShowProfileFor uid: String)
}
ProfileController:
extension ProfileController {
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return posts.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath) as! ProfileCell
cell.viewModel = PostViewModel(post: posts[indexPath.row])
return cell
}
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerIdentifier, for: indexPath) as! ProfileHeader
header.delegate = self
header.viewModel = ProfileHeaderViewModel(user: user)
return header
}
}
Feed controller:
func cell(_ cell: FeedCell, wantsToShowProfileFor uid: String) {
UserService.fetchUser(withUid: uid) { user in
print("id check \(uid)")
let controller = ProfileController(user: user)
self.navigationController?.pushViewController(controller, animated: true)
}
UserService(firebase)
static func fetchUser(withUid uid: String, completion: #escaping(User) -> Void) {
guard let uid = Auth.auth().currentUser?.uid else { return }
Collection_Users.document(uid).getDocument { snapshot, error in
guard let dictionary = snapshot?.data() else { return }
let user = User(dictionary: dictionary)
completion(user)
}
}
FeedCell:
#objc func showUserProfile() {
guard let viewModel = viewModel else { return }
print("check UID : \(viewModel.post.ownerUid)")
delegate?.cell(self, wantsToShowProfileFor: viewModel.post.ownerUid)
}
In your fetchUser function you always do:
guard let uid = Auth.auth().currentUser?.uid else { return }
Collection_Users.document(uid).getDocument { snapshot, error in
So you always get the user document for Auth.auth().currentUser?.uid, regardless of what else happened in the app.
If you wan to load the document for a different user, you'll have to pass the UID of the user that was clicked on to fetchUser and use that UID in the call to document.

Instead of deleting an array I want it to send the array to another UIViewController

I am trying to create a function that allows a user to select several videos and then select a button and it will send the selected videos to another array. I already have a similar function that handles deletions. I was really just trying to repurpose the code I already have for the deletion but everything I have tried has failed. I am a Swift newb but is there a way to do this or a better approach I should take?
var videos = [PHAsset]()
var dictionarySelectedIndexPath: [IndexPath: Bool] = [:]
#objc func didDeleteButtonClicked(_ sender: UIBarButtonItem) {
var deleteNeededIndexPaths: [IndexPath] = []
for (key, value) in dictionarySelectedIndexPath {
if value {
deleteNeededIndexPaths.append(key)
}
}
for i in deleteNeededIndexPaths.sorted(by: { $0.item > $1.item }) {
videos.remove(at: i.item)
}
collectionView.deleteItems(at: deleteNeededIndexPaths)
dictionarySelectedIndexPath.removeAll()
}
func getVideos() {
let assets = PHAsset.fetchAssets(with: PHAssetMediaType.video, options: nil)
assets.enumerateObjects({ (object, count, stop) in
self.videos.append(object)
})
self.videos.reverse()
self.collectionView.reloadData()
collectionView.delegate = self
collectionView.dataSource = self
let nib = UINib(nibName: "ItemCollectionViewCell", bundle: nil)
collectionView.register(nib, forCellWithReuseIdentifier: cellIdentifier)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "videoEditorSegueIdentifier" {
let otherVc = segue.destination as! VideoEditorVC
otherVc.videos = videos
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath) as! ItemCollectionViewCell
let asset = videos[indexPath.row]
let manager = PHImageManager.default()
if cell.tag != 0 {manager.cancelImageRequest(PHImageRequestID(cell.tag))}
cell.tag = Int(manager.requestImage(for: asset, targetSize: CGSize(width: 120.0, height: 120.0), contentMode: .aspectFill, options: nil) { (result, _) in cell.imageView?.image = result
})
return cell
}
As far as I can see, the issue you're having is because you're storing indexPath in a dictionary to remember what was selected and you're having difficulty translating that into actual data you're holding.
This would be far easier if you cut out the middle man and simply populated the array with actual selected objects in your didSelectItemAt method.
Something in the lines of:
var selectedVideos = [PHAsset]()
func videoFor(indexPath: IndexPath) -> PHAsset {
// return the video more or less the same as you do it in cellForItemAt:
}
func indexFor(video: PHAsset) -> Int? {
return selectedVideos.firstIndex(of: video)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let video = videoFor(indexPath: IndexPath)
if selectedVideos.contains(video) {
selectedVideos.remove(at: index)
} else {
selectedVideos.append(video)
}
}

How to display xib in current collection view

This is my first time working with Google AdMob native ads, I believe I followed the implementation instruction.. All that is left is actually displaying the ads within the collection view, and this is where I am stuck. I do not know how to correctly display the Ads in between users uploaded post. Basically I need help adding a xib to a collection view. task: Ads should be populating while scrolling through posts..
I am using
Collection View
Xib
Google AdMob Native advanced
I also do not receive any errors or crashes, and the console prints so I am obviously doing something wrong.. Received native ad:
The console also - print("Ads not dispalying ") and print("Not what I want")
Heres my code
import UIKit
import Firebase
class FollowingFeedViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UISearchBarDelegate, FeedCellDelegate, PeopleToFollowDelegate, GADUnifiedNativeAdLoaderDelegate {
// MARK: - Google ADMob
/// The ad unit ID from the AdMob UI.
let adUnitID = "ca-app-pub-3940256099942544/3986624511"
/// The number of native ads to load (between 1 and 5 for this example).
let numAdsToLoad = 5
/// The native ads.
var nativeAds = [GADUnifiedNativeAd]()
/// The ad loader that loads the native ads.
var adLoader: GADAdLoader!
func adLoaderDidFinishLoading(_ adLoader: GADAdLoader) {
addNativeAds()
}
func adLoader(_ adLoader: GADAdLoader, didReceive nativeAd: GADUnifiedNativeAd) {
print("Received native ad: \(nativeAd)")
// Add the native ad to the list of native ads.
nativeAds.append(nativeAd)
}
func adLoader(_ adLoader: GADAdLoader, didFailToReceiveAdWithError error: GADRequestError) {
print("\(adLoader) failed with error: \(error.localizedDescription)")
}
/// Add native ads to the list.
func addNativeAds() {
if nativeAds.count <= 0 {
print("Ads not dispalying ")
return
}
let adInterval = (posts.count / nativeAds.count) + 1
var index = 0
for nativeAd in nativeAds {
if index < collectionObject.count {
collectionObject.insert(nativeAd, at: index)
index += adInterval
} else {
print("Not what I want")
break
}
}
}
// MARK: - Properties
var posts = [Post]()
var collectionObject = [AnyObject]()
var viewSinglePost = false
var post: Post?
var currentKey: String?
var userProfileController: ProfileViewController?
var header: FeedReusableView?
#IBOutlet weak var collectionView: UICollectionView!
// MARK: - UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if posts.count > 4 {
if indexPath.item == posts.count - 1 {
fetchPosts()
}
}
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return posts.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PostsCell", for: indexPath) as? FollowingCell {
cell.delegate = self
cell.post = posts[indexPath.item] as Post
handleUsernameLabelTapped(forCell: cell)
handleMentionTapped(forCell: cell)
handleHashtagTapped(forCell: cell)
return cell
} else {
let nativeAd = collectionObject[indexPath.row] as! GADUnifiedNativeAd
nativeAd.rootViewController = self
let nativeAdCell = collectionView.dequeueReusableCell(withReuseIdentifier: "UnifiedNativeAdCell", for: indexPath)
// Get the ad view from the Cell. The view hierarchy for this cell is defined in
let adView : GADUnifiedNativeAdView = nativeAdCell.contentView.subviews
.first as! GADUnifiedNativeAdView
// Associate the ad view with the ad object.
// This is required to make the ad clickable.
adView.nativeAd = nativeAd
adView.mediaView?.mediaContent = nativeAd.mediaContent
// Populate the ad view with the ad assets.
(adView.headlineView as! UILabel).text = nativeAd.headline
(adView.advertiserView as! UILabel).text = nativeAd.advertiser
(adView.bodyView as! UILabel).text = nativeAd.body
adView.bodyView?.isHidden = nativeAd.body == nil
(adView.iconView as? UIImageView)?.image = nativeAd.icon?.image
adView.iconView?.isHidden = nativeAd.icon == nil
// In order for the SDK to process touch events properly, user interaction
// should be disabled.
adView.callToActionView?.isUserInteractionEnabled = false
return nativeAdCell
}
}
// MARK: - ViewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
// // Google Admob
let options = GADMultipleAdsAdLoaderOptions()
options.numberOfAds = numAdsToLoad
// Prepare the ad loader and start loading ads.
adLoader = GADAdLoader(adUnitID: adUnitID,
rootViewController: self,
adTypes: [.unifiedNative],
options: [options])
collectionView.dataSource = self
collectionView.delegate = self
adLoader.delegate = self
adLoader.load(GADRequest())
self.collectionView.register(UINib(nibName: "NativeAdCell", bundle: nil), forCellWithReuseIdentifier: "UnifiedNativeAdCell")
addNativeAds()
}
#objc func handleRefresh() {
posts.removeAll(keepingCapacity: false)
self.currentKey = nil
fetchPosts()
collectionView?.reloadData()
header?.profilesCollectionView.reloadData()
}
}
Fetch Post
func fetchPosts() {
guard let currentUid = Auth.auth().currentUser?.uid else { return }
if currentKey == nil {
USER_FEED_REF.child(currentUid).queryLimited(toLast: 5).observeSingleEvent(of: .value, with: { (snapshot) in
self.collectionView?.refreshControl?.endRefreshing()
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 postId = snapshot.key
self.fetchPost(withPostId: postId)
})
self.currentKey = first.key
})
} else {
USER_FEED_REF.child(currentUid).queryOrderedByKey().queryEnding(atValue: self.currentKey).queryLimited(toLast: 6).observeSingleEvent(of: .value, with: { (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 postId = snapshot.key
if postId != self.currentKey {
self.fetchPost(withPostId: postId)
}
})
self.currentKey = first.key
})
}
}
func fetchPost(withPostId postId: String) {
Database.fetchPost(with: postId) { (post) in
self.posts.append(post)
self.posts.sort(by: { (post1, post2) -> Bool in
return post1.creationDate > post2.creationDate
})
self.collectionView?.reloadData()
}
}
}
I think this will work, you have two data source as I can see from your code
var posts = [Post]()
var collectionObject = [AnyObject]()
and you want to create cell for all of them but the only data source you are going to show is posts based on your code
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return posts.count
}
this can be solved by changing your code to something like this
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if (section == 0) {
return posts.count
} else {
return collectionObject.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if (indexPath.section == 0) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PostsCell", for: indexPath) as FollowingCell
cell.delegate = self
cell.post = posts[indexPath.item] as Post
handleUsernameLabelTapped(forCell: cell)
handleMentionTapped(forCell: cell)
handleHashtagTapped(forCell: cell)
return cell
} else {
let nativeAd = collectionObject[indexPath.row] as! GADUnifiedNativeAd
nativeAd.rootViewController = self
let nativeAdCell = collectionView.dequeueReusableCell(withReuseIdentifier: "UnifiedNativeAdCell", for: indexPath)
// Get the ad view from the Cell. The view hierarchy for this cell is defined in
let adView : GADUnifiedNativeAdView = nativeAdCell.contentView.subviews
.first as! GADUnifiedNativeAdView
// Associate the ad view with the ad object.
// This is required to make the ad clickable.
adView.nativeAd = nativeAd
adView.mediaView?.mediaContent = nativeAd.mediaContent
// Populate the ad view with the ad assets.
(adView.headlineView as! UILabel).text = nativeAd.headline
(adView.advertiserView as! UILabel).text = nativeAd.advertiser
(adView.bodyView as! UILabel).text = nativeAd.body
adView.bodyView?.isHidden = nativeAd.body == nil
(adView.iconView as? UIImageView)?.image = nativeAd.icon?.image
adView.iconView?.isHidden = nativeAd.icon == nil
// In order for the SDK to process touch events properly, user interaction
// should be disabled.
adView.callToActionView?.isUserInteractionEnabled = false
return nativeAdCell
}
}
This code first add posts and then start adding your adds.
Check this and let me know if it's worked or not. If this show the cell then you can mix two data source together and populate your collection view cells with condition like if you create new object that math this condition with your current object posts & collectionObject
if indexPath.item % 4 == 0 {
show adds
} else {
show posts
}
Hope this will help
Your FollowingFeedViewController is not a subclass from UICollectionViewController, right? Because of that, you should set the delegate and dataSource properties of your collectionView instance.
Probably something like this:
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
}
It looks like at least some of your code is missing. I can't see a fetchPosts method.
I note that handleRefresh calls fetchPosts just before reloadData. Does fetchPosts load the data synchronously or asynchronously? If it loads the data asynchronously, reloadData will be called before the data is ready.
Similarly for the ads. I can't see any reloadData (or equivalent) calls to the collection view once the ads are ready. If you post your full code it'll be easier to diagnose the problem.

How to use the button inside CollcetionViewCell to delete cell itself

My app use flickr Api to search photo and present by collectionView.
Also I want to add the photo that i want to favorite.
So I add the button on cell and use Coredata to save image and photo title.
#IBAction func saveBtn(_ sender: UIButton) {
checkFavorite(photoTitle: photoArrayFromSearchView[sender.tag].title)
if isAdded == false {
save(btnTag: sender.tag)
}
}
func save(btnTag:Int){
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let favoritePhotos = FavoritePhotos(context: context)
downloadFavoriteData(btnTag: btnTag, favoritePhotos: favoritePhotos) { (dataDownloaded) in
if dataDownloaded {
do {
try context.save()
print("save successfully")
} catch {
print("fail to save")
}
}
}
}
I cant find the way to press button to save relative photo so i use button.tag = cell.item to achieve.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellID, for: indexPath) as! ResultCollectionViewCell
cell.BtnView.tag = indexPath.item
cell.photoTitle.text = photoArrayFromSearchView[indexPath.row].title
cell.photoImg.af_setImage(withURL: photoArrayFromSearchView[indexPath.row].photoURL)
return cell }
It works but here is the problem.
I cant use the same way by button.tag to delete item.
When the item has been delete, somehow my button.tag won't reload.
And it crash. Error: Index out of range.
Because button.tag didn't reload but collectionView index is already change.
#IBAction func deleteBtn(_ sender: UIButton) {
let Index = IndexPath(row: sender.tag, section: 0)
deleteItem(btnTag: sender.tag)
fetch()
favoritePhotoCollection.deleteItems(at: [Index])
}
func deleteItem(btnTag:Int){
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
context.delete(favoriteArray[btnTag])
do {
try context.save()
} catch {
print("delete fail")
}
}
func fetch(){
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let fetchRequset = NSFetchRequest<FavoritePhotos>(entityName: "FavoritePhotos")
fetchRequset.returnsObjectsAsFaults = false
do {
favoriteArray = try context.fetch(fetchRequset)
} catch {
print("fail to fetch")
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return favoriteArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellID, for: indexPath) as!
FavoriteCollectionViewCell
cell.BtnView.tag = indexPath.item
cell.photoTitle.text = favoriteArray[indexPath.row].photoTitle
if let data = favoriteArray[indexPath.row].photoImg as Data? {
cell.photoImg.image = UIImage(data: data)
}else {
cell.photoImg.image = nil
}
return cell
}
Can someone tell me how to fix this problem?
Or the better way to achieve using button inside CollcetionViewCell to delete or save data.
thx your patience to read.
It will not work because as collection view recycle. So that tag wouldn't be the same. What you can do is assigning something which is unique like you can use save title as a tag and try to save and extract using that tag.
The problem is the fetch line. Remove the item from CoreData and from the data source array but don't refetch the data.
#IBAction func deleteBtn(_ sender: UIButton) {
let indexPath = IndexPath(row: sender.tag, section: 0)
photoArrayFromSearchView.remove(at: indexPath.row)
deleteItem(btnTag: sender.tag)
favoritePhotoCollection.deleteItems(at: [indexPath])
}
There is another inconsistency: There are two different arrays favoriteArray and photoArrayFromSearchView
Instead of the button.tag, you could make a delete action delegate protocol(that has deleteCell func). Your view controller should conform the protocol and assign self to the cells. Then view controller can figure out the item's indexPath by "collectionView.indexPath(for :UICollectionViewCell)" and then delete the cell in the implementation of deleteCell func.

Reload Collection View in a Collection View Cell through delegation

I have a controller (A) with a Collection View that features 2 cell classes. One of them (B) contains another Collection View. After doing some research, I still cannot figure out how to update the cells in (B) from (A) or elsewhere to get what I want.
Issues
(B) does not reload properly when its button is pressed: the cell with whom the button was tied is still visible even though it is deleted from the userFriendRequests array in (A) in its delegate method. As a bonus I get a crash when I scroll to a new cell in (B) stating that "index is out of range" on the line cell.user = userFriendRequests[indexPath.row].
What I Have
Controller (A)
protocol UserFriendRequestsDelegate: class {
func didPressConfirmFriendButton(_ friendId: String?)
}
/...
fileprivate var userFriendRequests = [User]()
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if userFriendRequests.isEmpty == false {
switch indexPath.section {
case 0:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: friendRequestCellId, for: indexPath) as! UserFriendRequests
cell.userFriendRequests = userFriendRequests
cell.delegate = self
return cell
case 1:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! UserFriendCell
let user = users[indexPath.row]
cell.user = user
return cell
default:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! UserFriendCell
return cell
}
}
/...
extension AddFriendsController: UserFriendRequestsDelegate {
internal func didPressConfirmFriendButton(_ friendId: String?) {
guard let uid = FIRAuth.auth()?.currentUser?.uid, let friendId = friendId else {
return
}
let userRef = FIRDatabase.database().reference().child("users_friends").child(uid).child(friendId)
let friendRef = FIRDatabase.database().reference().child("users_friends").child(friendId).child(uid)
let value = ["status": "friend"]
userRef.updateChildValues(value) { (error, ref) in
if error != nil {
return
}
friendRef.updateChildValues(value, withCompletionBlock: { (error, ref) in
if error != nil {
return
}
self.setUpRequestsStatusesToConfirmed(uid, friendId: friendId)
DispatchQueue.main.async(execute: {
let index = self.currentUserFriendRequests.index(of: friendId)
self.currentUserFriendRequests.remove(at: index!)
for user in self.userFriendRequests {
if user.id == friendId {
self.userFriendRequests.remove(at: self.userFriendRequests.index(of: user)!)
}
}
self.attemptReloadOfCollectionView()
})
})
}
}
PS: self.attemptReloadOfCollectionView() is a func that simply invalidates a timer, sets it to 0.1 sec and then calls reloadData() on (A)'s Collection View.
CollectionViewCell (B)
weak var delegate: UserFriendRequestsDelegate?
var userFriendRequests = [User]()
/...
#objc fileprivate func confirmFriendButtonPressed(_ sender: UIButton) {
delegate?.didPressConfirmFriendButton(friendId)
}
/...
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return userFriendRequests.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: friendRequestCellId, for: indexPath) as! FriendRequestCell
cell.user = userFriendRequests[indexPath.row]
return cell
}
/...
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
guard let firstName = userFriendRequests[indexPath.row].first_name, let lastName = userFriendRequests[indexPath.row].last_name, let id = userFriendRequests[indexPath.row].id else {
return
}
nameLabel.text = firstName + " " + lastName
friendId = id
confirmButton.addTarget(self, action: #selector(confirmFriendButtonPressed(_:)), for: .touchUpInside)
}
What I want to achieve
Update (B) when a User is removed from the userFriendRequests array in (A), this User being identified by his id passed by (B) through delegation.
Any good soul that might have an idea on how to tackle this issue ?
Thanks in advance for your help !

Resources