how to update the UITableView data while scrolling - ios

I have displayed data in the UITableView.The listing is for add cart items in cart list.
According to this picture can see the following details:-
price
Name of product
Stepper to add the quantity
Total Amount
So for this Firstly I added the product in the UITableView. Then stepper action to increases or decreases the quantity, I given the code according .
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "cell"
var cell: ChartCell! = tableView.dequeueReusableCell(withIdentifier: identifier) as? ChartCell
if cell == nil {
tableView.register(UINib(nibName: "ChartCell", bundle: nil), forCellReuseIdentifier: identifier)
cell = tableView.dequeueReusableCell(withIdentifier: identifier) as? ChartCell
}
cell.setEventData(carts: chartViewModel.datafordisplay(atindex: indexPath))
cell.cartadd = { [weak self] in
if let i = self?.tableView.indexPath(for: $0) {
let productid = self?.chartViewModel.datafordisplay(atindex: indexPath)
print(productid?.cartid)
self?.chartViewModel.search(idsearch:productid?.cartid)
print(self?.chartViewModel.searchindex(objectatindex: 0))
cell.setcartData(cartsadd: (self?.chartViewModel.searchindex(objectatindex:0))!)
print(cell.quantity)
self?.chartViewModel.totalPriceInCart()
let theIntegerValue1 :[Int] = (self?.chartViewModel.totalvalue)!
let result = "\(theIntegerValue1[0])"
print(result)
let theStringValue1 :String = String(describing: result)
print(theStringValue1)
self?.totalresult.text = theStringValue1
print(i)
}
}
the viewmodel:-
class ChartViewModel: NSObject {
var datasourceModel:ChartDataSourceModel
var totalvalue:[Int] = []
var insertedArray:CartModel?
var filteredListArray:Array<CartModel>? = []
var productArray:CartModel?
var finalListArray:Array<CartModel>? = []
init(withdatasource newDatasourceModel: ChartDataSourceModel) {
datasourceModel = newDatasourceModel
print(datasourceModel.dataListArray)
}
func search(idsearch :String?) {
filteredListArray = datasourceModel.dataListArray?.filter{($0.cartid?.range(of: idsearch!, options: .caseInsensitive) != nil)}
print(filteredListArray)
}
func searchindex(objectatindex index: Int) -> CartModel {
return self.filteredListArray![index]
}
func datafordisplay(atindex indexPath: IndexPath) -> CartModel{
return datasourceModel.dataListArray![indexPath.row]
}
func numberOfRowsInSection(section:Int) -> Int {
return datasourceModel.dataListArray!.count
}
func delete(atIndex indexPath: IndexPath) {
datasourceModel.dataListArray!.remove(at: indexPath.row)
print(datasourceModel.dataListArray)
}
func totalPriceInCart() {
var totalPrice: Int = 0
for product in datasourceModel.dataListArray! {
totalPrice += product.cartsumint!
print(totalPrice)
}
self.totalvalue = [totalPrice]
}
func insert(atIndex indexPath: IndexPath) {
print(productArray)
print(datasourceModel.dataListArray)
datasourceModel.dataListArray!.insert(productArray!, at: indexPath.row)
print(datasourceModel.dataListArray)
self.datasourceModel.dataListArray = datasourceModel.dataListArray
print(datasourceModel.dataListArray)
self.finalListArray = self.datasourceModel.dataListArray
}
func add() {
datasourceModel.dataListArray?.append(insertedArray!)
print(datasourceModel.dataListArray)
print(insertedArray?.offerAddName)
print(insertedArray?.offerprice)
self.datasourceModel.dataListArray = datasourceModel.dataListArray
print(insertedArray?.cartsum)
}
}
The above code is to add the quantity. And this code is given in UITableView cellForRowAt delegate.
But the problem is:-
-As i adding the quantity of product ,the price also changes And will display in the UITableView. But while scrolling the UITableView the data will show as before.That means :-
initial suppose:- product name : car, price: 300, quantity: 1
This will show at UITableView. When I added quantity: 2, So price: 600 this will show in the UITableView.
But the problem is while scrolling the UITableView it become as price: 300, quantity: 1.
So how to update the UITableView. what should do
The UITableviewCell:-
func setEventData(carts:QM_CartModel)
{
self.name.text = carts.cartname
self.price.text = carts.carttotalprice
self.itemQuantityStepper.value = 1
setItemQuantity(quantity)
print(self.price.text)
let value = carts.cartsum
let x: Int? = Int(value!)
print(x)
let add = x!
print(add)
let theIntegerValue1 :Int = add
let theStringValue1 :String = String(theIntegerValue1)
// self.price.text = theStringValue1
self.price.text = "QR \(theStringValue1)"
print(self.price.text)
}
func setcartData(cartsadd:QM_CartModel)
{
let theIntegerValue :Int = self.quantity
let theStringValue :String = String(theIntegerValue)
cartsadd.cartquantity = theStringValue
print(cartsadd.cartquantity)
print(cartsadd.cartsum)
let value = cartsadd.cartsum
let qty = cartsadd.cartquantity
let x: Int? = Int(value!)
print(x)
let y: Int? = Int(qty!)
print(y)
let add = x! * y!
print(add)
let theIntegerValue1 :Int = add
let theStringValue1 :String = String(theIntegerValue1)
// self.price.text = theStringValue1
self.price.text = "QR \(theStringValue1)"
print(self.price.text)
cartsadd.cartsumint = theIntegerValue1
// print(cartsadd.cartsum)
}

