Remove item from array in UITableview - arrays

What I'm trying to accomplish is when user selects an element for UITableView this element gets append to servicioSeleccionadoarray. But I'm stuck in this because if user decides to deselect the cell I want to remove that item from the array. I've try anyarray.remove(at:)but I can figure the way to tapp into that index.
This is my code so far.
class ServicioHogarViewController: UIViewController{
let serviciosHogar = [String](arrayLiteral: "Alfombras", "Muebles Madera", "Sillones", "Marmol", "Aplicación Teflón","Vestiduras", "Salas", "Colchones", "Sillas Oficinas")
#IBOutlet weak var servicioHogarTB1: UITableView!
var selectedIndex : Int? = nil
var servicioSeleccionado : [String] = []
#IBAction func doneButton(_ sender: UIButton) {
performSegue(withIdentifier: "datePick2", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
servicioHogarTB1.delegate = self
servicioHogarTB1.dataSource = self
servicioHogarTB1.register(UINib(nibName: "ServicioHogarCell", bundle: nil), forCellReuseIdentifier: "servicioCell1")
servicioHogarTB1.separatorStyle = .none
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
print(servicioSeleccionado)
}
}
// MARK : UITabeView Delegation
extension ServicioHogarViewController : UITableViewDelegate, UITableViewDataSource{
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return serviciosHogar.count
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView.cellForRow(at: indexPath)?.accessoryType == .checkmark {
tableView.cellForRow(at: indexPath)?.accessoryType = .none
} else {
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
if tableView.cellForRow(at: indexPath)?.accessoryType == .checkmark {
servicioSeleccionado.append(serviciosHogar[indexPath.row])
print(servicioSeleccionado)
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "servicioCell1", for: indexPath) as! ServicioHogarCell
let servicio = serviciosHogar[indexPath.row]
cell.servicioLabel.text = servicio
return cell
}
}

If you have an array :
var cast = ["Vivien", "Marlon", "Kim", "Karl"]
and you want to remove "Marlon" from it, you can find the index of Marlon using the func firstIndex(of: Element) -> Int? method for an array and then remove it like so :
if let index = cast.firstIndex(of: "Marlon"){
cast.remove(at: index)
print(cast)
}
That said, on didSelectRowAt run this function for your array and you'll accomplish what you're looking to.

Related

How to implement userDefaults with a Global Variable array

I have an empty array set as a global variable that is populated with array items from a tableview. This is used to populate another tableview. This data needs to persist so that when the user returns to the app, their tableview data is in the same state they left it, i.e. populate with data from the array.
Though I've looked for dozens of tutorials and examples. I've also hacked at it myself to make it work and every time I reload the app, the array is empty. How can I get that global variable array to hold onto it's array data?
var sharedData = [String]()
This is my 1st VC where I have setup functions for the UserDefaults. And I've executed my saveArray() func every time a change is made to the array. I've then executed retrieveArray() func every time I need to load from the array.
import UIKit
var sharedData = [String]()
struct Keys {
static let arrayKey = "arrayKey"
}
let defaults = UserDefaults.standard
func saveArray() {
defaults.set(sharedData, forKey: Keys.arrayKey)
}
func retrieveArray() {
var savedData = defaults.object(forKey: Keys.arrayKey) as? [String] ?? []
savedData.append(contentsOf: sharedData)
}
class ViewController: UIViewController {
var effect:UIVisualEffect!
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet var tableView: UITableView!
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
#IBOutlet weak var visualEffectView: UIVisualEffectView!
let materialData = ["One", "Two", "Three", "Four"]
var searchMaterial = [String]()
var searching = false
#IBAction func favoritesButtonArrayUpdate(_ sender: UIBarButtonItem) {
print(sharedData)
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
saveArray()
retrieveArray()
print(sharedData)
}
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
print(self.materialData[indexPath.row], "selected!")
}
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let favorite = UITableViewRowAction(style: .default, title: "Favorite") { (action, indexPath) in
var data: String
if self.searching {
data = self.searchMaterial[indexPath.row]
} else {
data = self.materialData[indexPath.row]
}
sharedData.append(data)
saveArray()
print(sharedData)
}
favorite.backgroundColor = UIColor.orange
return [favorite]
}
}
This is my 2nd VC which displays the array data stored in the global variable array sharedData. I've again added all the func when making changes to the array and pulling data from the array.
import UIKit
class FavoritesViewController: UIViewController {
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
saveArray()
retrieveArray()
}
}
extension FavoritesViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
retrieveArray()
return sharedData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
retrieveArray()
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.numberOfLines = 0
cell.textLabel?.text = sharedData[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
sharedData.remove(at: indexPath.row)
saveArray()
tableView.beginUpdates()
tableView.deleteRows(at: [indexPath], with: .automatic)
tableView.endUpdates()
}
}
}
The problem could be here:
let savedData: [String] = userDefaults.object(forKey: "arrayKey") as? [String] ?? []
Try changing it with:
let savedData: [String] = userDefaults?.object(forKey: "arrayKey") as? [String] ?? []
This is because UserDefaults must be unwrapped to refer to member object. Give it a try
Based on MrHim recommendations I removed the saveArray and retrieveArray func from the viewDidLoad of my first VC and left retrieveArray in viewDidLoad of my second VC. Having saveArray in my viewDidLoads was overwriting the array with empty data. I then needed to retrieve the array data in the proper place in my second VC. Then in my numberOfRowsInSection I removed retrieveArray.

