Swift Firebase UICollectionView refresh causing duplicate thumbnails - swift

I have been trying to find a answer for this problem but no luck. When I use my refreshcontrol my UICollectionView Cells start repeating/duplicating cells. The thumbnails start switching around whenever I start refreshing the UICollectionView.
import UIKit
class CollectionViewCell: UICollectionViewCell {
#IBOutlet weak var postImage: UIImageView!
override func prepareForReuse() {
self.postImage.image = nil
super.prepareForReuse()
}
}
I've already added the prepareForReuse for the UICollectionViewCell but no luck.
import UIKit
import Firebase
import SVProgressHUD
import SDWebImage
import SwiftyJSON
import CoreLocation
class CollectionView: UICollectionViewController, UICollectionViewDelegateFlowLayout, CLLocationManagerDelegate {
#IBOutlet var collectionViews: UICollectionView!
var posts = [Post]()
var uid: String?
let user = Auth.auth().currentUser?.uid
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
locationManager.delegate = self
locationManager.distanceFilter = kCLLocationAccuracyNearestTenMeters
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
locationManager.stopUpdatingLocation()
collectionViews.dataSource = self
collectionViews.delegate = self
if CLLocationManager.locationServicesEnabled() {
switch(CLLocationManager.authorizationStatus()) {
case .notDetermined, .restricted, .denied:
print("No access")
downloadImagesWithoutLocation(refreshing: false, refreshControl: nil)
case .authorizedAlways, .authorizedWhenInUse:
print("Access")
downloadImages(refreshing: false, refreshControl: nil)
}
} else {
print("Location services are not enabled")
}
// refresh control
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(refreshControlAction(refreshControl:)), for: UIControlEvents.valueChanged)
self.collectionViews.insertSubview(refreshControl, at: 0)
}
#objc func refreshControlAction(refreshControl: UIRefreshControl) {
if CLLocationManager.locationServicesEnabled() {
switch(CLLocationManager.authorizationStatus()) {
case .notDetermined, .restricted, .denied:
print("No access")
downloadImagesWithoutLocation(refreshing: true, refreshControl: refreshControl)
case .authorizedAlways, .authorizedWhenInUse:
print("Access")
downloadImages(refreshing: true, refreshControl: refreshControl)
}
} else {
print("Location services are not enabled")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func downloadImagesWithoutLocation(refreshing: Bool, refreshControl: UIRefreshControl?) {
let ref = Database.database().reference().child("posts")
MBProgressHUD.showAdded(to: self.view, animated: true)
ref.queryOrdered(byChild: "businessName").observe(.childAdded, with: { snapshot in
if let dict = snapshot.value as? NSDictionary {
self.posts = []
for item in dict {
let json = JSON(item.value)
let uid = json["uid"].stringValue
var name: String = json["businessName"].stringValue
let address: String = json["businessStreet"].stringValue
let state: String = json["businessCity"].stringValue
let caption: String = json["caption"].stringValue
let downloadURL: String = json["download_url"].stringValue
let timestamp = json["timestamp"].doubleValue
let date = Date(timeIntervalSince1970: timestamp/1000)
let postID: String = json["postID"].stringValue
//let lat = json["businessLatitude"].doubleValue
//let long = json["businessLongitude"].doubleValue
//let businessLocation = CLLocation(latitude: lat, longitude: long)
//let latitude = self.locationManager.location?.coordinate.latitude
//let longitude = self.locationManager.location?.coordinate.longitude
//let userLocation = CLLocation(latitude: latitude!, longitude: longitude!)
//let distanceInMeters: Double = userLocation.distance(from: businessLocation)
//let distanceInMiles: Double = distanceInMeters * 0.00062137
//let distanceLabelText = String(format: "%.2f miles away", distanceInMiles)
let distanceLabelText = "Not Available"
let usersReference = Database.database().reference(withPath: "users").queryOrderedByKey().queryEqual(toValue: uid)
usersReference.observeSingleEvent(of: .value, with: { snapshot in
if let dict = snapshot.value as? NSDictionary {
let userInfo = dict.allValues[0]
let userJSON = JSON(userInfo)
name = userJSON["name"].stringValue
}
let post = Post(uid: uid, caption: caption, downloadURL: downloadURL, name: name, date: date, address: address, state: state, distance: distanceLabelText, postID: postID)
self.posts.append(post)
//self.posts.sort {$0.distance.compare($1.distance) == .orderedAscending}
self.posts.sort {$0.date.compare($1.date) == .orderedAscending}
self.collectionViews.reloadData()
})
}
}
if refreshing {
refreshControl?.endRefreshing()
}
MBProgressHUD.hide(for: self.view, animated: true)
})
}
func downloadImages(refreshing: Bool, refreshControl: UIRefreshControl?) {
let ref = Database.database().reference().child("posts")
MBProgressHUD.showAdded(to: self.view, animated: true)
ref.queryOrdered(byChild: "businessName").observe(.childAdded, with: { snapshot in
if let dict = snapshot.value as? NSDictionary {
self.posts = []
for item in dict {
let json = JSON(item.value)
let uid = json["uid"].stringValue
var name: String = json["businessName"].stringValue
let address: String = json["businessStreet"].stringValue
let state: String = json["businessCity"].stringValue
let caption: String = json["caption"].stringValue
let downloadURL: String = json["download_url"].stringValue
let timestamp = json["timestamp"].doubleValue
let date = Date(timeIntervalSince1970: timestamp/1000)
let postID: String = json["postID"].stringValue
let lat = json["businessLatitude"].doubleValue
let long = json["businessLongitude"].doubleValue
let businessLocation = CLLocation(latitude: lat, longitude: long)
let latitude = self.locationManager.location?.coordinate.latitude
let longitude = self.locationManager.location?.coordinate.longitude
let userLocation = CLLocation(latitude: latitude!, longitude: longitude!)
let distanceInMeters: Double = userLocation.distance(from: businessLocation)
let distanceInMiles: Double = distanceInMeters * 0.00062137
let distanceLabelText = String(format: "%.2f miles away", distanceInMiles)
//let distanceLabelText = "Not Available"
let usersReference = Database.database().reference(withPath: "users").queryOrderedByKey().queryEqual(toValue: uid)
usersReference.observeSingleEvent(of: .value, with: { snapshot in
if let dict = snapshot.value as? NSDictionary {
let userInfo = dict.allValues[0]
let userJSON = JSON(userInfo)
name = userJSON["name"].stringValue
}
let post = Post(uid: uid, caption: caption, downloadURL: downloadURL, name: name, date: date, address: address, state: state, distance: distanceLabelText, postID: postID)
self.posts.append(post)
self.posts.sort {$0.distance.compare($1.distance) == .orderedAscending}
self.collectionViews.reloadData()
})
}
}
if refreshing {
refreshControl?.endRefreshing()
}
MBProgressHUD.hide(for: self.view, animated: true)
})
}
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: "Cell", for: indexPath) as! CollectionViewCell
cell.postImage.image = nil
if self.posts[indexPath.row].downloadURL != nil {
cell.postImage.downloadImagezzz(from: self.posts[indexPath.row].downloadURL)
} else {
print("\n \(indexPath.row) could not return a value for pathToImage256 from Post. \n")
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 2
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.size.width / 3 - 1, height: collectionView.frame.size.width / 3 - 1)
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "PostSegue", sender: indexPath)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "PostSegue") {
let selectedCell = sender as! NSIndexPath
let selectedRow = selectedCell.row
let imagePage = segue.destination as! CollectionViewFeed
let user = self.posts[selectedRow].uid
imagePage.seguePostID = self.posts[selectedRow].downloadURL
imagePage.otherUser = user
print(self.posts[selectedRow].downloadURL)
} else {
print("\n Segue with identifier (imagePage) not found. \n")
}
}
}
extension UIImageView {
func downloadImagezzz(from imgURL: String) {
let url = URLRequest(url: URL(string: imgURL)!)
let task = URLSession.shared.dataTask(with: url) {
(data, responds, error) in
if error != nil {
print(error!)
return
}
DispatchQueue.main.async {
self.image = UIImage(data: data!)
}
}
task.resume()
}
}
Heres my whole view controller that loads the UICollectionView.
Below are the images of whats happening.