You need to store your data(updated) in your model class.Because while scrolling tableview dequeuereusablecell again call and it will get data from model that's why you always get old data.

class TableViewCellData {
var data: Any?
}
-
class TableViewCell: UITableViewCell {
var cellData: TableViewCellData?
{
didSet {
// change data in cell from TableViewCellData
}
}
var cartadd: (() -> Void)?
}
-
class ViewController: UITableViewController {
var dataSource: [TableViewCellData] = []
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "identifier", for: indexPath) as! TableViewCell
cell.cellData = dataSource[indexPath.row]
cell.cartadd = {
cell.cellData?.data = "" // set data to TableViewCellData
}
return cell
}
}

Related

Subtitles wont display on table views in Swift 5 despite being a subtitled table view cell

I'm working on a project that needs to display two table views at once that each draw from their own class, but no matter what I try, I can't get subtitles to display. The table view cells are formatted to subtitle, and it recognizes detailed text labels, but it just displays only the main text, or just an empty cell.
-------main story board-------
import UIKit
class MainViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableViewOne: UITableView!
#IBOutlet weak var eraserSwitch: UISwitch!
#IBOutlet weak var tableViewTwo: UITableView!
var topShelf: [Top] = []
var bottomShelf: [Bottom] = []
//var topShelf = ["Milk", "Eggs", "Yogurt"]
//var bottomShelf = ["Lettuce", "Carrots", "Onions"]
override func viewDidLoad() {
super.viewDidLoad()
topShelf.append(T1)
topShelf.append(T2)
bottomShelf.append(B1)
bottomShelf.append(B2)
// Do any additional setup after loading the view.
tableViewOne.register(UITableViewCell.self, forCellReuseIdentifier: "cellIDOne")
tableViewOne.delegate = self
tableViewOne.dataSource = self
tableViewTwo.register(UITableViewCell.self, forCellReuseIdentifier: "cellIDTwo")
tableViewTwo.delegate = self
tableViewTwo.dataSource = self
}
#IBAction func switchPressed(_ sender: UISwitch) {
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == tableViewOne {
return topShelf.count
}
return bottomShelf.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == tableViewOne {
let cell = tableViewOne.dequeueReusableCell(withIdentifier: "cellIDOne", for: indexPath)
// cell.textLabel?.text = topShelf[indexPath.row].description
cell.textLabel?.text = topShelf[indexPath.row].item
//cell.textLabel?.text = "a"
// cell.detailTextLabel?.text = topShelf[indexPath.row].experationDate
//cell.detailTextLabel?.text = "a"
cell.detailTextLabel?.text = "v"
//print(topShelf[indexPath.row].experationDate)
return cell
} else {
let cell = tableViewTwo.dequeueReusableCell(withIdentifier: "cellIDTwo", for: indexPath)
// cell.textLabel?.text = bottomShelf[indexPath.row]
cell.textLabel?.text = bottomShelf[indexPath.row].item
cell.detailTextLabel?.text = bottomShelf[indexPath.row].experationDate
//print(bottomShelf[indexPath.row].experationDate)
//USE THIS CODE AS A SKELETON FOR ADDING, ERASING, AND MARKING
// if playlist[indexPath.row].Favorite == true {
// cell.detailTextLabel?.text = "\(playlist[indexPath.row].artistName) ♥"
// } else {
// cell.detailTextLabel?.text = "\(playlist[indexPath.row].artistName) \(playlist[indexPath.row].playCount)"
// }
return cell
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView == tableViewOne {
// first table clicked, use for eraser
tableViewOne.deselectRow(at: indexPath, animated: true)
print("clickOne")
} else {
// you clicked the second table
tableViewTwo.deselectRow(at: indexPath, animated: true)
print("clickTwo")
}
}
-------Class-------
import Foundation
class Top {
var item: String
var retrievalDate: String
var experationDate: String
init(item: String, retrievalDate: String, experationDate: String) {
self.item = item
self.retrievalDate = retrievalDate
self.experationDate = experationDate
}
}
class Bottom {
var item: String
var retrievalDate: String
var experationDate: String
init(item: String, retrievalDate: String, experationDate: String) {
self.item = item
self.retrievalDate = retrievalDate
self.experationDate = experationDate
}
}
let T1 = Top(item: "Milk", retrievalDate: "10/11/22", experationDate: "10/22/22")
let T2 = Top(item: "Yogurt", retrievalDate: "10/11/22", experationDate: "10/20/22")
let B1 = Bottom(item: "Carrots", retrievalDate: "10/11/22", experationDate: "11/1/22")
let B2 = Bottom(item: "Lettuce", retrievalDate: "10/11/22", experationDate: "12/3/22")

