passing data from model to collectionViewCell - swift

I have several custom cells that are applied through this method
switch indexPath.row {
case 1:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "randomCell", for: indexPath)
as? randomCollectionViewCell
case 2:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "timeCell", for: indexPath)
as? timeCollectionViewCell
case 3:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ownerCell", for: indexPath)
as? ownerCollectionViewCell
default:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath)
as? imageModelCollectionViewCell
}
return cell
}
All cells are displayed simultaneously and sequentially. The last cell that is in the default function is the imageView which I need to pass the value from the model.
The model creates the image as a link, so you also need to upload a picture.
For example this code on like
cell.Image Model.image = ...
throws an error
Value of type 'UICollectionViewCell?'has no member 'modelimage'
This is code from collectionViewCell for what i need to passing data
import UIKit
class imageModelCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var modelImage: UIImageView!
}
How transfer data from model to cell?
//update
i am updating my code by Saleh Altahini post
thank you, I try to implement the second method.
i use var imageModelCell: imageModelCollectionViewCell?
and use method
DispatchQueue.main.async {
self.collectionView.reloadData()
imageModelCell!.modelImage = UIImage(data: data) as imageModelCollectionViewCell }
and have an error
Cannot convert value of type 'UIImage?' to type 'imageModelCollectionViewCell' in coercion

The error you're getting means that your cell is not downcasted to imageModelCollectionViewCell. Maybe you're not referencing the cell correctly?
Anyway, you can setup the cell in two ways.
first method is to setup your cell in the cellForItemAt function like this:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath) as! imageModelCollectionViewCell
cell.modelImage.image = //Your Image
return cell
}
Or you can reference your cell at the beginning and set it up later from anywhere else. Just add a variable like var imageModelCell: imageModelCollectionViewCell to the UICollectionViewDataSource and pass the cell in the cellForItemAt like this:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath) as! imageModelCollectionViewCell
self.imageModelCell = cell
return cell
}
you can then just use imageModelCell.modelImage = //Your Image from any other function or callback
A side note: it's a good practice to start the name of your classes with a capital letter and variables with a small letter, so you can better differentiate what you're calling or referencing with Xcode. Maybe consider changing the name of you class to ImageModelCollectionViewCell.

Related

How to call More than one CollectionView in collection View data Source on table view cell

I have 2 collection view in table view cells and each collection view has Outlet in own table view cell . how i can call and use this two collection view in cellForItemAt method in view controller.
if (collectionView == self.amazing_Collection) // doesnt work
this is table view methods in view controller
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let section = indexPath.section
if section == 0 {
let cell0 = tableView.dequeueReusableCell(withIdentifier: "searchCell", for: indexPath) as! searchCell
return cell0
}else if section == 1 {
let cell1 = tableView.dequeueReusableCell(withIdentifier: "slideCell", for: indexPath) as! slideCell
return cell0
and this is collection view method for fill image and labels
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier:
"amazingCollecionCell", for: indexPath) as! amazingCollecionCell
////this is work correctly
return cell
return cell
//here iwant to say if this collection view execute under lines
let cell_Just_Here = collectionView.dequeueReusableCell(withReuseIdentifier: "justhereproductscell", for: indexPath) as! JustHereProductsCell
//lable fill
return cell_Just_Here
}
}
When tableview's data source method is called, set the collection view's tag value as indexPath.row(cell's index path). By this in the collection view's datasource method you will be able to identify the collection view with the tag value and set the cells accordingly.
Hope this helps.

Divide the number of cell between two prototypes

as I am beginner I have a problem that may not be so pro to ask.
I have two prototype collection view cell in my app, let's call them Cell1 and Cell2, they both are in a same section.
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell1", for: indexPath) as? customCell {
return cell
} else if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell2", for: indexPath) as? customCell {
return cell
}
return UICollectionViewCell()
}
My problems starts from here:
in numberOfItemsInSection, I want to say for example draw 3 cell from prototype Cell1 and 5 cell from Cell2.
I don't know how I divide the number of cell between two prototypes, could anyone help me on that?
You can try
override func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return 8
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if (0...2).contains(indexPath.item) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell1", for: indexPath) as! customCell {
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell2", for: indexPath) as? customCell {
return cell
}
}
you have several options for this. If you know how many cells you will be having, lets say 8 you can just do a simple switch.
switch indexPath.item {
case 0,1,2,3:
let cell = .....
return cell
case 4,5,6,7:
let cell2 = ....
return cell
default:
let cell = ...
return cell
}
you can also do a modulo approach, which will give you cell1 for even item numbers and cell2 for uneven.
Without knowing your intentions directly, I can give you only a broad answer.

Unable to access collectionView cell variables using global variable

