Empty Collection View Swift - swift

I followed 1 tutorial and i was able to fill a collectionView with some data(imageview and text):
let appleProducts = ["A", "B", "C", "D"]
let imageArray = [UIImage(named: "pug1"), UIImage(named: "pug2"), UIImage(named: "pug3"), UIImage(named: "pug4")]
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return appleProducts.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath as IndexPath) as! CollectionViewCell
cell.imageView?.image = self.imageArray[indexPath.row]
cell.title?.text = self.appleProducts[indexPath.row]
return cell
}
Now passing from the demo project to mine, I want to fill this CollectionView with data(Picture and text) that I get from FirebaseDatabse so I created this method:
struct item {
let pictureId: String!
let picture: String!
}
var items = [item]()
func getLatestAddedItems(){
self.items.removeAll()
let databaseRef = FIRDatabase.database().reference()
databaseRef.child("Items").observe(.value, with: {
snapshot in
//self.items.insert(item(picture: picture), at: 0)
for childSnap in snapshot.children.allObjects {
let snap = childSnap as! FIRDataSnapshot
//print(snap.key)
let picture = (snap.value as? NSDictionary)?["bookImage"] as? String ?? ""
//print(picture)
self.items.append(item(pictureId:snap.key, picture:picture))
}
print(self.items.count)
})
}
And I create this button to call GetLatestAddedItems Method:
#IBAction func selectAction(_ sender: AnyObject) {
getLatestAddedItems()
}
And this one to check results:
#IBAction func gettableAction(_ sender: AnyObject) {
print(self.items[0].picture)
print(self.items[1].picture)
print(self.items[2].picture)
print(self.items.count) }
OutPut results:
picture 1 link
picture 2 link
picture 3 link
3
Everythings look fine and correct, now after making required changes in ContentView methods:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return items.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath as IndexPath) as! CollectionViewCell
//cell.imageView?.image = self.imageArray[indexPath.row]
let url = NSURL(string: items[indexPath.row].picture)
let data = NSData(contentsOf: url! as URL)
cell.imageView?.image = UIImage(data: data! as Data)
cell.title?.text = self.items[indexPath.row].pictureId
return cell
}
Now I'm getting an empty ContentView, the first time with button it works because I call the getLatestAddedItems() that will get and add data to the Items table, I try to call it in both ViewWillAppear or Viewdidload but nothings changes.
This is what I think the return items.count is returning 0 so nothings will appear any suggestions ?

Move your collectionView's protocol delegation initialisation to one of the ViewController lifecycle scope such as viewDidLoad() or viewWillAppear(_animated : Bool) if you are using a custom viewController(i.e embed a collectionView inside a viewController)
And reload your collectionView every time your user receives a value from its database.
override func viewDidLoad(){
super.viewDidLoad()
self.collectionView.dataSource = self
self.collectionView.delegate = self
}
func getLatestAddedItems(){
self.items.removeAll()
let databaseRef = FIRDatabase.database().reference()
databaseRef.child("Items").observe(.childAdded, with: {
snapshot in
for childSnap in snapshot.children.allObjects {
let snap = childSnap as! FIRDataSnapshot
let picture = (snap.value as? NSDictionary)?["bookImage"] as? String ?? ""
self.items.append(item(pictureId:snap.key, picture:picture))
print(self.items.count)
self.collectionView.reloadData()
}
})
}
PS:- All the calls to your firebase server are asynchronous, which takes some time to retrieve the data from your FBDB, so put print(self.items.count) should be inside the completionBlock of the firebase observing call otherwise if it is put outside it will be called even before your data has been retrieved from FBDB.

Related

Collectionview with coredata problems