Swift : How can I group or club download items to one cell tableView

May be I cannot properly explained it, I have implemented download files mechanism. Files downloading perfectly even URLSession and progress bar works efficiently. I am using TableView for displaying. Image also attached.
Issue is I want to club or merge to one download cell. One AppName contains 11 files so it cell displays 11 times. But I want to show it display only once and progress continues until end of files. Instead of 11 cells it should display 1 cell.
How can I achieve this? I am not getting an idea for this?
fileprivate var fileDownLoadDataArray:[DownLoadData] = []
func detailData(AppId: Int, AppName: String){
if let url = Bundle.main.url(forResource: "AppointmentDetail", withExtension: "json") {
do {
let data = try Data(contentsOf: url)
let decoder = JSONDecoder()
let jsonData = try decoder.decode(AppointmentDetail.self, from: data)
self.AppDetailData = jsonData
for param in AppDetailData?.sectionList ?? [] {
for item in param.items! {
if item.actionType == 2 {
let filename = item.actionUrl ?? ""
let data = DownLoadData(with: AppName, and: item.actionUrl ?? "")
fileDownLoadDataArray.append(data)
}
}
}
} catch {
print("error:\(error)")
}
}
}
Class NSObject
class DownLoadData: NSObject {
var fileTitle: String = ""
var downloadSource: String = ""
var downloadTask: URLSessionDownloadTask?
var taskResumeData: Data?
var downloadProgress: Float = 0.0
var isDownloading: Bool = false
var isDownloadComplete: Bool = false
var taskIdentifier: Int = 0
var groupDownloadON:Bool = false
var groupStopDownloadON:Bool = false
init(with title:String, and source:String){
self.fileTitle = title
self.downloadSource = source
super.init()
}
TableView DataSource:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fileDownLoadDataArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ChildTableViewCell", for: indexPath) as! ChildTableViewCell
let downloadData = fileDownLoadDataArray[indexPath.row]
cell.configureCell(with: downloadData)
cell.cellDelegate = self
return cell
}
Image:
What you need to do is to replace your code.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.Appdata!.count //Appdata?.count ?? 0
}
In cellForRowAt ..
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ChildTableViewCell", for: indexPath) as! ChildTableViewCell
//let dic = Appdata?[indexPath.row]
//cell.fileNameLabel.text = dic?.projectName
let downloadData = fileDownLoadDataArray[indexPath.row]
let mainProject = self.Appdata![indexPath.row]
print(mainProject.projectName as Any)
cell.configureCell(with: downloadData , projectName: mainProject)
cell.cellDelegate = self
return cell
}
In ConfigureCell
func configureCell(with downloadInfo:DownLoadData, projectName:Appointment){
// Set the download info into the cell
self.downloadData = downloadInfo
fileNameLabel.text = projectName.projectName
if self.downloadData.groupDownloadON {
startOrPauseDownload()
// reset flag
self.downloadData.groupDownloadON = false
}
if self.downloadData.groupStopDownloadON{
stopDownload()
self.downloadData.groupStopDownloadON = false
}
updateView()
}
Hope is that one you are looking for.Cheers

