UICollectionView showing unloaded xib and not updating the content inside using swift - ios

I have a collection view which is loaded from a .xib file. When the view opens sometimes the collection view will have loaded the content and other times it does not load any content into the cell causing just the .xib to be shown. Other times the .xib doesn't even show either. However, I don't understand why this is happening. When clicking on the cell, a new viewController opens with a detailed view which has the content loaded so the cell obviously knows what is suppose to be shown.
var currentUser: User!
var listCategories: [String] = ["Friends Lists", "Friends", "People"]
var lists = [Media]()
in viewDidLoad:
collectionView.register(UINib(nibName: "ListCell2.0", bundle: nil), forCellWithReuseIdentifier: Storyboard.listCell)
collectionView.reloadData()
observeMedia()
observeMedia():
func observeMedia() {
Media.observeNewMedia { (media) in
if !self.lists.contains(media) {
self.lists.insert(media, at: 0)
self.collectionView.reloadData()
}
}
}
viewWillAppear:
override func viewWillAppear(_ animated: Bool) {
observeMedia()
}
collectionView Methods:
extension HomeViewController
{
func numberOfSections(in collectionView: UICollectionView) -> Int {
return listCategories.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0 {
return lists.count
}else{
return 0
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Storyboard.listCell, for: indexPath) as! ListCell
cell.layer.applySketchShadow(color: UIColor.black, alpha: 0.08, x: 0, y: 0, blur: 10, spread: 0)
cell.layer.cornerRadius = 20
cell.layer.masksToBounds = false
cell.currentUser = self.currentUser
cell.media = self.lists[indexPath.item]
cell.mainView.setGradientBackground(colours: self.getColourFromTag(tag: self.lists[indexPath.item].tag))
return cell
}
//section header view
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView
{
let sectionHeaderView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: Storyboard.sectionHeader, for: indexPath) as! SectionHeaderView
let category = listCategories[indexPath.section]
sectionHeaderView.sectionTitle = category
return sectionHeaderView
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.performSegue(withIdentifier: Storyboard.showListDetailSegue, sender: nil)
}
the CollectionView Cell
import UIKit
import Foundation
import SAMCache
class ListCell: UICollectionViewCell {
#IBOutlet weak var nameView: UIView!
#IBOutlet weak var mainView: UIView!
#IBOutlet weak var nameButton: UIButton!
#IBOutlet weak var profileImageView: UIImageView!
//#IBOutlet weak var tagLabel: UILabel!
#IBOutlet weak var dateLabel: UILabel!
#IBOutlet weak var listTitle: UILabel!
#IBOutlet weak var boughtLabel: UILabel!
#IBOutlet weak var boughtProgress: UIProgressView!
var numOfItems = 0
var numOfBought = 0
var counter: Double = 0{
didSet{
boughtProgress.isHidden = false
let fractionalProgress = Float(counter)
boughtProgress.setProgress(fractionalProgress, animated: true)
}
}
var currentUser: User!
var media: Media! {
didSet{
if currentUser != nil{
self.updateUI()
}
}
}
var cache = SAMCache.shared()
func updateUI(){
let profileImageKey = "\(media.createdBy.uid)-profileImage"
if let image = cache?.object(forKey: profileImageKey) as? UIImage {
self.profileImageView.image = image
}else{
media.createdBy.downloadProfilePicture { [weak self] (image, error) in
if let image = image {
self?.profileImageView.image = image
self?.cache?.setObject(image, forKey: profileImageKey)
}else if error != nil {
print(error)
}
}
}
mainView.layer.cornerRadius = 20
mainView.layer.masksToBounds = true
//profile image
profileImageView.layer.cornerRadius = profileImageView.bounds.height / 2.0
profileImageView.layer.masksToBounds = true
//name
nameButton.setTitle("\(media.createdBy.firstName) \(media.createdBy.lastName)", for: [])
nameView.layer.cornerRadius = 20
nameView.layer.masksToBounds = true
//date
dateLabel.text = "\(convertDateFormatter(theDate: media.dueAt))"
dateLabel.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.3)
dateLabel.textColor = UIColor.white
dateLabel.layer.cornerRadius = dateLabel.bounds.height / 2.0
dateLabel.layer.masksToBounds = true
//title
listTitle.text = "\(media.title)"
//progress
numOfItems = media.items.count
print("num of items \(media.items.count)")
counter = Double(numOfBought)/Double(numOfItems)
boughtLabel.text = "\(numOfBought)/\(numOfItems) Bought"
boughtProgress.layer.cornerRadius = boughtProgress.bounds.height / 2.0
boughtProgress.layer.masksToBounds = true
}
#IBAction func arrowDidTap(){
print("arrow tapped")
print(media.tag)
}
func convertDateFormatter(theDate: String) -> String
{
print(theDate)
let newFormat = DateFormatter()
newFormat.dateFormat = "dd/MM/yyyy"
let dueDate = newFormat.date(from: theDate)
newFormat.dateFormat = "dd MMM yy"
print(newFormat.string(from: dueDate!))
return newFormat.string(from: dueDate!)
}
The first image shows when the view first loads. this is just what is shown in the .xib, however, the gradient has loaded, not the content
the second image shows how it should look. This is after scrolling through the view