Why i cant append my custom object to array?

so first i made a custom object :
import Foundation
class Website {
var name:String
var pictureLabel:String
init(title:String,pictureLabel:String) {
name = title
pictureLabel = picture
}
}
and then on my tableviewcontroller class :
class ViewController:
UIViewController,UITableViewDelegate,UITableViewDataSource {
var websites = [Website]()
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
tableView.rowHeight = 80
tableView.register(MyCell.self, forCellReuseIdentifier: "MyCell")
websites.append(Website(title: "facebook.com", pictureLabel: "facelogo"))
print(websites)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return websites.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! MyCell
cell.label.text = websites[indexPath.row].name
return cell }
error : Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file
the problem was on that line
tableView.register(MyCell.self, forCellReuseIdentifier: "MyCell")
it should be
tableView.register(UINib(nibName: "MyCell", bundle: nil), forCellReuseIdentifier: "MyCell")`

Populating an UITableview from a struct

I have two viewControllers one called programlist that displays the list of tiles and populates a a suitable view.
the second viewController inputs the data. Issues implementing the callback due to an error in the prepareForsegue function. Getting the error "Instance member 'callback' cannot be used on type 'addWorkout'"
viewController 1 aka Programlist:
import UIKit
struct Item: Codable {
var title: String
var others: [String]
}
class ProgramList: UIViewController, UITableViewDataSource, UITableViewDelegate{
var Programs = [Item]()
#IBOutlet weak var programTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
load()
}
//saving current state of programs array
func save() {
guard let data = try? JSONEncoder().encode(Programs) else { return }
UserDefaults.standard.set(data, forKey: "notes")
}
//loading saved program array
func load() {
guard let loadedData = UserDefaults.standard.data(forKey: "notes") else { return }
do {
Programs = try JSONDecoder().decode([Item].self, from: loadedData)
programTableView.reloadData()
} catch { print(error) }
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Programs.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
cell.programTitle.text = Programs[indexPath.row].title
return cell
}
//Removing Item by swipping left & saving this newly established array
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCell.EditingStyle.delete {
Programs.remove(at: indexPath.row)
programTableView.reloadData()
save()
}
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toAddPage"{
workoutController.callback = { [weak self] string in
let entered = Item(title: string, others: ["hi"])
self?.programs.append(entered)
let indexPath = IndexPath(row: self?.programs.count - 1, section: 0)
self?.tableView.insertRows(at: [indexPath], with: .automatic)
self?.save()
}
}
}
}
}
}
viewController 2 aka addWorkout:
import UIKit
class addWorkout: UIViewController {
#IBOutlet weak var workoutTitle: UITextField!
var callback : ((String) -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func saveWorkoutTitle(_ sender: Any) {
if !workoutTitle.text!.isEmpty {
callback?(workoutTitle.text!)
}
}
}
The main mistake is you are trying to save an array of Item – which is not supported anyway – to UserDefaults and read an array of String. That's a clear type mismatch.
To be able to save an array of a custom struct to UserDefaults adopt Codable to save the struct as JSON.
struct Item : Codable {
var title: String
var others: [String]
}
Further it's a very bad practice to declare a data source array outside of any class.
This is the ProgramList class with adjusted load and save methods and the data source array inside the class. The method viewDidAppear is not needed.
class ProgramList: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var programTableView: UITableView!
var programs = [Item]()
override func viewDidLoad() {
super.viewDidLoad()
load()
}
//saving current state of programs array
func save() {
guard let data = try? JSONEncoder().encode(programs) else { return }
UserDefaults.standard.set(data, forKey: "notes")
}
//loading saved program array
func load() {
guard let loadedData = UserDefaults.standard.data(forKey: "notes") else { return }
do {
programs = try JSONDecoder().decode([Item].self, from: loadedData)
programTableView.reloadData()
} catch { print(error) }
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return programs.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
cell.programTitle.text = programs[indexPath.row].title
return cell
}
//Removing Item by swipping left & saving this newly established array
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
programs.remove(at: indexPath.row)
programTableView.deleteRows(at: [indexPath], with: .automatic)
save()
}
}
}
To share data between controllers use a closure as callback and pass the string
class AddWorkout: UIViewController {
#IBOutlet weak var workoutTitle: UITextField!
var callback : ((String) -> Void)?
#IBAction func saveWorkoutTitle(_ sender: Any) {
if !workoutTitle.text!.isEmpty {
callback?(workoutTitle.text!)
}
}
}
Back in ProgramList controller assign a closure to the callback property in prepareForSegue (or right before presenting the controller)
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toAddPage" {
let workoutController = segue.destination as! AddWorkout
workoutController.callback = { string in
let entered = Item(title: string, others: ["hi"])
self.programs.append(entered)
let indexPath = IndexPath(row: self.programs.count - 1, section: 0)
self.tableView.insertRows(at: [indexPath], with: .automatic)
self.save()
}
}
}

Passing selected String in uiTableView from Array to uiLabel in new ViewController

I have my array, my tableview setup and the table shows the array of strings. 80+ strings in an array.
Now, I select a row, and obviously I want to pass the string in that row to a uiLabel in a secondary ViewController.
placeTypes is my declared array that is not in this posted code, just imagine an array with 84 strings! My segueIdentifier is A <- easy peasy. And passedString is the uiLabel that will receive the ..well...passed string data.
TableView code
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return placeTypes.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = placeTypes[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
NSLog("You selected cell number: \(indexPath.row)!")
performSegue(withIdentifier: "A", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "A" {
// let viewController = segue.destination as? ViewController
// SOMEHOW PASS THE SELECTED STRING IN THE SELECTED ROW TO THE VIEW CONTROLLER
}
}
Okay and now my ViewController code
#IBOutlet weak var passedString: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
EDIT: I am still getting errors. With the updated prepare for segue I get use of unresolved Identifier for placeTypes[indexPath.row] and viewController is telling me there is no sendString variable.
class TableViewController: UITableViewController {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Row number: \(indexPath.row)")
performSegue(withIdentifier: "A", sender: indexPath)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "A" {
if let viewController = segue.destination as ViewController,
let indexPath = sender as IndexPath {
viewController.sendString = placeTypes[indexPath.row]
}
}
}
}
class ViewController : UIViewController {
#IBOutlet weak var passedString: UILabel!
// Put the string you need to send in a separate var
// You can't rely on the view controller being properly initalized
var sendString: String?
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let sendString = sendString {
passedString.text = sendString
}
}
}
You can also take a look at legendary-potato: https://github.com/ryantxr/legendary-potato
In did didSelectRowAt pass indexPath as sender and in prepare you can cast it to IndexPath. Try this.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
NSLog("You selected cell number: \(indexPath.row)!")
performSegue(withIdentifier: "A", sender: indexPath)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "A" {
let indexPath = sender as? IndexPath {
let yourText = placeTypes[indexPath.row]
// let viewController = segue.destination as? ViewController
// SOMEHOW PASS THE SELECTED STRING IN THE SELECTED ROW TO THE VIEW CONTROLLER
}
}
}

Swift: How to Display Parsed JSON Data in CollectionView inside a TableView?

I'm trying to display my data as this image.
My problem is that data displayed inside table view rows are all the same thing, while it should display all data of the array.
This is the code I used to display the collectionView inside the tableView:
var onlineNews = ["local", "Economy", "Variety", "international", "sport"]
var storedOffsets = [Int: CGFloat]()
var tableIndexPath: IndexPath!
#IBOutlet var listTableView: UITableView!
var tableIndex: Int = 0
var categoryResults = [JSON]() {
didSet {
listTableView.reloadData()
}
}
let requestManager = RequestManager()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
for i in onlineNews {
requestManager.categoryList(sectionName: i)
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return onlineNews.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell", for: indexPath) as! NewsTableViewCell
tableIndex = indexPath.row
return cell
}
func tableView(_ tableView: UITableView,
willDisplay cell: UITableViewCell,
forRowAt indexPath: IndexPath) {
guard let tableViewCell = cell as? NewsTableViewCell else { return }
tableViewCell.setCollectionViewDataSourceDelegate(dataSourceDelegate: self, forRow: (indexPath as NSIndexPath).row)
tableViewCell.collectionViewOffset = storedOffsets[(indexPath as NSIndexPath).row] ?? 0
}
func tableView(_ tableView: UITableView,
didEndDisplaying cell: UITableViewCell,
forRowAt indexPath: IndexPath) {
guard let tableViewCell = cell as? NewsTableViewCell else { return }
storedOffsets[(indexPath as NSIndexPath).row] = tableViewCell.collectionViewOffset
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return categoryResults.count
}
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ColCell",
for: indexPath) as! NewsCollectionViewCell
cell.contentType.text = categoryResults[indexPath.row]["ContentType"].stringValue **// This is where I get the same values for all table view rows**
cell.sectionName.text = onlineNews[tableIndex]
return cell
}
I'm sure someone can absolutely help me with this as I know that it takes only a small tweak to make it work, but not sure where.
Update:
I have followed a way that I believe should work, which is to declare the JSON array to be like this [[JSON]], and then use categoryResults[collection.tag][indexPath.item]["ContentType"].stringValue to get to the value. However, it gives me "index out of range" message. Do you have any clue how can I solve the issue?
var onlineNews = ["local", "Economy", "Variety", "international", "sport"]
var storedOffsets = [Int: CGFloat]()
#IBOutlet var listTableView: UITableView!
var tableIndex: Int = 0
var categoryResults = [[JSON]]() { // updated
didSet {
listTableView.reloadData()
}
}
let requestManager = RequestManager()
override func viewDidLoad() {
super.viewDidLoad()
requestManager.resetCategory()
updateSearchResults()
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.updateSearchResults), name: NSNotification.Name(rawValue: "categoryResultsUpdated"), object: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
for i in 0..<onlineNews.count {
requestManager.categoryList(sectionName: onlineNews[i])
}
}
func updateSearchResults() {
categoryResults = [requestManager.categoryResults] // updated
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return onlineNews.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell", for: indexPath) as! NewsTableViewCell
tableIndex = indexPath.row
return cell
}
func tableView(_ tableView: UITableView,
willDisplay cell: UITableViewCell,
forRowAt indexPath: IndexPath) {
guard let tableViewCell = cell as? NewsTableViewCell else { return }
tableViewCell.setCollectionViewDataSourceDelegate(dataSourceDelegate: self, forRow: (indexPath as NSIndexPath).row)
tableViewCell.collectionViewOffset = storedOffsets[(indexPath as NSIndexPath).row] ?? 0
}
func tableView(_ tableView: UITableView,
didEndDisplaying cell: UITableViewCell,
forRowAt indexPath: IndexPath) {
guard let tableViewCell = cell as? NewsTableViewCell else { return }
storedOffsets[(indexPath as NSIndexPath).row] = tableViewCell.collectionViewOffset
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return categoryResults[collectionView.tag].count // updated
}
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ColCell",
for: indexPath) as! NewsCollectionViewCell
cell.contentType.text = categoryResults[collectionView.tag][indexPath.row]["ContentType"].stringValue // updated
return cell
}
This the content of RequestManager class (where I call the API):
var categoryResults = [JSON]()
func categoryList(sectionName: String) {
let url = "http://mobile.example.com/api/Content?MobileRequest=GetCategoryNews&PageNo=1&RowsPerPage=10&Category=\(sectionName)&IssueID=0&Type=online"
print("this is the url \(url)")
Alamofire.request(url, method: .get).responseJSON{ response in
if let results = response.result.value as? [String:AnyObject] {
let items = JSON(results["Data"]?["OnlineCategoryNews"]! as Any).arrayValue
self.categoryResults += items
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "categoryResultsUpdated"), object: nil)
}
}
}
func resetCategory() {
categoryResults = []
}
deinit {
NotificationCenter.default.removeObserver(self)
}
Update 2:
And here is the method where the collectionView.tag is assigned. This is added to the tableViewCell class:
func setCollectionViewDataSourceDelegate
<D: protocol<UICollectionViewDataSource, UICollectionViewDelegate>>
(dataSourceDelegate: D, forRow row: Int) {
collectionView.delegate = dataSourceDelegate
collectionView.dataSource = dataSourceDelegate
collectionView.tag = row
collectionView.bounds.size.width = self.bounds.size.width
collectionView.reloadData()
}
Collection view delegate methods don't know context of their collection view. You should calculate onlineNews index depending on the collectionView instance instead of using indexPath.row, which is internal collection view index path.
Edit: better option (to avoid scrolling and layout issues) is to use single collection view, where cells are grouped in rows. If you don't want to make layout manager, you can achieve such layout by adding small, but very wide separator views between sections
Edit2:
cell.contentType.text = categoryResults[indexPath.row]["ContentType"].stringValue
uses local indexPath of this collection view. You could assign tag to tableViewCell.collectionView with a value of desired categoryResults index. Then you can use this tag as in categoryResults[collectionView.tag]

Resources