In your cellForItemAt method add this before you start the task to download the new image and it will work.
cell.postImage.image = nil
cell.postImage.sd_cancelCurrentImageLoad()

Related

How to dynamically update my gallery data

Hello Respected Comrades,
I made a gallery app. initially I get a data of media from phone.
but when i add some new photos to device. i cant see them until :
re install app
fetching in view will appear (this is just a temperory fix)
I want to update my data dynamically with respect to phone data
code:
import UIKit
import Foundation
import Photos
import CoreData
enum MediaType{
case video, photo
}
View model
class GalleryPageViewModel : BaseViewModel{
var mediaArray = Spectator<MediaArray?>(value:
[])
var title = "Gallery"
var appDelegate:AppDelegate?
var context : NSManagedObjectContext?
let responder : AppResponder
var tempMedia = [MediaModel]()
init(with responder:AppResponder){
self.responder = responder
super.init()
}
}
extension GalleryPageViewModel{
func populatePhotos(){
mediaArray.value = []
tempMedia = []
PHPhotoLibrary.requestAuthorization{ [weak self] status in
if status == .authorized{
let assets = PHAsset.fetchAssets(with: nil)
assets.enumerateObjects{ (object,_,_) in
var image = UIImage()
image = self!.conversionPhotoToImage(asset: object)
var mediaType : MediaType = .photo
if object.mediaType == .video{
mediaType = .video
}
let media = MediaModel(img: image, asset: object, mediaType: mediaType)
self?.tempMedia.append(media)
}
}
else{
print("auth failed")
}
self?.setUpData()
}
}
func conversionPhotoToImage(asset : PHAsset) -> UIImage{
let manager = PHImageManager.default()
var media = UIImage()
let requestOptions=PHImageRequestOptions()
requestOptions.isSynchronous=true
requestOptions.deliveryMode = .highQualityFormat
manager.requestImage(for: asset, targetSize: CGSize(width: 1000, height: 1000), contentMode:.aspectFill, options: requestOptions) { image,_ in
media = image!
}
return media
}
func setUpData(){
self.mediaArray.value = tempMedia
}
}
extension GalleryPageViewModel{
func numberOfItemsInSection() -> Int{
return mediaArray.value?.count ?? 0
}
func didSelectAtRow(index:IndexPath){
self.responder.pushToDetailVc(data: mediaArray.value![index.row])
}
}
extension GalleryPageViewModel{
func setUpCoreData(){
appDelegate = UIApplication.shared.delegate as! AppDelegate
context = appDelegate?.persistentContainer.viewContext
}
func storeInCoreData(){
let entity = NSEntityDescription.entity(forEntityName: "MediaData", in: context!)
let newUser = NSManagedObject(entity: entity!, insertInto: context)
var i = 1
for data in mediaArray.value!{
newUser.setValue(data.img, forKey: "image")
newUser.setValue(data.duration, forKey: "duration")
newUser.setValue("data", forKey: "mediaType")
newUser.setValue(data.location, forKey: "location")
newUser.setValue(data.creationDate, forKey: "creationDate")
var id = String()
if data.mediaType == .photo{
id = "imgEn\(i)"
}
else{
id = "vidEn\(i)"
}
i+=1
newUser.setValue(id, forKey: "id")
}
}
}
View controller
import UIKit
import Photos
class GalleryPageViewController: BaseViewController {
var galleryCollectionView : UICollectionView?
var galleryCollectionViewFlowLayout : UICollectionViewFlowLayout? = nil
var viewModel: GalleryPageViewModel? {
didSet {
self.bindViewModel()
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.title = viewModel?.title
view.backgroundColor = .systemBackground
setUpFlowLayout()
galleryCollectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: galleryCollectionViewFlowLayout!)
galleryCollectionView?.register(MediaCollectionViewCell.self, forCellWithReuseIdentifier: "cell")
setUpCollectionView()
viewConstraintsForGalleryPage()
viewModel?.populatePhotos()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
}
// MARK: - UI WORKS
extension GalleryPageViewController{
func setUpFlowLayout(){
galleryCollectionViewFlowLayout = UICollectionViewFlowLayout()
galleryCollectionViewFlowLayout?.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
galleryCollectionViewFlowLayout?.itemSize = CGSize(width: (view.frame.width/2) - 20, height: (self.view.frame.width/2)-10)
}
func setUpCollectionView(){
galleryCollectionView?.dataSource = self
galleryCollectionView?.delegate = self
}
func viewConstraintsForGalleryPage(){
// adding sub view to maintain heirarchy.
view.addSubview(galleryCollectionView!)
// constraints for views in this page
// collection view
galleryCollectionView?.translatesAutoresizingMaskIntoConstraints = false
// galleryCollectionView?.backgroundColor = .blue
galleryCollectionView?.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor,constant: 10).isActive = true
galleryCollectionView?.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
galleryCollectionView?.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor,constant: 10).isActive = true
galleryCollectionView?.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true
}
}
//MARK: - COLLECTION VIEW DELEGATE AND DATA SOURCE
extension GalleryPageViewController : UICollectionViewDelegate{
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// vc.data = viewModel?.mediaArray.value?[indexPath.row]
viewModel?.didSelectAtRow(index: indexPath)
}
}
extension GalleryPageViewController : UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return viewModel?.numberOfItemsInSection() ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MediaCollectionViewCell
let cellData = viewModel?.mediaArray.value?[indexPath.row]
cell.imageView.image = cellData?.img
if cellData?.mediaType == .video{
cell.playBtn.isHidden = false
cell.durationLabel.isHidden = false
let manager = PHImageManager.default()
manager.requestAVAsset(forVideo: (cellData?.asset)!, options: nil){asset,_,_ in
let duration = asset?.duration
let durationTime = CMTimeGetSeconds(duration!)
let finalTime = durationTime/60
DispatchQueue.main.async {
cell.durationLabel.text = "\(Int(finalTime)) : \(Int(durationTime) % 60)"
}
}
}
else{
cell.playBtn.isHidden = true
cell.durationLabel.isHidden = true
}
return cell
}
}
//MARK: - BINDING VARIABLES
extension GalleryPageViewController{
private func bindViewModel(){
viewModel?.mediaArray.bind { [weak self] _ in
print("i am gonna reload")
print(self?.viewModel?.mediaArray.value?.isEmpty)
DispatchQueue.main.async {
self?.galleryCollectionView?.reloadData()
}
}
}
}