The problem is when I switch between pages (TabNavigation) and I return in this page, a cell is added unwantedly, I rewrite the code the code many times, can someone help me?
CoreData is implemented it to save favorites in this collection view, and everything works except this little bug
var Distance : String!
var Logo : UIImage!
var pp : String!
var menuu : UIButton!
var loc : String!
var shop: [NSManagedObject] = []
#IBOutlet weak var ShopCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
ShopCollectionView.layer.cornerRadius = 10
ShopCollectionView.layer.masksToBounds = true
// register cell
let nibCell = UINib(nibName: ShopCollectionViewCellId, bundle: nil)
ShopCollectionView.register(nibCell, forCellWithReuseIdentifier: ShopCollectionViewCellId)
ShopCollectionView.delegate = self
ShopCollectionView.dataSource = self
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound]) { (granted, error) in }
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "ShopsData", in: managedContext)!
let item = NSManagedObject(entity: entity, insertInto: managedContext)
let fetch = NSFetchRequest<NSFetchRequestResult>(entityName: "ShopsData")
do {
let result = try? managedContext.fetch(fetch) as? [ShopsData]
shop = result ?? []
} catch {
fatalError()
}
collectionView.reloadData()
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
return shop.count + 1
}
<This is my writed method>
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.row >= shop.count {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ShopCollectionViewCellId, for: indexPath) as! ShopCollectionViewCell
return cell
} else {
let shop = shop[indexPath.row]
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ShopCollectionViewCellId, for: indexPath) as! ShopCollectionViewCell
cell.People.text = shop.value(forKey: "actualCustomers") as? String
cell.Location.text = shop.value(forKey: "location") as? String
return cell
}
}
This is the code I write
In your numberOfItemsInSection you return shop.count + 1 which means you are telling your collection view to show you 1 additional cell than the actual data you have.
Then in your cellForItemAt indexPath, you handle this by creating 1 blank cell.
If suggest you make the following changes to these functions as shown below and perhaps you will see the results you expect
override func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int
{
return shop.count
}
override func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let shop = shop[indexPath.row]
let cell =
collectionView.dequeueReusableCell(withReuseIdentifier: ShopCollectionViewCellId,
for: indexPath) as! ShopCollectionViewCell
cell.People.text = shop.value(forKey: "actualCustomers") as? String
cell.Location.text = shop.value(forKey: "location") as? String
return cell
}

CollectionViewCell is no displayed receiving data from Firebase

I have to fill the cells with data from the firebase. But they are not displayed. Help and explain where I made a mistake.
How to fill cell data ?
class TrainingProgramViewController: UIViewController {
#IBOutlet weak var collectionView: UICollectionView!
//var trainingPrograms = TrainingProgram.fetchTrainingProgram()
var trainingPrograms = [TrainingProgram]()
let cellScale: CGFloat = 0.7
override func viewDidLoad() {
super.viewDidLoad()
fetchPrograms()
}
func fetchPrograms() {
Database.database().reference().child("programs").observe(.childAdded) { (snapshot) in
if let dict = snapshot.value as? [String: Any] {
print(dict)
let newTitle = dict["title"] as! String
print("Новый тайтл:" + newTitle)
let newDescription = dict["description"] as! String
let trainingCell = TrainingProgram(description: newDescription, title: newTitle)
self.trainingPrograms.append(trainingCell)
print(self.trainingPrograms)
}
}
}
}
extension TrainingProgramViewController: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return trainingPrograms.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TrainingProgramCollectionViewCell", for: indexPath) as! TrainingProgramCollectionViewCell
let trainingProgram = trainingPrograms[indexPath.item]
cell.trainingPrograms = trainingProgram
return cell
}
This is a model:
class TrainingProgram
{
var description = ""
var title = ""
init(description: String, title: String) {
self.description = description
self.title = title
}
}
This is my structure of Database :
You forget to reload your collectionView
func fetchPrograms() {
Database.database().reference().child("programs").observe(.childAdded) { (snapshot) in
if let dict = snapshot.value as? [String: Any] {
print(dict)
let newTitle = dict["title"] as! String
print("Новый тайтл:" + newTitle)
let newDescription = dict["description"] as! String
let trainingCell = TrainingProgram(description: newDescription, title: newTitle)
self.trainingPrograms.append(trainingCell)
print(self.trainingPrograms)
}
DispatchQueue.main.async {
self. collectionView.reloadData()
}
}
}
Also set
collectionView.delegate = self
collectionView.dataSource = self
In your collectionView Method
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TrainingProgramCollectionViewCell", for: indexPath) as! TrainingProgramCollectionViewCell
cell.titleLabel.text = trainingPrograms[indexPath.item].title
return cell
}
After you fetch the data and append it to your array which is shown in your tableView/collectionView you always have to reloadData() like collectionView.reloadData() or tableView.reloadData()

