Calling the method reloadData() - ios

My app includes two collectionViews , mainCollectionView and nestedCollectionView which is in the mainCollectionViewCell .
It's like the iPhone calendar app , each cell in the mainCollectionView has nestedCollectionView which represents a month(the number of the cells will be the number of the month days).
class cell_Main:UICollectionViewCell{
let collectionView:UICollectionView = {
let cv = nestedCollectionView()
cv.backgroundColor = .white
return cv
}()
to update the nestedcollectionView if the month changes , I"ve used nestedcollectionView.reloadData() inside the method(which belongs to mainCollectionView ):
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell_main", for: indexPath) as! cell_Main
let nested_CollectionView = cell.collectionView as! nestedCollectionView
.
.
.
nested_CollectionView.reloadData()
}
! if I scroll the mainCollectionView, the nestedCollectionView supposed to be updated (the month will be changed).
my question: the code works fine , but is it the right way to reloadData() here?, does it an expensive CPU work, does the app use too much CPU?

instead of using nested Collection View which represent month in a year , I've tried to make one Main CollectionView , and the number of sections will be 12 (the months number) , each section represent month and in each section the numberOfItemsInSection will be the month days number . and any updation can be here(without using reloadData()):
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
}
.finally when we scroll down to the end section we would call reloadData() to update the new numberOfSections and move to the next year .

Related

UICollectionView loads more cells other than visible ones

I have a UICollectionView, which has 2k+ records. At anytime only 6-7 rows will be visible and I'm using reusable cells. Everything works fine.
But when I make a console log in cellForRowAtIndexPath, initially 80+ rows are being loaded. After that it loads 1st 7 rows again, and properly loads only the visible cells.
Why does it load 80+ rows initially. This make a slight lag in initial loading.
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return results.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
print("Cell For Row -> \(indexPath)")
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ResultCell", for: indexPath) as! ResultCell
cell.data = result[indexPath.item]
return cell
}
UPDATE:
I was using auto-sizing cells. So I did define estimatedItemSize as UICollectionViewFlowLayoutAutomaticSize
I tried defining a proper CGSize instead of UICollectionViewFlowLayoutAutomaticSize. And the extra cells stopped loading.
While performing autosizing cells, we give estimatedItemSize.
On using UICollectionViewFlowLayoutAutomaticSize for estimatedItemSize, the collectionview tries to load a countable number of cells (visible and non-visible) and get the estimated size.
If a proper CGSize (estimated) is given, the extra cells(non-visible) would be loaded less. So, the closer your estimated size is, the lesser non-visible cells are loaded.

How to create tag fileds in iOS

How can I create a tag fields like the below attached screenshot in iOS.
tag text shall be taken from the user input.
Swift 3 Xcode 8.3.2
Its easy. No need to use any framework for this, You can create your own view.
Suppose you have a ViewController on which you want to add skills for particular user. So on that view you will be having one TextField to accept the skill name and a collectionView to show all the skills entered by the user.Check image for more clear view.
Create skills array which you need to pass to your collectionView delegate methods.
var skillArray = [String]()
Now whenever you add anything inside your textfield and on press of return button on keyboard you need to add that skill name in your skills array and reload your collectionView.
skillArray.append(textField.text)
collectionView.reloadData()
Next add collectionview methods:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.skillArray.count
}
// make a cell for each cell index path
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let skillCell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath as IndexPath) as! SkillCollectionViewCell
skillCell.skillLabel.text = skillArray[indexPath.row]
skillCell.deleteAction = {
self.skillArray.remove(at: indexPath.row)
self.collectionView.reloadData()
}
return skillCell
}
Final step is to add collectionViewFlowLayout methods.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// handle tap events
print("You selected cell #\(indexPath.item)!")
}
func collectionView(_ collectionView: UICollectionView,layout collectionViewLayout: UICollectionViewLayout,sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize{
let widthText = self.skillArray[indexPath.item]
let font = UIFont(name: "Helvetica", size:18)
let fontAttributes = [NSFontAttributeName: font] // it says name, but a UIFont works
let myText = widthText
let size = (myText as NSString).size(attributes: fontAttributes)
return CGSize(width: size.width+28, height:30)
}
You can use more Designs with using user input and handling the tag by using cell index of collection view for more designs follow the link -
https://www.cocoacontrols.com/search?q=flowlayout
I recommend UICollectionView to implement Tags. It's less code, less overhead and easy to implement.
Follow this link for guidance :
https://codentrick.com/create-a-tag-flow-layout-with-uicollectionview/
This is how it looks like. Please note it is flexible too.
Hope this will help you

Swift - separate views have subviews that are sharing the same memory?

new to swift. I have a nested CollectionView from one viewcontroller. The main viewcontroller has 7 collectionviewcell ("Level1Cell" in the code below). Each time I click a button or trigger an event, I want the collectionView to reload with the new data.
func eventHandler() {
// updates data
myCollectionView.reloadData()
}
Then, after it calls reload, it will call the reload again on each of the the nested CollectionViewCell.
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Level1Cell", for: indexPath) as! Level1Cell
cell.appsCollectionView.reloadData()
return cell
}
The problem is, let say I want to, for the first cell, set a particular row some text.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if(self.index == 0 && indexPath.row == 30){
rightCell.textLabel.text = "asdasd"
}
The fourth "Level1Cell" cell somehow has its label set also at the 30th row, but not the second and third. After stepping through the debugger, I realize that the cells, after reloading, the fourth cell "Level1Cell" is set to have the the same memory address as the first cell ( why does reload do this - shouldn't it allocate a new memory for each "Level1Cell"? - how can I get around this). Also, should I not use reload to update the data in the view and nested view of those from the view controller?
Thanks!
UIcollectionview will reuse cells. You must provide needed data for row in method
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
Or just clear previous data at cell.

UITableView in UICollectionView misbehaving

I have put UITableView in UICollectionView, and it has 4 items, but when I scroll UICollectionView to the last item, it shows the content of the first UITableView ( So when I press option 3 button it scrolls to the last item of collectionView but the content is wrong ) . You can have a look at the below picture.
Below is the link to my project, please help me out with this issue.
Link to my project
You have to reload the UITableView in cellForItemAt as mentioned below.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TableCollectionCell", for: indexPath) as! TableCollectionCell
cell.tableView.tag = indexPath.item
cell.tableView.reloadData()
return cell
}

How to manage two different cells in a collection view

This is a really basic wireframe of what I'm trying to achieve:
This is what I currently have in Xcode, resulting in 3 cells per row, with no space in between. The date label cell isn't showing up because I don't know how to get cellForItem to recognize it along with the post cells (hence the question):
I have two separate cell classes - one for the date labels and one for the rows of images.
My collection view methods are as follows:
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", for: indexPath) as! PostCell
let dateCell = collectionView.dequeueReusableCell(withReuseIdentifier: "dateLabelCell", for: indexPath) as! DateLabelCell
cell.postImage.loadImageUsingCacheWithUrlString(posts[indexPath.row].pathToImage)
cell.postID = posts[indexPath.row].postID
cell.postImage.contentMode = UIViewContentMode.scaleAspectFill
// Here I'll have to get the date and have the labels display the days of the week properly
dateCell.dateLabel.text = "Monday"
return cell
}
But I'm not sure how to manage both cells in the above methods. I'll have to sort the posts by a timestamp so things posted on a certain day get added to the correct day's row, but that's something I'll do another day - for now I'm just wondering how I can get the UI laid out so that the collection view shows a date label, then a row of post cells, and repeat.
Thanks for any advice!

Resources