Getting rows one by one on refreshing by pulling down ,wanted whole array on viewdidload

When I reload the tableview by pulling down the refreshing controller , it gets me rows one by one on each refreshing . I want all the data of rows in (view did load) and refreshing .
Table view is in view controller , I am getting one row in each refresh /reload, but want all rows on(view did load) and on refreshing .
when I open the view I get one row and when I refresh the view I get one more row but wanted to have all rows in one time in (view did load) and refreshcontrol .
there are three methods (view did load) / view will appear / refreshing control / I want the whole value of cartData on viewdidload.
public struct FavouriteCart {
var p_name : String!
var p_price : String!
var p_id : String!
var qty: String!
public init(p_name: String , p_price: String , p_id : String, qty: String) {
self.p_name = p_name
self.p_price = p_price
self.p_id = p_id
self.qty = qty
}
}
public struct favSection {
var favitems: [FavouriteCart]
public init(favitems: [FavouriteCart] ) {
self.favitems = favitems
}
}
override func viewDidLoad() {
super.viewDidLoad()
//self.getFav()
// self.reloadInputViews()
// self.getFav()
self.viewWillAppear(true)
self.updateTableview()
if btn2 != btn3 {
lblPreorder.isHidden = true
lblOrdermethod.isHidden = false
print("BUTTONCLICKED")
UserDefaults.standard.removeObject(forKey: "button1")
} else if btn2 == btn3 {
lblPreorder.isHidden = false
lblOrdermethod.isHidden = true
print("BUTTON-NOT-CLICKED")
UserDefaults.standard.removeObject(forKey: "button1")
}
// self.view.layoutIfNeeded()
// self.view.setNeedsDisplay()
// self.getFav()
// self.updateTableview()
self.tableView.dataSource = self
self.tableView.delegate = self
print("111111111 -> \(cartid)")
self.view.addSubview(self.tableView)
if #available(iOS 10.0, *) {
tableView.refreshControl = refreshControl
} else {
tableView.addSubview(refreshControl)
}
refreshControl.addTarget(self, action: #selector(newCartViewController.refreshData), for: UIControlEvents.valueChanged)
//
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.refreshData()
// self.refreshData()
// self.getFav()
// self.updateTableview()
}
#objc func refreshData() {
self.getFav()
self.getTotal1()
self.updateTableview()
self.refreshControl.endRefreshing()
}
func updateTableview() {
DispatchQueue.main.async{
self.tableView.reloadData()
}
}
// Mark: getting all cart items:-->
func getFav(){
let request = getApi.displaycartGetWithRequestBuilder(restId: "17", cartId:cartid!)
Alamofire.request(request.URLString, method: .get , parameters: nil, encoding: JSONEncoding.default)
.responseJSON { response in
print("123321/\(response)")
let res = response
print("101res/\(res)")
let total = self.cartData
print("cartd1/\(total)")
if let value = response.value as? [String: AnyObject] {
if let success = value["error"] as? Bool {
if success == false {
print("2222/\(response)")
if let response = value["cartdata"] as? [String: AnyObject] {
let cart = response["simple"] as! [[String: AnyObject]]
var itemsdata: [FavouriteCart] = []
for (_ , value) in cart.enumerated() {
let obj = value as! [String:AnyObject]
let p_name = obj["p_name"] as! String
let p_price = obj["p_price"] as! String
let p_id = obj["p_id"] as! String
let qty = obj["qty"] as! String
var prid = p_id as! String
print("stirng ID - > /\(p_id)")
let item = FavouriteCart(p_name: p_name, p_price: p_price, p_id: p_id, qty: qty)
itemsdata.append(item)
// self.cartData.append(favitems)
print("hiiooooooooooooooooooooooo/\(itemsdata)")
}
self.cartData.append(favSection(favitems: itemsdata))
self.tableView.reloadData()
}
}
}
else
{
let myAlert = UIAlertController(title:"Alert",message:value["error_msg"] as? String,preferredStyle:UIAlertControllerStyle.alert)
let okAction = UIAlertAction(title:"OK",style:UIAlertActionStyle.default , handler: nil)
myAlert.addAction(okAction)
}
}
}
}
// Mark:--> Delete items from cart.
// func delFav(p_id: String ,completionHandler: #escaping (Bool) -> Void) {
func delFav(product_id: String, completionHandler: #escaping (Bool) -> Void){
//var product1 = UserDefaults.standard.object(forKey: "p_id")
//print("this is my \(product1)")
let request = getApi.deleteproductcartGetWithRequestBuilder(restId: "17", cartId: cartid!, productId: product_id , freeDish: "none", type: "simple")
Alamofire.request(request.URLString, method: .delete , parameters: nil, encoding: JSONEncoding.default)
.responseJSON { response in
print("del favvvvvvvvv\(response)")
//print(response)
if let value = response.value as? [String: AnyObject] {
if let success = value["error"] as? Bool {
if success == false {
let response = value["cartdata"] as? [String]
print("10001 - > /\(response)")
//self.tableView.reloadData()
} else
{
print("error message")
}
}
}
// completionHandler(true)
}
}
func delterow(product_id: String) {
self.delFav(product_id: product_id, completionHandler: {sucess in
if sucess {
print("DELETED_ITEM")
}
})
}
}
extension newCartViewController: UITableViewDelegate , UITableViewDataSource{
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 90;
}
// func numberOfSections(in tableView: UITableView) -> Int {
// return cartData.count
// }
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// return sectionsData[section].items.count
return cartData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cartTablecell", for: indexPath) as! cartTableViewCell
let item: FavouriteCart = cartData[indexPath.section].favitems[indexPath.row]
cell.btnsub1.tag = indexPath.row
cell.btnadd1.tag = indexPath.row
cell.lblItemName.text = item.p_name
cell.productPrice.text = item.p_price
cell.lblprice.text = item.p_price
return cell
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool{
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == .delete) {
let item: FavouriteCart = cartData[indexPath.section].favitems[indexPath.row]
self.delterow(product_id: item.p_id)
self.tableView.reloadData()
}
}
}
used completion handler in the api call and reloaded the data in the api call :-----
override func viewDidLoad() {
super.viewDidLoad()
// self.getFav()
//self.viewWillAppear(true)
// refreshControl.addTarget(self, action: #selector(viewDidAppear(_:)), for: UIControlEvents.valueChanged)
refreshControl.attributedTitle = NSAttributedString(string: "Pull to refresh")
refreshControl.addTarget(self, action: #selector(newCartViewController.refreshData), for: UIControlEvents.valueChanged)
tableView.addSubview(refreshControl)
if btn2 != btn3 {
lblPreorder.isHidden = true
lblOrdermethod.isHidden = false
print("BUTTONCLICKED")
UserDefaults.standard.removeObject(forKey: "button1")
} else if btn2 == btn3 {
lblPreorder.isHidden = false
lblOrdermethod.isHidden = true
print("BUTTON-NOT-CLICKED")
UserDefaults.standard.removeObject(forKey: "button1")
}
// self.view.layoutIfNeeded()
// self.view.setNeedsDisplay()
// self.getFav()
// self.updateTableview()
self.tableView.dataSource = self
self.tableView.delegate = self
print("111111111 -> \(cartid)")
self.view.addSubview(self.tableView)
if #available(iOS 10.0, *) {
tableView.refreshControl = refreshControl
} else {
tableView.addSubview(refreshControl)
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.updateTableview()
self.getFav()
}
#objc func refreshData() {
self.getFav()
self.getTotal1()
DispatchQueue.main.async {
self.refreshControl.endRefreshing()
}
}
func updateTableview() {
DispatchQueue.main.async{
self.tableView.reloadData()
}
}
func getFav() {
getFav(completionHandler: { success in
if success {
DispatchQueue.main.async{
self.tableView.reloadData()
}
}
})
}
//TOTAL API CALL:
func getTotal1() {
let request = getApi.getamountcartGetWithRequestBuilder(restId: "17", cartId: (cartid as? String)!)
Alamofire.request(request.URLString, method: .get , parameters: nil, encoding: JSONEncoding.default)
.responseJSON { response in
print("123321#######/\(response)")
let res = response
print("101res/\(res)")
if let value = response.value as? [String: AnyObject] {
if let success = value["error"] as? Bool {
if success == false {
var grandtotal = value["total"] as Any
var gtotal = grandtotal
print("^^^^^/\(gtotal)")
print("####/\(grandtotal)")
UserDefaults.standard.set(10, forKey: "gtotal")
}
}
}
}
}
//
// Mark: getting all cart items:-->
func getFav(completionHandler: #escaping (Bool) -> Void){
let request = getApi.displaycartGetWithRequestBuilder(restId: "17", cartId:cartid!)
Alamofire.request(request.URLString, method: .get , parameters: nil, encoding: JSONEncoding.default)
.responseJSON { response in
print("123321/\(response)")
let res = response
print("101res/\(res)")
let total = self.cartData
print("cartd1/\(total)")
if let value = response.value as? [String: AnyObject] {
if let success = value["error"] as? Bool {
if success == false {
print("2222/\(response)")
if let response = value["cartdata"] as? [String: AnyObject] {
let cart = response["simple"] as! [[String: AnyObject]]
// let total = value["total"] as! [String: Any]
// print("1231231231234/\(total)")
//let userdata: [Favourites] = []
//
var cartData: [FavouriteCart] = []
for (_ , value) in cart.enumerated() {
let obj = value as! [String:AnyObject]
let p_name = obj["p_name"] as! String
let p_price = obj["p_price"] as! String
let p_id = obj["p_id"] as! String
let qty = obj["qty"] as! String
// UserDefaults.standard.set(qty, forKey: "qty")
var prid = p_id as! String
print("stirng ID - > /\(p_id)")
let item = FavouriteCart(p_name: p_name, p_price: p_price, p_id: p_id, qty: qty)
cartData.append(item)
DispatchQueue.main.async{
print("RELOADED-----ON-----API")
self.cartData.append(favSection(favitems: cartData))
self.tableView.reloadData()
}
// self.tableView.reloadData()
// self.cartData.append(favitems)
//QTY::::::-------
// let quant = QtyCart(qty: qty)
// self.qtyData.append(quant)
//
//print("hiiooooooooooooooooooooooo/\(itemsdata)")
}
}
print("COMPLETION-------------HANDLER")
completionHandler(true)
}
}
else
{
let myAlert = UIAlertController(title:"Alert",message:value["error_msg"] as? String,preferredStyle:UIAlertControllerStyle.alert)
let okAction = UIAlertAction(title:"OK",style:UIAlertActionStyle.default , handler: nil)
myAlert.addAction(okAction)
}
}
}
}