How to pass image from url to another view contoller using sd webimage framework swift

I have a collection view cell in first view controller which has imageview fetched from url using sd webimage third party library.This image is a thumbnail image.I want to pass the actual image to another view controller in didselectitemat of first view controller.The code is as follows:
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return subcategoryArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
print("inside cell for item at ")
let cell:SubCategoryCollectionViewCell = self.collectionview3.dequeueReusableCell(withReuseIdentifier: "Cell2", for: indexPath) as! SubCategoryCollectionViewCell
if defaultAnimalArray.count - 1 >= indexPath.row
{
let item = self.defaultAnimalArray[indexPath.row]
cell.subThumbImg?.image = UIImage(named: item as! String)
}
else
{
//If now defaultAnimalArray.count = 8, indexPath = 8 , But array = 0...4, then,
let item1 = self.subcategoryArray[indexPath.row - self.defaultAnimalArray.count]
self.subcatthumbimagelink = (item1 as AnyObject).object(forKey: "SubcategoryThumb") as! String
cell.subThumbImg.sd_setImage(with: URL(string: self.subcatthumbimagelink), placeholderImage: UIImage(named: "placeholder.png"),options: SDWebImageOptions(), completed: {(image, error, cacheType, imageURL) -> Void in
print("image loaded")
})
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("image selected for coloring")
if defaultAnimalArray.count - 1 >= indexPath.row
{
print("indexpath selected is \(indexPath.row)")
let item = self.animalcategoryImages[indexPath.row]
var drawVC = self.storyboard?.instantiateViewController(withIdentifier: "DrawingViewController") as! DrawingViewController
drawVC.selectedimage = UIImage(named:item)
self.navigationController?.pushViewController(drawVC, animated: true)
}
else
{
print("indexpath selected in else loop is \(indexPath.row)")
let item1 = self.subcategoryArray[indexPath.row - 10]
print("subcategory count after manipulation is \(self.subcategoryArray)")
print("count of item1 \((item1 as AnyObject).count)")
print("item1 is \(item1)")
self.subcategoryimagelink = (item1 as AnyObject).object(forKey: "SubcategoryImage") as! String
print("category image link is \(self.subcategoryimagelink)")
self.ImageviewMain.sd_setImage(with: URL(string: self.subcategoryimagelink))
var drawVC = self.storyboard?.instantiateViewController(withIdentifier: "DrawingViewController") as! DrawingViewController
drawVC.selectedimage = self.ImageviewMain.image
self.navigationController?.pushViewController(drawVC, animated: true)
}
The subcategory count is addition of array from url and a array which is default.Kindly help me how to pass the image from url which is in cell to another view controller.
You need to pass only image url string instead of UIImage object
var drawVC = self.storyboard?.instantiateViewController(withIdentifier: "DrawingViewController") as! DrawingViewController
drawVC.imageURL = self.subcatthumbimagelink // you can also pass string from array
self.navigationController?.pushViewController(drawVC, animated: true)
In DrawingViewController
var imageURL : String?
self.imageView.sd_setImage(with: URL(string:imageURL), placeholderImage: UIImage(named: "placeholder.png"),options: SDWebImageOptions(), completed: {(image, error, cacheType, imageURL) -> Void in
print("image loaded")
})

Error when peeking and popping from collection view

Received an error
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
when trying to peek and pop from a collection view. I've checked my data struct and index path but everything seems to be fine.
Here's my code for the collections view
class thisSeaonViewController: UICollectionViewController, UIViewControllerPreviewingDelegate {
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
var URLArrayStringThisSeason = [String]()
var currentURL = String()
override func viewDidLoad() {
generateData()
if( traitCollection.forceTouchCapability == .available){
registerForPreviewing(with: self as! UIViewControllerPreviewingDelegate, sourceView: view)
}
}
override func viewDidAppear(_ animated: Bool) {
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
let imageView = cell.viewWithTag(1) as! UIImageView
let url = NSURL(string: URLArrayStringThisSeason[indexPath.row])
let placeholderImage = UIImage(named: "Rectangle")!
let filter = AspectScaledToFillSizeWithRoundedCornersFilter(
size: imageView.frame.size,
radius: 0
)
imageView.af_setImage(withURL: url as! URL, placeholderImage: placeholderImage, filter: filter, imageTransition: .crossDissolve(0.2)
)
cell.backgroundColor = UIColor.init(hexString: "#F3F3F3")
cell.layer.cornerRadius = 3.0
return cell
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return URLArrayStringThisSeason.count
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let vc = storyboard?.instantiateViewController(withIdentifier: "gridDetailedView") as! gridDetailedViewController
vc.imageURL = URLArrayStringThisSeason[indexPath.row]
self.navigationController?.pushViewController(vc, animated: true)
}
func generateData() {
if URLArrayStringThisSeason.count == 0 {
self.activityIndicator.isHidden = false
self.activityIndicator.startAnimating()
}
let queryThisSeason = FIRDatabase.database().reference().child("thisSeason")
queryThisSeason.keepSynced(true)
queryThisSeason.observeSingleEvent(of: .value, with: {(snapshot) in
if snapshot.childrenCount != 0 {
let urlArray = snapshot.value as! [String]
let urlLimitedArray = Array(urlArray.reversed())
self.URLArrayStringThisSeason = urlLimitedArray
self.collectionView?.reloadData()
self.activityIndicator.stopAnimating()
self.activityIndicator.isHidden = true
}
})
}
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
guard let indexPath = collectionView?.indexPathForItem(at: location) else { return nil }
guard let cell = collectionView?.cellForItem(at: indexPath) else { return nil }
guard let detailVC = storyboard?.instantiateViewController(withIdentifier: "gridDetailedView") as? gridDetailedViewController else { return nil }
//let photo = UIImage(named: "Rectangle")
detailVC.imageURL = URLArrayStringThisSeason[indexPath.row]
print(URLArrayStringThisSeason[indexPath.row])
detailVC.preferredContentSize = CGSize(width: 300, height: 300)
previewingContext.sourceRect = cell.frame
print("peek")
return detailVC
}
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
self.navigationController?.show(viewControllerToCommit, sender: Any?.self)
print("pop")
}
}
when peeking and popping, the function is supposed to send the imageURL to the detailed view controller and AlamofireImage will handle the image download and loading.
However, I've been getting misalignment issues with the collections view as the source rect will appear slightly above the cells and preventing peek and pop at certain parts of the cell. I think that this could be the cause of the peek and pop crash too.
edit:
here's what happens when I try to do peek and pop, you can see the focus of the cell is slightly shifted on top.
Ok I fixed the misalignment problem by changing this registerForPreviewingWithDelegate(self, sourceView: view)
to this
registerForPreviewingWithDelegate(self, sourceView: self.collectionView!)
however, the app is still crashes everytime I try to peek and pop.
Edit:
Ok the other problem is pretty much just some errors in the code. Just follow the above to fix the misalignment problem.