How to pass data from UI Table View to UI Collection View inside Table View Cell?

i have ui collection view on my table view cell using xib .
i want to pass data that i get from API to ui collection view inside table view cell
this is my code
model
class MessageTextType {
var messageType: String = ""
var messageFromMe: String = ""
var date: String = ""
var type: String = ""
var text: String = ""
var image: String = ""
var imagePreview: String = ""
var time: String = ""
var speech: String = ""
var resolvequery: String = ""
var columnCarousel: String = ""
}
table view
var messageTextArray : [MessageTextType] = [MessageTextType]()
var messageFromMe : [MessageInput] = [MessageInput]()
override func viewDidLoad() {
super.viewDidLoad()
chatTableView.delegate = self
chatTableView.dataSource = self
chatMessage.delegate = self
chatTableView.register(UINib(nibName: "MessageText", bundle: nil), forCellReuseIdentifier: "MessageText")
chatTableView.register(UINib(nibName: "MessageFromMe", bundle: nil), forCellReuseIdentifier: "MessageFromMe")
chatTableView.register(UINib(nibName: "ChatImage", bundle: nil), forCellReuseIdentifier: "MessageImage")
chatTableView.register(UINib(nibName: "MessageCarousel", bundle: nil), forCellReuseIdentifier: "MessageCarousel")
configureTableView()
chatTableView.separatorStyle = .none
showNavItem()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let chatinfo = messageTextArray[indexPath.item]
if chatinfo.messageType == "chatInput" {
let cell : MessageFromMe! = tableView.dequeueReusableCell( withIdentifier: "MessageFromMe") as? MessageFromMe
cell.chatMe.text = chatinfo.messageFromMe
cell.time.text = chatinfo.time
return cell
}
else{
if chatinfo.type == "image" {
let cell : ChatImage! = tableView.dequeueReusableCell( withIdentifier: "MessageImage") as? ChatImage
let remoteImageURL = URL(string: chatinfo.image)!
Alamofire.request(remoteImageURL).responseData { (response) in
if response.error == nil {
print(response.result)
if let data = response.data {
cell.chatImage.image = UIImage(data: data)
}
}
}
return cell
}else if chatinfo.type == "text" {
let cell : MessageText! = tableView.dequeueReusableCell( withIdentifier: "MessageText") as? MessageText
cell.chatText.text = chatinfo.text
return cell
}
else {
let cell : MessageCarousel! = tableView.dequeueReusableCell( withIdentifier: "MessageCarousel") as? MessageCarousel
return cell
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return messageTextArray.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func configureTableView() {
chatTableView.rowHeight = UITableView.automaticDimension
chatTableView.estimatedRowHeight = 500.0
}
#IBAction func sendPressed(_ sender: Any) {
chatInput()
getDataText()
chatMessage.text = ""
}
func chatInput() {
let messageRespon = MessageTextType()
let date = Date()
let formatter = DateFormatter()
formatter.timeStyle = .short
formatter.dateStyle = .none
messageRespon.messageType = "chatInput"
messageRespon.messageFromMe = chatMessage.text!
messageRespon.time = formatter.string(from: date)
messageTextArray.append(messageRespon)
configureTableView()
chatTableView.reloadData()
}
func getDataText() {
startAnimating(type: NVActivityIndicatorType.ballPulseSync)
let id = UserDefaults.standard.object(forKey: "id") as! String
let chatParams : [String : Any] = [ "user_id": id,
"bot_id": "dBmK5m",
"query": chatMessage.text!
]
let token = UserDefaults.standard.object(forKey: "token") as! String
let headersku: HTTPHeaders = [
"Content-Type":"application/json",
"Accept": "application/json",
"Authorization": "Bearer \(token)"
]
Alamofire.request(base_url+"/chat", method: .post, parameters: chatParams,encoding: JSONEncoding.default, headers: headersku)
.responseJSON {
response in
if response.result.isSuccess {
let loginJSON : JSON = JSON(response.result.value!)
print(loginJSON)
let output = loginJSON["result"]["output"]
for (_, subJson):(String, JSON) in output {
let text = subJson["text"].stringValue
let type = subJson["type"].stringValue
let speech = subJson["speech"].stringValue
let image = subJson["originalContentUrl"].stringValue
let date = loginJSON["timestamp"]["date"].stringValue
let resolvequery = loginJSON["resolvequery"].stringValue
let columns = subJson["columns"]
let message = MessageTextType()
message.text = text
message.messageType = "text"
message.type = type
message.speech = speech
message.image = image
message.date = date
message.resolvequery = resolvequery
self.messageTextArray.append(message)
if type == "text" {
let utterance = AVSpeechUtterance(string: output[0]["text"].stringValue +
". "+output[1]["text"].stringValue)
utterance.rate = 0.5
utterance.voice = AVSpeechSynthesisVoice(language: "id-ID")
let voice = AVSpeechSynthesizer()
voice.speak(utterance)
}
}
self.configureTableView()
self.chatTableView.reloadData()
self.stopAnimating()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+0.1, execute: {
let indexPath = IndexPath(row: self.messageTextArray.count-1, section: 0)
self.chatTableView.scrollToRow(at: indexPath, at: UITableView.ScrollPosition.bottom, animated: true)
})
}
else {
let alertController = UIAlertController(title: "warning", message: "server sedang bermasalah , coba lagi", preferredStyle: .alert)
let action1 = UIAlertAction(title: "Ok", style: .default) { (action:UIAlertAction) in
self.stopAnimating()
}
alertController.addAction(action1)
self.present(alertController, animated: true, completion: nil)
}
}
}
collection view inside table view cell
import UIKit
class MessageCarousel: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var carouselImage: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.carouselImage.dataSource = self
self.carouselImage.delegate = self
self.carouselImage.register(UINib.init(nibName: "CarouselViewCell", bundle: nil), forCellWithReuseIdentifier: "carouselViewID")
self.carouselImage.reloadData()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "carouselViewID", for: indexPath as IndexPath) as! CarouselViewCell
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print(indexPath.row)
}
}
import UIKit
class ViewController : UIViewController {
}
extension ViewController:UITableViewDataSource,UITableViewDelegate{
// this is for your tableView
In your tableView Cell :-
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let chatinfo = messageTextArray[indexPath.item]
let cell : MessageCarousel! = tableView.dequeueReusableCell( withIdentifier: "MessageCarousel") as? MessageCarousel
if yourModelData != nil{
// reload collectionView
}
return cell
}
}
extension ViewController :UICollectionViewDataSource,UICollectionViewDelegate{
// This is for Your CollectionView
// In collection View
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if yourModelData.count != 0{
return yourModelData.count
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "carouselViewID", for: indexPath as IndexPath) as! CarouselViewCell
// handle Model here
let msg = yourModelData[indexPath.row]. messageFromMe
return cell
}
}
// hope its worked for you
you have to pass data in cellrowAt method.
update your code :
let cell : MessageCarousel! = tableView.dequeueReusableCell( withIdentifier: "MessageCarousel") as? MessageCarousel
** cell.yourDataArray = chatinfo.arrayColumns **
cell.carouselImage.reloadData()
return cel
// yourInputArray is array that contain collectionview data
class MessageCarousel: UITableViewCell {
var yourDataArray = NSMutableArray() // or any other array.
//.... your code
}
You have to update your model MessageTextType, add array of columns variable in MessageTextType
class MessageTextType {
var arrayColumns : [Column]!
//... your rest code
}
class Column {
var thumbnailImageUrl : String!
var title : String!
public class func modelsFromDictionaryArray(array:NSArray) -> [Column]
{
var models:[Column] = []
for item in array
{
models.append(Column(dictionary: item as! NSDictionary)!)
}
return models
}
required public init?(dictionary: NSDictionary) {
thumbnailImageUrl = dictionary["thumbnailImageUrl"] as? String ?? ""
title = dictionary["title"] as? String ?? ""
}
init() {
}
}
add this code in API response:
let columns = Column.modelsFromDictionaryArray(array:subJson["columns"])
message.arrayColumns = columns