How do I update collectionview based on added info to firebase

Im having a problem in my app, I am working on a Twitter/Instagram like app that posts a pic and then retrieves it in the "Home" section. But, I cant find a way to make the collection view update when the new post is added in firebase. I tried self.collectionview.reloadData(), it didn't work, I tried self.posts.removeAll() and then self.fetchPosts() to retrieve it again and it didn't work. I've been working on this problem for months and just can't find a possible solution without having to pay $$ for a "short problem".
Thanks in advance!
Here is my code:
#IBOutlet weak var collectionview: UICollectionView!
var posts = [Post]()
var following = [String]()
lazy var refreshControl: UIRefreshControl? = {
let refreshControl = UIRefreshControl()
refreshControl.tintColor = UIColor.gray
refreshControl.addTarget(self, action: #selector(refreshList), for: UIControlEvents.valueChanged)
collectionview.addSubview(refreshControl)
self.collectionview.reloadData()
return refreshControl
}()
override func viewDidLoad() {
super.viewDidLoad()
setupNavigationBarItems()
fetchPosts()
collectionview.refreshControl = refreshControl
}
func setupNavigationBarItems() {
navigationItem.title = "Home"
}
#objc func refreshList() {
let deadline = DispatchTime.now() + .milliseconds(1000)
DispatchQueue.main.asyncAfter(deadline: deadline) {
self.collectionview.reloadData()
self.refreshControl?.endRefreshing()
print("reloaded...")
}
self.collectionview.reloadData()
}
#objc func fetchPosts() {
let ref = Database.database().reference()
ref.child("users").queryOrderedByKey().observeSingleEvent(of: .value, with: { snapshot in
let users = snapshot.value as! [String : AnyObject]
for (_,value) in users {
if let uid = value["uid"] as? String {
if uid == Auth.auth().currentUser?.uid {
if let followingUsers = value["following"] as? [String : String]{
for (_,user) in followingUsers{
self.following.append(user)
}
}
self.following.append(Auth.auth().currentUser!.uid)
ref.child("posts").queryOrderedByKey().observeSingleEvent(of: .value, with: { (snap) in
let postsSnap = snap.value as! [String : AnyObject]
for (_,post) in postsSnap {
if let userID = post["userID"] as? String {
for each in self.following {
if each == userID {
let posst = Post()
if let author = post["author"] as? String, let likes = post["likes"] as? Int, let pathToImage = post["pathToImage"] as? String, let postID = post["postID"] as? String {
posst.author = author
posst.likes = likes
posst.pathToImage = pathToImage
posst.postID = postID
posst.userID = userID
if let people = post["peopleWhoLike"] as? [String : AnyObject] {
for (_,person) in people {
posst.peopleWhoLike.append(person as! String)
}
}
self.posts.append(posst)
}
}
}
self.collectionview.reloadData()
}
}
})
}
}
}
})
ref.removeAllObservers()
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.posts.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "postCell", for: indexPath) as! PostCell
cell.postImage.downloadImage(from: self.posts[indexPath.row].pathToImage)
cell.authorLabel.text = self.posts[indexPath.row].author
cell.likeLabel.text = "\(self.posts[indexPath.row].likes!) Likes"
cell.postID = self.posts[indexPath.row].postID
for person in self.posts[indexPath.row].peopleWhoLike {
if person == Auth.auth().currentUser!.uid {
cell.likeBtn.isHidden = true
cell.dislikeBtn.isHidden = false
break
}
}
return cell
}
}
Replace this
ref.child("posts").queryOrderedByKey().observeSingleEvent(of: .value, with: { (snap) in
with
ref.child("posts").observe(of: .childAdded, with: { (snap) in
to be able to listen to every added post

Pass image from collection to viewcontroller swift

i haave problem i can't Pass ImageView From collection to viewcontroller using Firebase Database
This My Code
import UIKit
import Firebase
import FirebaseDatabase
import SDWebImage
import FirebaseStorage
import KRProgressHUD
class ViewControllerCollocation: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var MyColloctaion: UICollectionView!
var imagePicker = UIImagePickerController()
var images = [ImagePost]()
var dbRef:DatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
setutxent()
designCollectionView()
imagePicker.delegate = self
dbRef = Database.database().reference().child("Images")
/////////
loadDB()
KRProgressHUD.set(style: .custom(background: .black, text: .white, icon: nil))
KRProgressHUD.show(withMessage: "Loading...")
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
KRProgressHUD.dismiss()
}
}
func loadDB(){
dbRef.observe(DataEventType.value, with: { (snapshot) in
var newImages = [ImagePost]()
for imageFireSnapshot in snapshot.children {
let ImagesFireObject = ImagePost(snapshot: imageFireSnapshot as! DataSnapshot)
newImages.append(ImagesFireObject)
}
self.images = newImages
self.MyColloctaion.reloadData()
}
)}
func collectionView(_ colloction: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images.count
}
internal func collectionView(_ colloction: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = colloction.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! UploadOneCollectionViewCell
let image = images[indexPath.row]
cell.ImageView.layer.cornerRadius = 13
cell.ImageView.clipsToBounds = true
cell.ImageView.sd_setImage(with: URL(string: image.url), placeholderImage: UIImage(named: "Image1"))
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
func designCollectionView() {
let itemSize = UIScreen.main.bounds.width/3 - 3
let layout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 1, left: 1, bottom: 1, right: 1)
layout.itemSize = CGSize(width: itemSize, height: 230)
layout.minimumInteritemSpacing = 1
layout.minimumLineSpacing = 1
//layout.scrollDirection = .horizontal
self.MyColloctaion.isPagingEnabled = true
MyColloctaion.collectionViewLayout = layout
}
func steupbar(){
navigationController?.navigationBar.barTintColor = UIColor.black
tabBarController?.tabBar.barTintColor = UIColor.black
self.navigationController?.navigationBar.titleTextAttributes =
[NSAttributedString.Key.foregroundColor: UIColor.white,
NSAttributedString.Key.font: UIFont(name: "Baskerville-BoldItalic", size: 21)!]
}
#IBAction func Upload(_ sender: Any) {
imagePicker = UIImagePickerController()
imagePicker.allowsEditing = false
imagePicker.sourceType = .photoLibrary
imagePicker.delegate = self
self.present(imagePicker, animated: true, completion: nil)
}
func generateRandom(size: UInt) -> String {
let prefixSize = Int(min(size, 43))
let uuidString = UUID().uuidString.replacingOccurrences(of: "-", with: "")
return String(Data(uuidString.utf8)
.base64EncodedString()
.replacingOccurrences(of: "=", with: "")
.prefix(prefixSize))
}
}
this is My ""ImagePost.swift"""
import Foundation
import FirebaseDatabase
struct ImagePost {
let key: String!
let url:String!
let itemRef:DatabaseReference?
init(url:String, key:String) {
self.key = key
self.url = url
self.itemRef = nil
}
init(snapshot:DataSnapshot) {
key = snapshot.key
itemRef = snapshot.ref
let snapshotValue = snapshot.value as? NSDictionary
if let imageUrl = snapshotValue?["url"] as? String {
url = imageUrl
}else{
url = ""
}
}
}
and This is My detail view
import UIKit
class VC1: UIViewController {
var imageURL : String?
#IBOutlet weak var ImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
}
}
and Thanks for your help guys!
You can pass image to detail view by getting image in didselect method:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let image = images[indexPath.row]
let vc = self.storyboard?.instantiateViewController(withIdentifier: "VC1") as! VC1
vc.imageObject = images[indexPath.row]
self.navigationController?.pushViewController(vc, animated: false)
}
Just create a variable as imageObject in VC1 and pass data to it as shown above.

Firebase observeSingleEvent continuously duplicate entry being appended in my array

When I refresh the collection view the data duplicates by +1 in my. How can I avoid duplicate entries in my array when I pull to refresh this function?
Also used self.posts.removeAll() still no result.
var posts = [Post]() {
didSet {
collectionView?.reloadData()
}
}
var following = [String]()
let refreshControl = UIRefreshControl()
override func viewDidLoad() {
super.viewDidLoad()
refreshControl.tintColor = UIColor.gray
refreshControl.addTarget(self, action: #selector(fetchPosts), for: UIControlEvents.valueChanged)
collectionView?.addSubview(refreshControl)
collectionView?.alwaysBounceVertical = true
fetchPosts()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.collectionView.reloadData()
}
func fetchPosts(){
let ref = FIRDatabase.database().reference()
ref.child("users").queryOrderedByKey().observeSingleEvent(of: .value, with: { snapshot in
guard let users = snapshot.value as? [String : AnyObject] else {
return
}
print(snapshot.key)
for (_,value) in users {
if let uid = value["uid"] as? String {
if uid == FIRAuth.auth()?.currentUser?.uid {
if let followingUsers = value["following"] as? [String : String]{
for (_,user) in followingUsers{
self.following.append(user)
print(user)
}
}
self.following.append(FIRAuth.auth()!.currentUser!.uid)
ref.child("posts").queryOrderedByKey().observeSingleEvent(of: .value, with: { (snap) in
for postSnapshot in snap.children.allObjects as! [FIRDataSnapshot] {
let post = postSnapshot.value as! [String : AnyObject]
print(snap.key)
if let userID = post["userID"] as? String {
for each in self.following {
if each == userID {
print(each)
let posst = Post()
if let date = post["date"] as? Int, let author = post["author"] as? String, let likes = post["likes"] as? Int, let pathToImage = post["pathToImage"] as? String, let postID = post["postID"] as? String {
posst.date = Int(date)
posst.author = author
posst.likes = likes
posst.pathToImage = pathToImage
posst.postID = postID
posst.userID = userID
print(posst)
if let people = post["peopleWhoLike"] as? [String : AnyObject] {
for (_,person) in people {
posst.peopleWhoLike.append(person as! String)
}
}
var postExist:Bool = false
for post in self.posts {
if post.postID == posst.postID {
postExist = true
break
}
}
if !postExist {
self.posts.append(posst)
}
self.posts.sort(by: {$0.date! > $1.date!})
self.refreshControl.endRefreshing()
}
}
}
self.collectionView.reloadData()
}
}
})
}
}
}
})
ref.removeAllObservers()
}
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 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PostCell.identifier, for: indexPath) as! PostCell
cell.posts = posts[indexPath.row]
let post = posts[indexPath.row]
for person in post.peopleWhoLike {
if person == FIRAuth.auth()!.currentUser!.uid {
cell.like.isHidden = true
cell.unlike.isHidden = false
break
}
}
return cell
}
}
Updated with the solutions.
I take it that when the refresh is activated, this function is called and that all the posts are downloaded. For your duplicate problem, it seems that you keep on appending data to your posts array without removing the old data.
ref.child("posts").queryOrderedByKey().observeSingleEvent(of: .value, with: { (snap) in
let postsSnap = snap.value as! [String : AnyObject]
self.posts.removeAll() // This will remove previously downloaded posts.
// All your other code ...