Horizontal UICollectionView with CoreData - ios

I am attempting a horizontal UICollectionView printing out CoreData entries, I get no errors when I enter in data and try to view the data, but the data does not print out in the UICollectionView. It is not an issue with entering the data in CoreData. below is my code to fetch CoreData and print out in UICollectionView, where am I going wrong?
class HistoryVC: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var QBHistory = [QB]()
override func viewDidLoad() {
super.viewDidLoad()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return QBHistory.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "QBCollectionViewCell", for: indexPath) as! QBCollectionViewCell
do{
QBHistory = try context.fetch(QB.fetchRequest())
for each in QBHistory {
cell.QBName.text = each.qbName
cell.QBPotential.text = each.qbPotential
cell.QBValue.text = each.qbValue
cell.QBBust.text = String(each.qbBust)
cell.QBRound.text = each.qbRound
}
} catch {
print("oh no it broke")
}
return cell
}
}

The problem is this line in numberOfItemsInSection:
return QBHistory.count
That would be zero, so you have zero cells.
You need to move
QBHistory = try context.fetch(QB.fetchRequest())
Into viewDidLoad, so that it happens before your collection view data source query methods are called.

Related

Double direction scrolling collectionView with multiple sections data issue

I have a double direction scrolling collectionView with 50 sections, 10 items per section and 3 showing cells per section and filling the collectionView with the same data array.
the problem is the collectionView duplicate data in every section and I want to show different data in appearing sections to the user.
Any help please!
this is my code:
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 50
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: contentCellIdentifier,
for: indexPath) as! UserCollectionCell
cell.userImageView.kf.setImage(with: URL.init(string: String().loadCorrectUrl(url:firebaseUsers[indexPath.row].image)))
cell.userNameLabel.text=firebaseUsers[indexPath.row].name
if(selectedIndexPaths.contains(indexPath) ){
cell.userBackgroudView.isHidden=false
}
else{
cell.userBackgroudView.isHidden=true
}
}
return cell
}
Implement prepareForReuse in UserCollectionCell and clear the imageView and label text to prevent showing duplicate data on scroll
class UserCollectionCell: UICollectionViewCell {
override func prepareForReuse() {
super.prepareForReuse()
self.userImageView.image = nil
self.userNameLabel.text = nil
}
}
Hope it helps

UIcollectionview inside UIcollectionviewcell and how to display data

I need to create a collectionView A contains few types of cells. One of the cell contains collectionView B that can scroll horizontally. So collectionView A will scroll vertically.
Can I know how to create it and how to display the data into collectionView B?
Thanks again guys
Collection A have Cells lets call our target cell as ASubCell
then at ASubCell we will have Collection B with all of its delegate , and you will create delegate say ASubCellDelegate to send action on Collection B to ViewController of Collection A , here example
import UIKit
protocol ASubCellDelegate {
// CollectionView Cell Pressed
func onSubCellAtcolectionBPressed(_item : YourData)
}
class ASubCell: UICollectionViewCell {
#IBOutlet weak var collectionViewB : UICollectionView!
var delegate : ASubCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
// setup your Collection View B
}
}
// set up your horizontal Collection View
extension UICollectionViewCell:UICollectionViewDelegate,UICollectionViewDataSource {
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YourBCellID", for: indexPath) as! YourBCellID
return cell
}
public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if delegate != nil {
self.onSubCellAtcolectionBPressed(YourData)
}
}
}

UICollectionView cellForItem(at:) crashes