Related

CollectionView with Cells made up of LPLinkView's and UIImageView's is Slow and Reloads Data While Scrolling

I have a UICollectionView with cells of two types; some that load images from a URL, and others that load metadata from a URL and display it with an LPLinkView.
Below is my code for the cell that displays data via LPLinkView:
import UIKit
import LinkPresentation
class LinkItemLinkPreviewCell: UICollectionViewCell {
static let identifier = "kLinkPreviewCollectionViewCell"
var linkView: LPLinkView?
var urlMetadata: LPLinkMetadata?
#IBOutlet var containerView: UIView? = UIView()
#IBOutlet var titleLabel: UILabel? = UILabel()
#IBOutlet var dateLabel: UILabel? = UILabel()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.clipsToBounds = true
self.autoresizesSubviews = true
self.layer.cornerRadius = 20
}
override func prepareForReuse() {
super.prepareForReuse()
}
var linkItem: LinkPostDataObject? {
didSet {
titleLabel?.text = linkItem?.postTitle ?? ""
let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd hh:mm"
dateLabel?.text = df.string(from: toDate((linkItem?.timeSent)!/1000)!)
let provider = LPMetadataProvider()
let url = URL(string: linkItem!.url)
if url != nil {
provider.startFetchingMetadata(for: URL(string: linkItem!.url)!) { (metadata, error) in
if let md = metadata {
DispatchQueue.main.async { [self] in
linkView = LPLinkView()
linkView?.metadata = md
linkView!.frame = containerView!.frame
containerView?.addSubview(linkView!)
linkView!.isUserInteractionEnabled = false
urlMetadata = metadata
}
}
}
}
}
}
}
Below is the code for the UICollectionViewCell that displays an image from a URL:
import UIKit
class LinkItemImageCell: UICollectionViewCell {
static let identifier = "kImageCollectionViewCell"
#IBOutlet var imageView: UIImageView? = UIImageView()
#IBOutlet var titleLabel: UILabel? = UILabel()
#IBOutlet var dateLabel: UILabel? = UILabel()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.clipsToBounds = true
self.autoresizesSubviews = true
self.layer.cornerRadius = 20
}
override func prepareForReuse() {
super.prepareForReuse()
}
var linkItem: LinkPostDataObject? {
didSet {
titleLabel?.text = linkItem?.postTitle ?? ""
let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd hh:mm"
dateLabel?.text = df.string(from: toDate((linkItem?.timeSent)!/1000)!)
if linkItem?.url.isImage() == true {
let url = URL(string: linkItem!.url)
url!.getImageData(from: url!) { (data, response, error) in
guard let data = data, error == nil else { return }
DispatchQueue.main.async() { [self] in
imageView?.image = UIImage(data: data)
}
}
}
}
}
}
And below is the code for my ViewController:
import UIKit
class LinkCollectionViewController : UIViewController, UICollectionViewDelegate,UICollectionViewDataSource {
#IBOutlet weak var collectionView: UICollectionView!
#IBOutlet weak var collectionNameLabel: UILabel!
#IBOutlet weak var collectionSubTitleLabel: UILabel!
#IBOutlet weak var collectionCreatorLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let backButton = UIBarButtonItem()
backButton.title = "Inbox"
self.navigationController?.navigationBar.topItem?.backBarButtonItem = backButton
collectionNameLabel.text = airlockStore.selectedChannel.channelName
collectionSubTitleLabel.text = airlockStore.selectedChannel.channelDescription
collectionCreatorLabel.text = airlockStore.selectedChannel.creator
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
collectionView.alwaysBounceVertical = true
collectionView.register(UINib(nibName: "LinkImageItemCell", bundle: nil), forCellWithReuseIdentifier: "kImageCollectionViewCell")
collectionView.register(UINib(nibName: "LinkItemLinkPreviewCell", bundle: nil), forCellWithReuseIdentifier: "kLinkPreviewCollectionViewCell")
collectionView.reloadItems(at: collectionView.indexPathsForVisibleItems)
collectionView.reloadData()
NotificationCenter.default.addObserver(self, selector: #selector(self.updateLinkCollection), name: Notification.Name("Link_Collection_Updated"), object: nil)
}
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.setNavigationBarHidden(false, animated: animated)
}
#objc func updateLinkCollection() {
collectionView.reloadData()
collectionView.reloadItems(at: collectionView.indexPathsForVisibleItems)
}
// MARK: - UICollectionViewDataSource Delegate
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return airlockStore.selectedChannel.linkPosts.count
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
// MARK: - UICollectionViewDelegate
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//Image
if airlockStore.selectedChannel.linkPosts.reversed()[indexPath.item].url.isImage() == true {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: LinkItemImageCell.identifier, for: indexPath) as? LinkItemImageCell
else { preconditionFailure("Failed to load collection view cell") }
cell.linkItem = airlockStore.selectedChannel.linkPosts.reversed()[indexPath.item]
return cell
}
//URL
else {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: LinkItemLinkPreviewCell.identifier, for: indexPath) as? LinkItemLinkPreviewCell
else { preconditionFailure("Failed to load collection view cell") }
cell.linkItem = airlockStore.selectedChannel.linkPosts.reversed()[indexPath.item]
return cell
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "GoToLinkBlockViewController", sender: self)
airlockStore.selectedLinkBlock = airlockStore.selectedChannel.linkPosts.reversed()[indexPath.item]
guard let cell: LinkItemLinkPreviewCell = collectionView.cellForItem(at: indexPath)! as? LinkItemLinkPreviewCell else {
return
}
airlockStore.selectedLinkBlock.urlMetadata = cell.urlMetadata
}
}
What I'm noticing is that the cells with the LPLinkView's are really slow to display data, and also that a LOT of refreshing happens when scrolling the the UICollectionView.
Any ideas or guidance on how I could improve performance here appreciated; really just trying to not reload the images/URL's of the cells as I scroll.
I don't have time to work through your code, so my answer is going to be general:
When your table view/collection view displays data that has to be fetched over the network, load that data into your data model, not into cells. When the network load completes and that entry in the model is updated, tell the corresponding cell to reload.
If you load data into your cells, as you scroll, the data you loaded before will be lost, and if you scroll back, you'll have to load it again. Ideally, save you loaded data to files in the caches directory so it will still be available if the user closes the view controller and then reopens it.
If you install downloaded data into your model then when you scroll away and scroll back the cell will render correctly as soon as it's displayed.