How to store image from collectionviewcell to core data

I have an entity called Task where taskImage is an attribute of binary data. I have the following
#IBOutlet weak var collectionView: UICollectionView!
var imageSelected = [UIImage]()
Then I have collection view as follows
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.imageSelected.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
as! EditCollectionViewCell
cell.imageView?.image = imageSelected[(indexPath as NSIndexPath).row]
cell.layer.borderColor = UIColor.white.cgColor
cell.layer.borderWidth = 3
return cell
}
Now I am trying to save image to core data when Save bar button item is pressed as follows
#IBAction func saveBtnPressed(_ sender: AnyObject) {
if #available(iOS 10.0, *) {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let task = Task(context: context)
task.taskDesc = taskText.text!
//task.taskImage = UIImagePNGRepresentation(cell.imageView?.image)
} else {
// Fallback on earlier versions
}
I am getting error for taskImage, any help regarding storing image will be appreciated.
My code to store image in core data
let appDel:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context:NSManagedObjectContext = appDel.managedObjectContext
let newContact = NSEntityDescription.insertNewObjectForEntityForName("Contact", inManagedObjectContext: context)
let imageData:NSData = UIImageJPEGRepresentation(imgViewPhoto.image!, 1)!
newContact.setValue(imageData, forKey: "imageData")
and retrieve it from coredata
let imageData:NSData = contact.valueForKey("imageData") as! NSData
imgViewPhoto.image = UIImage(data: imageData, scale: 1)