I am using Swift4 and Xcode9.
I create my collectionView cells by using the delegate method below;
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "mediaItemCell", for: indexPath) as! MediaItemCollectionViewCell
cell.mediaItemCellImageView.image = mediaPlayer?.item(at: indexPath.row)?.image
return cell
}
Then, I want to replace the image of selected cell with a "stop" image. To achieve this, I have tried to use didSelectItemAt method;
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if (mediaPlayer?.isPlaying == true) {
// stop the player
mediaPlayer?.stopPlayingMedia()
} else {
// change the image and start playing
let cell = collectionView.cellForItem(at: indexPath) as! MediaItemCollectionViewCell // CRASH
cell.mediaItemCellImageView.image = UIImage(named: "stop.png")
...
...
}
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
// restore the original image
let cell = collectionView.cellForItem(at: indexPath) as! MediaItemCollectionViewCell
cell.mediaItemCellImageView.image = mediaPlayer?.item(at: indexPath.row)?.image
// stop playing
mediaPlayer?.stopPlayingMedia()
}
Now, when I select the cell which is already selected (hence the original image has already been replaced with "stop.png") the code above works; i.e. the original image is restored, which is done by stopPlayingMedia() method.
When I select a cell different than the currently selected one, the App crashes. I tried to move the didSelectItemAt call out of the delegate method, but it did not work.
Surprisingly, the logical check if collectionView.cellForItem(at: indexPath) is MediaItemCollectionViewCell succeeds when I select the currently selected cell, and fails when I select another cell.
I want to change the image of the cell, hence need to cast the variable type but it fails. Why does to cast fail when I select a different cell than the currently selected one?
Thanks
Edit:
I use collectionView.reloadData() to restore all the images to originals (I mentioned this in the OP - when stopPlayingMedia() is invoked). It appears that, if I add a private var index:IndexItem? to my ViewController class and update its value within didSelectItemAt (to save the last selected cell) and use the code below, the code does not crash
extension ViewController:MediaPlayerControllerDelegate {
// this delegate method is invoked when stopPlayingMedia() is called
func mediaPlayerControllerDidFinishPlaying() {
// restore the UI
// collectionView.reloadData() -> this causes the crash, instead, I only restore one cell
let cell = collectionView.cellForItem(at: index!) as! MediaItemCollectionViewCell
cell.mediaItemCellImageView.image = mediaPlayer?.item(at: (index?.row)!)?.image
timeLabel.text = "00:00"
progressBar.progress = 0.0
}
}
I tried the following to create cell and changing the image inside cell on selection. Not crashing at all. Please check the implementation, It might help you.
import UIKit
class ViewController: UIViewController {
private var isPlayingModel = [false, false, false, false, false] // initially all are stop, not playing
#IBOutlet weak var collectionView: UICollectionView! {
didSet{
collectionView.delegate = self
collectionView.dataSource = self
}
}
}
extension ViewController: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return isPlayingModel.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "mediaItemCell", for: indexPath) as! MediaItemCollectionViewCell
cell.imageVw.image = isPlayingModel[indexPath.row] ? #imageLiteral(resourceName: "start") : #imageLiteral(resourceName: "stop")
return cell
}
}
extension ViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
isPlayingModel[indexPath.row] = !isPlayingModel[indexPath.row]
let cell = collectionView.cellForItem(at: indexPath) as! MediaItemCollectionViewCell
cell.imageVw.image = isPlayingModel[indexPath.row] ? #imageLiteral(resourceName: "start") : #imageLiteral(resourceName: "stop")
}
}
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.size.width, height: 60)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 4
}
}
class MediaItemCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imageVw: UIImageView!
}
Check the implementation here.
You are not passing indexPath correctly to load a cell, that's why it is crashing.Edit your didSelectItemAt: method as follows:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let selectedCell = IndexPath(item: indexPath.item, section: indexPath.section)
let cell = collectionView.cellForItem(at: selectedCell) as! ACollectionViewCell
cell.imgView.image = UIImage(named: "3.jpg")
}
Collection view indexPath has element item, and not row
Try this and see: (let me know what does it print)
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
// restore the original image
if let cell = collectionView.cellForItem(at: indexPath) as? MediaItemCollectionViewCell {
if let cellImage = mediaPlayer?.item(at: indexPath.item)?.image { // Collection view indexPath has element `item`, and not `row`
cell.mediaItemCellImageView.image = cellImage
} else {
print("cellImage not found at indexPath - \(indexPath)")
}
} else {
print("collection view cell `MediaItemCollectionViewCell` not found at indexPath -\(indexPath) ")
}
// stop playing
mediaPlayer?.stopPlayingMedia()
}

UICollectionview - prefetchItemsAt indexPaths - not being called

I'm trying to use prefetching which was introduced in iOS 10. But unable to achieve it.
I do set the delegate and enable the prefetching. But when i set a breakpoint or console log at prefetch, it does not pass through the function ever.
I know on fast scroll, the prefetching is skipped. but even on slowest scroll, its never been called
var dataSource = [IndexPath: Any]()
override func viewDidLoad() {
if #available(iOS 10.0, *) {
mainCollectionView.isPrefetchingEnabled = true
mainCollectionView.prefetchDataSource = self
}
//Other stuffs
}
//This is not being called
func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) {
print("Prefectch")
for indexPath in indexPaths {
dataSource[indexPath] = fetchDataSource(indexPath)
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) as! MyCell
cell.dataSource = dataSource[indexPath] ?? fetchDataSource(indexPath)
return cell
}
Call
override func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
self.collectionView(collectionView, prefetchItemsAt: [indexPath])
}
To trigger the prefetch, and remove:
collectionViewLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
If you have it.
This was by me the case.

How to add cell to dynamic collection view using swift

In top of that image you can see some images and plus button I want to do like this in my app so i used collection view to get this view and everything works fine but i cant add cell to my dynamic collection view can some one help me to do this process
code in my view controller:
import UIKit
import Alamofire
import SwiftyJSON
import SDWebImage
import SwiftElegantDropdownMenu
class EditPendingViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,UITextViewDelegate,UICollectionViewDelegate,UICollectionViewDataSource,UIImagePickerControllerDelegate,UINavigationControllerDelegate{
var pendingImageString:[String]!
#IBOutlet var editPendingCollectionvIEW: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return pendingImageString.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("editPendingCell", forIndexPath: indexPath) as!MypendindeditCollectionViewCell
let img:NSString = pendingImageString[indexPath.item]
cell.editImage.sd_setImageWithURL(NSURL(string: imageApikey + (img as String)))
cell.contentView.layer.borderColor = UIColor.lightGrayColor().CGColor
cell.contentView.layer.borderWidth = 1.0
return cell
}
}
I have not done any process for adding cell to my collection view i just loaded the data from the server.now help to add the cell
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return pendingImageString.count + 1 // + 1 for last cell
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell : CollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! CollectionViewCell
cell.btn.tag = indexPath.row
if indexPath.item = pendingImageString.count {
cell.imageview = //your static image that is shown in last cell
cell.cancelButton.isHidden = true
}
else{
let img:NSString = pendingImageString[indexPath.item]
cell.editImage.sd_setImageWithURL(NSURL(string: imageApikey + (img as String)))
cell.cancelButton.isHidden = false
}
}
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
if indexPath.item = pendingImageString.count{
// update your array with new image file
}
}
// cancel button action
func buttonClicked(sender: UIButton?) {
let tag = sender.tag
// remove object from array and reload collectionview
}
On click of last cell of the collection view add logic to enter your product in the database then just reload the collection view
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.row == pendingImageString.count - 1
{
//TODO - add item to database and reload collectionview
}
}

Resources