iOS- UICollectionView horizontal scroll every cell within a UITableView

I have a UITableView in which i have placed a UICollectionView and then reused this scenario for 10 or more cells.
What i want is when i scroll my UICollectionView each of the Cells of other collection view must also be scrolled at the same time synchronously.
MyViewController.swift
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet private weak var menuButton: UIButton!
#IBOutlet var dottedView: UIView!
var array1 = ["Indian Standard Time","Adelaide Standard Time"
,"Auckland Standard Time","Melbourne Standard Time",
"Manchester Standard Time","Paris Standard Time",
"Alaska Standard Time","Greenland Standard Time"
,"Sutherland Standard Time","Russia Standard Time"]
var array2 = ["desc","desc","desc","desc","desc"]
var array3 = ["Mon","Tue","Wed","Thu", "Fri","Sat","Sun"]
var array4 = ["12 2021","12 2021","12 2021","12 2021", "12 2021","12 2021","12 2021"]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
#IBOutlet var maintableview: UITableView!
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell",for: indexPath) as! TableViewCell
cell.tag = indexPath.row
cell.collectionview.tag = (100 * indexPath.section) + indexPath.row
cell.label1.text = array1[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 130
}
#IBAction func datetimeclick(_ sender: Any) {
let vc = storyboard?.instantiateViewController(identifier: "dateViewController") as! DateViewController
present(vc, animated: true)
}
#IBAction func addbtnclick(_ sender: Any) {
let vc = storyboard?.instantiateViewController(identifier: "timezonecontroller") as! TimeZoneViewController
present(vc, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
self.dottedView.addDashedBorder()
let nextdate = Date().addDate()
let prevdate = Date().subtractDate()
let dayofweek = String().dayOfWeek(fDate: nextdate)
let tomorrowDate = String().dateOfWeek(fDate: nextdate)
let yesterdayDate = String().dateOfWeek(fDate: prevdate)
let year = String().getYear(fDate: Date())
let splitstr = dayofweek?.prefix(3)
print("tomdate",tomorrowDate!)
print("prevdate",yesterdayDate!)
print("year",year!)
print("dayofWeekCap", splitstr!)
menuButton.isUserInteractionEnabled = true
let interaction = UIContextMenuInteraction(delegate :self)
menuButton.backgroundColor = UIColor(hexString: "#1361E5")
menuButton.addInteraction(interaction)
}
override func viewDidLayoutSubviews() {
}
}
MyTableViewCell.swift
import UIKit
class TableViewCell: UITableViewCell {
#IBOutlet weak var label1: UILabel!
#IBOutlet weak var label2: UILabel!
#IBOutlet weak var collectionview: UICollectionView!
#IBOutlet weak var collectioncell: UICollectionViewCell!
#IBOutlet weak var collectionText: UILabel!
var scrollToPosition = 0
var indexPosition = 0
extension TableViewCell : UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 48
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let arrayString = timeSlot[indexPath.row]
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectioncell", for: indexPath)
let title = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 33))
indexPosition = indexPath.row
if indexPath.row >= scrollToPosition
{
title.textColor = UIColor.white
cell.contentView.backgroundColor = UIColor.systemBlue
}
else
{
title.textColor = UIColor.black
cell.layer.borderWidth = 1.0
cell.layer.borderColor = UIColor.darkGray.cgColor
cell.contentView.backgroundColor = UIColor.white
}
title.text = arrayString
title.textAlignment = NSTextAlignment.center
for subView in cell.contentView.subviews {
subView.removeFromSuperview()
}
cell.contentView.addSubview(title)
let now = Date()
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_IN")
formatter.dateFormat = "HH:mm" //for complete format EEEE dd MMMM YYYY HH:mm
let datetime = formatter.string(from: now)
let currentDate = createDateFromString(string: datetime)
for i in timeSlot.indices {
let arrayDate = createDateFromString(string: timeSlot[i])
if currentDate > arrayDate && flagDate == false {
flagDate = true
countToScroll = i
}
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 100, height: 33)
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
DispatchQueue.main.async {
for cell in self.collectionview.visibleCells {
let indexpath = self.collectionview.indexPath(for: cell)
self.indexPosition = indexpath!.row
self.collectionview.selectItem(at: IndexPath(row: self.indexPosition, section: 0), animated: true, scrollPosition: .centeredHorizontally)
}
}
}
}