Here i made a collectionView cell variable for accessing both objects. But unable to access the objects inside the cell variable
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
var cell: UICollectionViewCell!
if collectionView == collectionView1 {
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellAttachment", for: indexPath) as! AttachmentCell
cell.imgAttachment.image = imageArray1[indexPath.row]
cell.delegate = self
}
else if collectionView == collectionView2 {
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellAttachmentView", for: indexPath) as! AttachmentViewCell
cell.imgFileIcon.image = imgArray2[indexPath.row].fileIcon
}
return cell
Value of type 'UICollectionViewCell?' has no member 'imgAttachment'
The problem lies here.
var cell: UICollectionViewCell!
You have declared the cell to be of type UICollectionViewCell. So, no matter which subclass you store inside it, you cell will only be of type UICollectionViewCell.
You should change it like this,
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView === collectionView1 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellAttachment", for: indexPath) as! AttachmentCell
cell.imgAttachment.image = imageArray1[indexPath.row]
cell.delegate = self
return cell
} else if collectionView === collectionView2 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellAttachmentView", for: indexPath) as! AttachmentViewCell
cell.imgFileIcon.image = imgArray2[indexPath.row].fileIcon
return cell
} else {
// Return the proper cell for other cases
}
}
Or, if you are adamant you need only a single return statement at the end of the delegate, then you could do it like this,
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
var yourCell: UICollectionViewCell!
if collectionView === collectionView1 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellAttachment", for: indexPath) as! AttachmentCell
cell.imgAttachment.image = imageArray1[indexPath.row]
cell.delegate = self
yourCell = cell
} else if collectionView === collectionView2 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellAttachmentView", for: indexPath) as! AttachmentViewCell
cell.imgFileIcon.image = imgArray2[indexPath.row].fileIcon
yourCell = cell
} else {
// Return the proper cell for other cases
}
return yourCell
}
You need to silent the compiler by casting the cell as AttachmentCell. See the below example,
(cell as! AttachmentCell).imgAttachment.image = imageArray1[indexPath.row]
(cell as! AttachmentCell).delegate = self
The reason compiler is not able to recognize the variable is the declaration of variable cell as UICollectionViewCell. As there is no imgAttachment variable in UICollectionViewCell so compiler will complain.

Reloading Collection View when returning to previous View Controller

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! LevelSelectCVC
cell.imageView?.image = imageArray[indexPath.row]
if indexPath.item >= stageProgress {
cell.imageView?.image = UIImage(named: "Lock Icon Grey")
} else {
cell.imageView?.image = imageArray[indexPath.item]
}
return cell
}
In this function I check the value of the integer stageProgress and add the same amount of images from an UIImage array to the collection view cells. The remaining of the cells adds a default UIImage. After returning from another view controller I have to check the stageProgress and add another UIImage from the array.
Does anyone know how I can do this? I have tried to do:
self.CollectionView.reloadData()
In both ViewDidAppear and PrepareForSegue
If I restart the game collectionView updates.
Calling ViewDidLoad() in ViewDidAppear resolved the issue.

Why are image views sometimes not appearing in collection view cells?

I just updated to Swift 3.
My collection views were working great before the update. I did the recommended changes to make the compiler happy, but now I'm having this problem.
Image views that are in my custom UICollectionViewCells are simply not appearing anymore. Neither programmatically generated image views nor prototype image views are appearing.
I've given the image views background colors to check if my images are nil. The background colors aren't appearing, so it is safe to assume the image views are not appearing at all.
The cells themselves ARE appearing. Each image view has a label underneath, and the label is displaying properly with the correct text.
The most confusing part is that sometimes the image views DO appear, but there seems to be no rhyme or reason as to why or when.
My code is pretty standard, but I'll go ahead and share it anyway:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return searchClubs.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: HomeCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! HomeCollectionViewCell
cell.barLabel.text = searchClubs[indexPath.row].name
cell.imageCell.image = searchClubs[indexPath.row].image
cell.imageCell.layer.masksToBounds = true
cell.imageCell.layer.cornerRadius = cell.imageCell.frame.height / 2
return cell
}
func feedSearchClubs(child: AnyObject) {
let name = child.value(forKey: "Name") as! String
//Image
let base64EncodedString = child.value(forKey: "Image")!
let imageData = NSData(base64Encoded: base64EncodedString as! String, options: NSData.Base64DecodingOptions.ignoreUnknownCharacters)
let image = UIImage(data:imageData! as Data)
//Populate clubs array
let club = Club.init(name: name, image: image!)
self.searchClubs.append(club)
DispatchQueue.main.async {
self.collectionView.reloadData()
}
}
Since Xcode 8 you have to call layoutIfNeeded() to calculate size (in your case you need to know cell.imageCell.frame.height) and position from auto layout rules or use a fixed value of cornerRadius.
cell.imageCell.layoutIfNeeded()
cell.imageCell.layer.masksToBounds = true
cell.imageCell.layer.cornerRadius = cell.imageCell.frame.height / 2
OR
cell.imageCell.layer.masksToBounds = true
cell.imageCell.layer.cornerRadius = 5
The imageCell's frame isn't set up ready yet in the cellForItemAt method.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: HomeCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! HomeCollectionViewCell
cell.barLabel.text = searchClubs[indexPath.row].name
cell.imageCell.image = searchClubs[indexPath.row].image
return cell
}
Instead put the setting up of layer on willDisplay since cell.imageCell.frame.height will have its value.
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
let cell: HomeCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! HomeCollectionViewCell
cell.imageCell.layer.masksToBounds = true
cell.imageCell.layer.cornerRadius = cell.imageCell.frame.height / 2
}