Value in JSON does not display in tableviewcell custom

Can't display data in TableViewCell.Data reports of events, but the when you open the array "sports" display the data in cels no.The display of the title occurs and the transfer is ended...
This is my json code...
Event.swift
import UIKit
struct Event {
let match : String
let forecast : String
let data : String
let image : UIImage
var sports : [Sport]
init (match : String, forecast : String, data: String, image : UIImage, sports : [Sport]) {
self.match = match
self.forecast = forecast
self.data = data
self.image = image
self.sports = sports
}
static func eventsFromBundle ()-> [Event] {
var events = [Event] ()
guard let url = Bundle.main.url(forResource: "events", withExtension: "json") else {
return events
}
do {
let data = try Data(contentsOf: url)
guard let rootObject = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String : Any] else {
return events
}
guard let eventObjects = rootObject["events"] as? [[String: AnyObject]] else {
return events
}
for eventObject in eventObjects {
if let match = eventObject["match"] as? String,
let forecast = eventObject["forecast"] as? String,
let data = eventObject["data"] as? String,
let imageName = eventObject["image"] as? String,
let image = UIImage(named: imageName),
let sportsObject = eventObject["sports"] as? [[String : String]]{
var sports = [Sport]()
for sportObject in sportsObject {
if let nameTitle = sportObject["name"] ,
let titleName = sportObject["image"],
let titleImage = UIImage(named: titleName + ".jpg"),
let prognozLabel = sportObject["prognoz"],
let obzor = sportObject["obzor"] {
sports.append(Sport(name: nameTitle, prognoz: prognozLabel, image: titleImage, obzor: obzor, isExpanded: false))
}
}
let event = Event(match: match, forecast: forecast, data: data, image: image, sports: sports)
events.append(event)
}
}
} catch {
return events
}
return events
}
}
import UIKit
class SportViewController: BaseViewController {
var events = Event.eventsFromBundle ()
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
addSlideMenuButton()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 100
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
NotificationCenter.default.addObserver(forName: .UIContentSizeCategoryDidChange, object: .none, queue: OperationQueue.main) { [weak self] _ in
self?.tableView.reloadData()
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? SportDetailViewController,
let indexPath = tableView.indexPathForSelectedRow {
destination.selectedEvent = events[indexPath.row]
}
}
}
extension SportViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return events.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellMatch", for: indexPath) as! SportTableViewCell
let event = events[indexPath.row]
cell.matchLabel.text = event.match
cell.imageMatch.image = event.image
cell.forecastLabel.text = event.forecast
cell.dataLabel.text = event.data
cell.matchLabel.font = UIFont.preferredFont(forTextStyle: .subheadline)
cell.forecastLabel.font = UIFont.preferredFont(forTextStyle: .callout)
return cell
}
}
Her is the controller.SportDetailViewController.swift
import UIKit
class SportDetailViewController: UIViewController {
var selectedEvent : Event!
let obzorText = "Select for more info >"
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
title = selectedEvent.match
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 300
// Do any additional setup after loading the view.
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
}
extension SportDetailViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return selectedEvent.sports.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : SportDetailTableViewCell = tableView.dequeueReusableCell(withIdentifier: "cellMatch", for: indexPath) as! SportDetailTableViewCell
let sport = selectedEvent.sports[indexPath.row]
cell.nameTitle.text = sport.name
cell.titleImage.image = sport.image
cell.prognozLabel.text = sport.prognoz
cell.selectionStyle = .none
cell.nameTitle.backgroundColor = UIColor.darkGray
cell.backgroundColor = UIColor.red
cell.obzorText.text = sport.isExpanded ? sport.obzor : obzorText
cell.obzorText.textAlignment = sport.isExpanded ? .left : .center
return cell
}
}
extension SportDetailViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) as? SportDetailTableViewCell else { return }
var sport = selectedEvent.sports[indexPath.row]
sport.isExpanded = !sport.isExpanded
selectedEvent.sports[indexPath.row] = sport
cell.obzorText.text = sport.isExpanded ? sport.obzor : obzorText
cell.obzorText.textAlignment = sport.isExpanded ? .left : .center
tableView.beginUpdates()
tableView.endUpdates()
tableView.scrollToRow(at: indexPath, at: .top, animated: true)
}
}
all these methods have tried: tableview.datasource = self , tableview.delegate = self и reloadData().....in viewDidLoad.
Delete this init from your struct: (because struct gets free initializer)
init (match : String, forecast : String, data: String, image : UIImage, sports : [Sport]) {
self.match = match
self.forecast = forecast
self.data = data
self.image = image
self.sports = sports
}
Now, your var events won't be populated as you are calling method in class scope. So change this:
class SportViewController: BaseViewController {
var events = Event.eventsFromBundle ()
...
...
}
to
class SportViewController: BaseViewController {
var events = [Event]()
...
...
override func viewDidLoad() {
super.viewDidLoad()
addSlideMenuButton()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 100
events = Event().eventsFromBundle()
}
...
...
}
This should solve your problem.