How do I make image visible when collection view cell is double tapped?

I have a collection view with a lot of images and all of these images has a heart image in the right corner. This heart image needs to be set to visible when the big image is double tapped as an indicator that it has been liked.
I have added a double tap gesture to my collection view and now I need to set the heart image to visible when this gesture happens on the selected cell.
Any suggestions to how I do it? I can't find any answers to this anywhere.
This is my collection view controller:
import UIKit
class OevelserCollectionViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
// MARK: - Properties
#IBOutlet weak var OevelserCollectionView: UICollectionView!
#IBOutlet var tap: UITapGestureRecognizer!
var oevelseCollectionViewFlowLayout: UICollectionViewFlowLayout!
let oevelseArray = OevelseArray()
// MARK: - Init
override func viewDidLoad() {
super.viewDidLoad()
setupOevelseCollectionView()
}
// MARK: - Functions
#IBAction func didDoubleTap(_ sender: UITapGestureRecognizer) {
print("tapped")
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
setupOevelseCollectionViewItemSize()
}
private func setupOevelseCollectionView() {
self.OevelserCollectionView.delegate = self
self.OevelserCollectionView.dataSource = self
let nib = UINib(nibName: "OevelseCollectionViewCell", bundle: nil)
OevelserCollectionView.register(nib, forCellWithReuseIdentifier: "OevelseCollectionViewCell")
}
private func setupOevelseCollectionViewItemSize() {
if oevelseCollectionViewFlowLayout == nil {
let numberOfItemPerRow: CGFloat = 1
let lineSpacing: CGFloat = 20
let interItemSpacing: CGFloat = 8
let width = (OevelserCollectionView.frame.width - (numberOfItemPerRow - 1) * interItemSpacing) / numberOfItemPerRow
let height = width - 50
oevelseCollectionViewFlowLayout = UICollectionViewFlowLayout()
oevelseCollectionViewFlowLayout.itemSize = CGSize(width: width, height: height)
oevelseCollectionViewFlowLayout.sectionInset = UIEdgeInsets.zero
oevelseCollectionViewFlowLayout.scrollDirection = .vertical
oevelseCollectionViewFlowLayout.minimumLineSpacing = lineSpacing
oevelseCollectionViewFlowLayout.minimumInteritemSpacing = interItemSpacing
OevelserCollectionView.setCollectionViewLayout(oevelseCollectionViewFlowLayout, animated: true)
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return oevelseArray.oevelser.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "OevelseCollectionViewCell", for: indexPath) as! OevelseCollectionViewCell
let oevelseText = oevelseArray.oevelser[indexPath.item].oevelseName
let oevelseImage = oevelseArray.oevelser[indexPath.item].oevelseImage
cell.oevelseLabel.text = oevelseText
cell.oevelseImageView.image = UIImage(named: oevelseImage)
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
}
And here is my collection view cell class:
import UIKit
class OevelseCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var oevelseImageView: UIImageView!
#IBOutlet weak var oevelseLabel: UILabel!
#IBOutlet weak var isLikedImageView: UIImageView!
#IBOutlet weak var heartImageWidthConstraint: NSLayoutConstraint!
override func awakeFromNib() {
super.awakeFromNib()
}
}
Inside cellForRowAt
cell.oevelseImageView.image = UIImage(named: oevelseImage)
cell.oevelseImageView.tag = indexPath.row
let tapGR = UITapGestureRecognizer(target: self, action: #selector(handleTap))
tapGR.numberOfTapsRequired = 2
cell.oevelseImageView.addGestureRecognizer(tapGR)
#objc func handleTap(_ gesture: UITapGestureRecognizer){
let index = gesture.view!.tag
guard let cell = tableView.cellForRow(at:IndexPath(row:index,section:0)) else { return }
arr[index].isLiked.toggle()
cell.isLikedImageView.image = arr[index].isLiked ? <#likeImg#> : <#defImg#>
}
OR
#objc func handleTap(_ gesture: UITapGestureRecognizer){
arr[gesture.view!.tag ].isLiked.toggle()
self.tableView.reloadRows(at:[IndexPath(row:index,section:0)],with:.none)
}

CollectionView in TableviewCell : Display data using Alamofire and SwiftyJSON with MVC model

I have a Collectionview in Tableviewcell. Using Alamofire and SwiftJSON i download data and store in my model project. I have 2 model file one for tableview, and one for collectionview
Model Project for Tableview:
class Matchs {
var matchTime : String
var matchMbs : Int
var matchLeague : String
var matchCode : Int
var matchHomeTeam : String
var matchAwayTeam : String
init(time : String, mbs : Int, league : String, code : Int, homeTeam : String, awayTeam : String ) {
matchTime = time
matchMbs = mbs
matchLeague = league
matchCode = code
matchHomeTeam = homeTeam
matchAwayTeam = awayTeam
}
}
Model Project for Collectionview:
class MatchsOdds {
var homeWin : Double
var awayWin : Double
var draw : Double
var under : Double
var over : Double
var oddResult = ["1","0","2","Under","Over"]
init(homeWin: Double, awayWin : Double, draw : Double, under : Double, over : Double) {
self.homeWin = homeWin
self.awayWin = awayWin
self.draw = draw
self.under = under
self.over = over
}
}
And here is the Viewcontroller code :
class MainViewController: UIViewController {
#IBOutlet weak var tableview: UITableView!
let MATCH_URL = "somelink"
var match : [Matchs] = []
var matchOdd : [MatchsOdds] = []
#IBOutlet weak var totalMatchLabel: UILabel!
#IBOutlet weak var totalOddsLabel: UILabel!
fileprivate func getMatchData(url:String) {
Alamofire.request(url).responseJSON {
response in
if response.result.isSuccess {
print("I got the match data")
let matchJSON : JSON = JSON(response.result.value!)
self.getMatch(json: matchJSON)
}else {
print("Match Unavailable")
}
self.tableview.reloadData()
}
}
fileprivate func getMatch(json: JSON) {
if let matchs = json["data"]["b"]["f"]["list"].array {
matchs.forEach { (arg0) in
let events = arg0
let tournamentName = events["tournamentName"].stringValue
let homeTeam = events["homeTeam"].stringValue
let mbs = events["mbs"].intValue
let matchCode = events["matchCode"].intValue
let matchTime : String = events["eventHour"].stringValue
let awayTeam = events["awayTeam"].stringValue
let matchTimeFirst5 = matchTime.prefix(5)
let allMatch = Matchs(time: String(matchTimeFirst5), mbs: mbs, league: tournamentName, code: matchCode, homeTeam: homeTeam, awayTeam: awayTeam)
let homeWin = events["oddList"][0]["v"].doubleValue
let draw = events["oddList"][1]["v"].doubleValue
let awaywin = events["oddList"][2]["v"].doubleValue
let under = events["oddList"][3]["v"].doubleValue
let over = events["oddList"][4]["v"].doubleValue
let fiveOdds = MatchsOdds(homeWin: homeWin, awayWin: awaywin, draw: draw, under: under, over: over)
match.append(allMatch)
matchOdd.append(fiveOdds)
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
getMatchData(url: MATCH_URL)
}
override func viewDidAppear(_ animated: Bool) {
}
}
extension MainViewController: UITableViewDelegate,UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return match.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let matcCell = match[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "oddsCell") as! OddsTableViewCell
tableView.separatorStyle = .none
cell.matchToMatch(matcs: matcCell)
tableview.allowsSelection = false
cell.collectionview.tag = indexPath.row
cell.collectionview.reloadData()
cell.matchOddCV = matchOdd
return cell
}
}
No problem from here. I cat write data to Tableviewcell labels. But when i try the matchOdds data to Collectionview cell label. I only got first data which is repeating like this:
Here is the code for Tableviewcell :
class OddsTableViewCell: UITableViewCell {
#IBOutlet weak var reloadButton: RoundedButton!
#IBAction func reloadBottonPressed() {
print("reloadDataPressed")
}
var matchOddCV : [MatchsOdds]!
#IBOutlet weak var collectionview: UICollectionView!
#IBOutlet weak var timeLabel: UILabel!
#IBOutlet weak var mbsLabel: UILabel! {
didSet{
mbsLabel.layer.cornerRadius = 5
mbsLabel.layer.masksToBounds = true
}
}
#IBOutlet weak var leageLabel: UILabel!
#IBOutlet weak var matchCodeLabel: UILabel!
#IBOutlet weak var homeVsAwayLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
collectionview.dataSource = self
collectionview.delegate = self
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func matchToMatch (matcs : Matchs) {
timeLabel.text = matcs.matchTime
mbsLabel.text = String(matcs.matchMbs)
leageLabel.text = matcs.matchLeague
matchCodeLabel.text = String(matcs.matchCode)
homeVsAwayLabel.text = "\(matcs.matchHomeTeam) - \(matcs.matchAwayTeam)"
}
}
extension OddsTableViewCell: UICollectionViewDataSource, UICollectionViewDelegate,UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.bounds.width/5, height: collectionView.bounds.height)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "oddsCollectionViewCell", for: indexPath) as! OddsCollectionViewCell
let matchCell = matchOddCV[indexPath.row]
if indexPath.row == 0 {
cell.matchResultLabel.text = matchCell.oddResult[0]
cell.matchOddsLabel.text = String(matchCell.homeWin)
}else if indexPath.row == 1{
cell.matchResultLabel.text = matchCell.oddResult[1]
cell.matchOddsLabel.text = String(matchCell.draw)
}else if indexPath.row == 2 {
cell.matchResultLabel.text = matchCell.oddResult[2]
cell.matchOddsLabel.text = String(matchCell.awayWin)
}else if indexPath.row == 3 {
cell.matchResultLabel.text = matchCell.oddResult[3]
cell.matchOddsLabel.text = String(matchCell.under)
}else if indexPath.row == 4 {
cell.matchResultLabel.text = matchCell.oddResult[4]
cell.matchOddsLabel.text = String(matchCell.over)
}
cell.matchOddsLabel.layer.borderWidth = 0.5
cell.matchOddsLabel.layer.borderColor = UIColor.lightGray.cgColor
cell.matchResultLabel.layer.borderWidth = 0.5
cell.matchResultLabel.layer.borderColor = UIColor.lightGray.cgColor
return cell
}
}
Collectionviewcell code :
class OddsCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var matchResultLabel: UILabel!
#IBOutlet weak var matchOddsLabel: UILabel!
}
According to the table's cellForRowAt
cell.collectionview.reloadData()
cell.matchOddCV = matchOdd
you assign the same array for all the collections inside all the table cells , what you need is to create an array property inside each Matchs object and do
let matcCell = match[indexPath.row]
cell.matchOddCV = matcCell.odds // create odds array and assign data for each object
cell.collectionview.reloadData()
As I can see, you are reloading the collectionview before setting the new list matchOddCV.
So you should do:
// assign the new list
cell.matchOddCV = matchOdd
// reload colllectionview
cell.collectionview.reloadData()