Two custom cells in UITableView

I'm trying to use two custom cells for displaying the product information, on the first one I show the product main information and in the second one I display the comments of this product.
At the moment everything is linked in the StoryBoard and I have my tableview prepared for storing the comment information in the second custom cell (I have checked the requestComments() function and It's working fine but I can't make them appear.
Is it something related to the numberOfRowsInSection? Because I tried to SUM the products.count with the comments.count and It's showing an error.
It's my first time using two custom cells so I hope someone can help me.
Here is my code:
import UIKit
import Social
class MarcaProductoViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var productoImageView:UIImageView!
#IBOutlet var tableView:UITableView!
#IBOutlet var votarFrame:UIView!
#IBOutlet var votarBarra:UISlider!
#IBOutlet var votarLabel:UILabel!
var productoImage:String!
var nombre:String!
var producto:Producto!
var productos = [Producto]()
var mensaje:Mensaje!
var mensajes = [Mensaje]()
var img:UIImage?
override func viewDidLoad() {
super.viewDidLoad()
// Set table view background color
self.tableView.backgroundColor = UIColor(red: 240.0/255.0, green: 240.0/255.0, blue: 240.0/255.0, alpha: 0.2)
// Remove extra separator
self.tableView.tableFooterView = UIView(frame: CGRectZero)
// Change separator color
self.tableView.separatorColor = UIColor(red: 240.0/255.0, green: 240.0/255.0, blue: 240.0/255.0, alpha: 0.8)
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 88.0
requestPost()
requestComments()
tableView.reloadData()
}
override func viewDidAppear(animated: Bool) {
tableView.reloadData()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.hidesBarsOnSwipe = false
self.navigationController?.setNavigationBarHidden(false, animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func requestPost () {
let request = NSMutableURLRequest(URL: NSURL(string: "http://www.website.es/product.php")!)
request.HTTPMethod = "POST"
let postString = "name="+name
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
print("error=\(error)")
return
}
self.productos = self.parseJsonData(data!)
// Reload table view
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
})
}
task.resume()
tableView.reloadData()
}
func parseJsonData(data: NSData) -> [Producto] {
var productos = [Producto]()
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
// Parse JSON data
let jsonProductos = jsonResult?["lista_productos"] as! [AnyObject]
for jsonProducto in jsonProductos {
let producto = Producto()
producto.image = jsonProducto["image"] as! String
producto.name = jsonProducto["name"] as! String
producto.desc = jsonProducto["desc"] as! String
productos.append(producto)
}
}
catch let parseError {
print(parseError)
}
return productos
}
func requestComments () {
//print("Hola")
let request = NSMutableURLRequest(URL: NSURL(string: "http://www.website.es/comments.php")!)
request.HTTPMethod = "POST"
let postString = "name="+name
//print(postString)
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
print("error=\(error)")
return
}
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)!
print("mensajes = \(responseString)")
self.mensajes = self.parseJsonDataComments(data!)
// Reload table view
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
})
}
task.resume()
tableView.reloadData()
}
func parseJsonDataComments(data: NSData) -> [Mensaje] {
var messages = [Mensaje]()
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
// Parse JSON data
let jsonProductos = jsonResult?["messages"] as! [AnyObject]
for jsonProducto in jsonProductos {
let message = Mensaje()
message.author = jsonProducto["author"] as! String
message.message = jsonProducto["message"] as! String
message.date = jsonProducto["date"] as! String
messages.append(message)
}
}
catch let parseError {
print(parseError)
}
return message
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// Return the number of sections.
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
return productos.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
title = productos[indexPath.row].nombre
if indexPath.row == 0 {
print("11")
let cell = tableView.dequeueReusableCellWithIdentifier("CellDetail", forIndexPath: indexPath) as! ProductoTableViewCell
cell.selectionStyle = .None
if let url = NSURL(string: productos[indexPath.row].imagen) {
if let data = NSData(contentsOfURL: url) {
self.productoImageView.image = UIImage(data: data)
}
}
cell.name.text = productos[indexPath.row].name
cell.desc.text = productos[indexPath.row].desc
cell.layoutIfNeeded()
return cell
}
else {
print("22")
let cell2 = tableView.dequeueReusableCellWithIdentifier("MostrarComentarios", forIndexPath: indexPath) as! ComentariosTableViewCell
cell2.selectionStyle = .None
cell2.author.text = mensajes[indexPath.row].author
cell2.comment.text = mensajes[indexPath.row].comments
cell2.date.text = mensajes[indexPath.row].date
cell2.layoutIfNeeded()
return cell2
}
} }
Update:
I have made the following changes:
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// Return the number of sections.
return productos.count+mensajes.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
return productos.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
title = productos[indexPath.row].nombre
if indexPath.section == 0 {
print("11")
let cell = tableView.dequeueReusableCellWithIdentifier("CellDetail", forIndexPath: indexPath) as! ProductoTableViewCell
cell.selectionStyle = .None
if let url = NSURL(string: productos[indexPath.row].imagen) {
if let data = NSData(contentsOfURL: url) {
self.productoImageView.image = UIImage(data: data)
}
}
cell.nombre.text = productos[indexPath.row].nombre
cell.descripcion.text = productos[indexPath.row].descripcion
cell.modo_de_empleo.text = productos[indexPath.row].modo_de_empleo
cell.marca.text = productos[indexPath.row].marca
cell.linea.text = productos[indexPath.row].linea
cell.distribuidor.text = productos[indexPath.row].distribuidor
cell.tamano.text = productos[indexPath.row].tamano
cell.precio.text = productos[indexPath.row].precio
cell.codigo_nacional.text = productos[indexPath.row].codigo_nacional
cell.layoutIfNeeded()
return cell
}
else {
let cell2 = tableView.dequeueReusableCellWithIdentifier("MostrarComentarios", forIndexPath: indexPath) as! ComentariosTableViewCell
print(mensajes[indexPath.row].mensaje)
cell2.selectionStyle = .None
cell2.comentario.text = mensajes[indexPath.row].mensaje
cell2.fecha.text = mensajes[indexPath.row].fecha
cell2.layoutIfNeeded()
return cell2
}
}
At the moment, I can display the comments perfectly, but the problem is that the messages from this product are always the same (repeated in every new comment row) I just need to change something (I don't know what exactly) to show the correct information for the messages without beeing duplicated.
Thanks in advance.
I think you have to use return products.count
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return products.count
}
And you have to use % 2 == 0 instead of == 0
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
title = productos[indexPath.row].nombre
if indexPath.row % 2 == 0 { // runs if indexPath.row = 0, 2, 4, 6 etc
let cell = tableView.dequeueReusableCellWithIdentifier("CellDetail", forIndexPath: indexPath) as! ProductoTableViewCell
return cell
} else { // runs if indexPath.row = 1, 3, 5, 7 etc
let cell2 = tableView.dequeueReusableCellWithIdentifier("MostrarComentarios", forIndexPath: indexPath) as! ComentariosTableViewCell
return cell2
}
}
Remainder Operator
The remainder operator (a % b) works out how many multiples of b will
fit inside a and returns the value that is left over (known as the
remainder).
Here’s how the remainder operator works. To calculate 9 % 4, you first
work out how many 4s will fit inside 9:
You can fit two 4s inside 9, and the remainder is 1 (shown in orange).
In Swift, this would be written as:
9 % 4 // equals 1
If someone has the same problem:
else {
let cell2 = tableView.dequeueReusableCellWithIdentifier("MostrarComentarios", forIndexPath: indexPath) as! ComentariosTableViewCell
cell2.selectionStyle = .None
cell2.comentario.text = mensajes[(indexPath.section)-1].mensaje
cell2.fecha.text = mensajes[(indexPath.section)-1].fecha
cell2.layoutIfNeeded()
return cell2
}
Regards,

Resources