What’s the “cleaner” way to pass data between UIViewControllers

I gotta populate a UIViewController using data from a UITableView. So, when the user click on each UITableview Cell, another screen should appear filled with some data from the respective clicked UITableView Cell. I don't have certain if I should do it using "Segue" to the other screen, or if there's any better and "clean" way to do that. What would you guys recommend me to do?
Storyboard:
Details Screen:
import UIKit
class TelaDetalheProdutos: UIViewController {
#IBOutlet weak var ImageView: UIImageView!
#IBOutlet weak var labelNomeEDesc: UILabel!
#IBOutlet weak var labelDe: UILabel!
#IBOutlet weak var labelPor: UILabel!
#IBOutlet weak var labelNomeProduto: UILabel!
#IBOutlet weak var labelDescricao: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
}
ViewController:
import UIKit
class ViewController: UIViewController, UICollectionViewDataSource, UITableViewDataSource {
#IBOutlet weak var tableViewTopSell: UITableView!
#IBOutlet var collectionView: UICollectionView!
#IBOutlet weak var collectionViewBanner: UICollectionView!
var dataSource: [Content] = [Content]()
var dataBanner: [Banner] = [Banner]()
var dataTopSold: [Top10] = [Top10]()
override func viewDidLoad() {
super.viewDidLoad()
//SetupNavBarCustom
self.navigationController?.navigationBar.CustomNavigationBar()
let logo = UIImage(named: "tag.png")
let imageView = UIImageView(image:logo)
self.navigationItem.titleView = imageView
//CallAPIData
getTopSold { (data) in
DispatchQueue.main.async {
self.dataTopSold = data
self.tableViewTopSell.reloadData()
}
}
getBanner { (data) in
DispatchQueue.main.async {
self.dataBanner = data
self.collectionViewBanner.reloadData()
}
}
getAudiobooksAPI { (data) in
DispatchQueue.main.async {
self.dataSource = data
self.collectionView.reloadData()
}
}
}
//CollectionView
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if (collectionView == self.collectionView) {
return self.dataSource.count
}else{
return self.dataBanner.count
}}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if (collectionView == self.collectionView) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath) as! CollectionViewCell
let content = self.dataSource[indexPath.item]
cell.bookLabel.text = content.descricao
cell.bookImage.setImage(url: content.urlImagem, placeholder: "")
return cell
}else if (collectionView == self.collectionViewBanner) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCellBanner", for: indexPath) as! CollectionViewCell
let content = self.dataBanner[indexPath.item]
cell.bannerImage.setImage(url: content.urlImagem, placeholder: "")
return cell
}
return UICollectionViewCell()
}
//TableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.dataTopSold.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "topSoldCell", for: indexPath) as! TableViewCell
let content = self.dataTopSold[indexPath.item]
cell.labelNomeTopSell.text = content.nome
cell.imageViewTopSell.setImage(url: content.urlImagem, placeholder: "")
cell.labelPrecoDe.text = "R$ \(content.precoDe)"
cell.labelPrecoPor.text = "R$ 119.99"
return cell
}
}
extension UIImageView{
func setImage(url : String, placeholder: String, callback : (() -> Void)? = nil){
self.image = UIImage(named: "no-photo")
URLSession.shared.dataTask(with: NSURL(string: url)! as URL, completionHandler: { (data, response, error) -> Void in
guard error == nil else{
return
}
DispatchQueue.main.async(execute: { () -> Void in
let image = UIImage(data: data!)
self.image = image
if let callback = callback{
callback()
}
})
}).resume()
}
}
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
switch segue.destination{
case is DestinationViewController:
let vc = segue.destination as! DestinationViewController
//Share your data to DestinationViewController
//Like vc.variableName = value
default:
break
}
}
Make sure that the data your sharing is going to an actual variable like var artistToDisplay: String? in the DestinationViewController, and not an IBOutlet.
You may also need to implement the tableView(_:didSelectRowAt:_) and performSegue(withIdentifier:sender:) methods to begin the segue.

Resources