why Xcode do not execute the codes in func tableView? - ios

question:
I set several breakpoints inside the function of tableView. However the Xcode didn't execute the code inside the tableView. please tell me how to fix these.
I'm new to learn about IOS development and I'm trying to write a demo of Tweeter show page. Looking forward for responses!
Here is code of extension UITablewViewDataSource:
extension WechatMomentViewController: UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.tweetList?.count ?? 0;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let tweetCell = tableView.dequeueReusableCell(withIdentifier: "WechatMomentListCell", for: indexPath) as? WechatMomentListCell else {
fatalError("there is no WechatMomentList")
}
let tweet = viewModel.tweetList?[indexPath.row]
for i in tweet?.images ?? [] {
let flagImage = UIImageView()
flagImage.sd_setImage(with: URL(string: i.url))
tweetCell.Images.append(flagImage)
}
for i in tweet?.comments ?? [] {
let flagComment = UILabel()
flagComment.text = "\(i.sender) : \(i.content)"
tweetCell.comments.append(flagComment)
}
tweetCell.senderNick.text = tweet?.sender?.nick
tweetCell.senderAvatar.sd_setImage(with: URL(string: tweet?.sender?.avatar ?? ""), placeholderImage: UIImage(named: "placeholder.png"))
tweetCell.content.text = tweet?.content
return tweetCell
}
}
and here is the code of all ViewController:
import UIKit
import SnapKit
import SDWebImage
import Alamofire
//
class WechatMomentViewController: UIViewController {
let viewModel = WechatMomentViewModel()
var userAvatar = UIImageView()
var userProfileImage = UIImageView()
var userNick = UIButton()
var TweetCell = UITableViewCell()
override func viewDidLoad() {
super.viewDidLoad()
viewModel.delegate = self
getUserProfile()
getTweet()
}
fileprivate func getUserProfile() {
viewModel.getUserProfile()
view.addSubview(userProfileImage)
userAvatar.backgroundColor = UIColor.black
view.addSubview(userAvatar)
userAvatar.snp.makeConstraints{ (make) in
make.height.equalTo(80)
make.width.equalTo(80)
make.right.equalToSuperview().offset(-10)
make.centerY.equalToSuperview()
}
userAvatar.clipsToBounds = true;
userAvatar.layer.cornerRadius = 10;
view.addSubview(userNick)
userNick.snp.makeConstraints{ (make) in
make.width.equalTo(90)
make.height.equalTo(20)
make.trailing.equalTo(userAvatar.snp.leading)
make.centerY.equalTo(userAvatar)
}
userProfileImage.frame = CGRect(x: 0, y: 0, width: 414, height: 448)
}
fileprivate func getTweet() {
viewModel.getTweet()
}
}
extension WechatMomentViewController: WechatMomentVCProtocol {
func refreshUI() {
if let user = viewModel.user,
let avatar = user.avatar,
let profileImage = user.profileImage {
userAvatar.sd_setImage(with: URL(string: avatar))
userProfileImage.sd_setImage(with: URL(string: profileImage))
userNick.setTitle(user.nick, for: .normal)
}
}
}
extension WechatMomentViewController: UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.tweetList?.count ?? 0;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let tweetCell = tableView.dequeueReusableCell(withIdentifier: "WechatMomentListCell", for: indexPath) as? WechatMomentListCell else {
fatalError("there is no WechatMomentList")
}
let tweet = viewModel.tweetList?[indexPath.row]
for i in tweet?.images ?? [] {
let flagImage = UIImageView()
flagImage.sd_setImage(with: URL(string: i.url))
tweetCell.Images.append(flagImage)
}
for i in tweet?.comments ?? [] {
let flagComment = UILabel()
flagComment.text = "\(i.sender) : \(i.content)"
tweetCell.comments.append(flagComment)
}
tweetCell.senderNick.text = tweet?.sender?.nick
tweetCell.senderAvatar.sd_setImage(with: URL(string: tweet?.sender?.avatar ?? ""), placeholderImage: UIImage(named: "placeholder.png"))
tweetCell.content.text = tweet?.content
return tweetCell
}
}
and here is identifire code of WechatMomentListCell:
import Foundation
import UIKit
class WechatMomentListCell: UITableViewCell{
var content = UILabel()
var senderAvatar = UIImageView()
var senderNick = UILabel()
var Images = [UIImageView()]
var comments = [UILabel()]
}

your class should extend UITableViewController not UIViewController . Also you must register you cell.
class WechatMomentViewController: UITableViewController {
let kCellIdentifier = "CellIdentifier"
override func viewDidLoad() {
super.viewDidLoad()
self.tableView?.register(WechatMomentListCell, forCellReuseIdentifier: kCellIdentifier)
}
}

Add something like:
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self // if you are...
tableView.datasource = self
...
}
The problem ist that you will most likely (you didn't show) have a regular UIViewController and not a UITableViewController. Therefore the tableview does not have a delegate nor a datasource. Alternatively, if you are using a storyboard or a xib, you can right click from the tableview to the controller and assign those values there.

The problem is:
firstly, I don't have TableView(). So I create a new instance of TableView.
Secondly, use
view.addSubivew(tableview)
Then, member to reloadData from your View Model.
and... try clean build(it is really helpful)

Related

TableView is not updating properly after logout and log in

I have a ProfileView controller where I display the email of the user that is logged in. When I sign out and sign in again the email is updated but the tableview is not updated when new info. Even if it is done the reloading is just appending duplicating rows to the view. Below is my code. Can someone check what I may be doing wrong
import UIKit
import FirebaseAuth
import SDWebImage
import FirebaseDatabase
final class ProfileViewController: UIViewController {
#IBOutlet var tableView: UITableView!
var data = [ProfileViewModel]()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard let email = Auth.auth().currentUser?.email! else {
return
}
tableView.register(ProfileTableViewCell.self,
forCellReuseIdentifier: ProfileTableViewCell.identifier)
data.append(ProfileViewModel(viewModelType: .info,
title: "Email: \(email ?? "No Email")",
handler: nil))
tableView.register(UITableViewCell.self,
forCellReuseIdentifier: "cell")
tableView.delegate = self
tableView.dataSource = self
tableView.tableHeaderView = createTableHeader()
}
func createTableHeader() -> UIView? {
guard let email = UserDefaults.standard.value(forKey: "email") as? String else {
return nil
}
let safeEmail = DatabaseManager.safeEmail(emailAddress: email)
let filename = safeEmail + "_profile_picture.png"
let path = "images/"+filename
let headerView = UIView(frame: CGRect(x: 0,
y: 0,
width: self.view.width,
height: 300))
headerView.backgroundColor = .link
let imageView = UIImageView(frame: CGRect(x: (headerView.width-150) / 2,
y: 75,
width: 150,
height: 150))
imageView.contentMode = .scaleAspectFill
imageView.backgroundColor = .white
imageView.layer.borderColor = UIColor.white.cgColor
imageView.layer.borderWidth = 3
imageView.layer.masksToBounds = true
imageView.layer.cornerRadius = imageView.width/2
headerView.addSubview(imageView)
StorageManager.shared.downloadURL(for: path, completion: { result in
switch result {
case .success(let url):
imageView.sd_setImage(with: url, completed: nil)
case .failure(let error):
print("Failed to get download url: \(error)")
}
})
return headerView
}
}
extension ProfileViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let viewModel = data[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: ProfileTableViewCell.identifier,
for: indexPath) as! ProfileTableViewCell
cell.setUp(with: viewModel)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
data[indexPath.row].handler?()
}
}
class ProfileTableViewCell: UITableViewCell {
static let identifier = "ProfileTableViewCell"
public func setUp(with viewModel: ProfileViewModel) {
self.textLabel?.text = viewModel.title
switch viewModel.viewModelType {
case .info:
textLabel?.textAlignment = .center
selectionStyle = .none
}
}
}
I think you need to empty data array before appending new object into that array.
just write
data.removeAll() before
data.append(ProfileViewModel(viewModelType: .info, title: "Email: \(email ?? "No Email")", handler: nil)).
I think this will resolve your issue.

UITableViewCell size does not change

I cannot understand why the cells do not resize according to the given .xib file
This is my table controller
import Foundation
import UIKit
class RecipeTableView: UIViewController {
let cellIdentifier = "RecipeTableViewCell"
#IBOutlet weak var recipeTableView: UITableView!
private let localDatabaseManager: LocalDatabaseManager = LocalDatabaseManager.shared
private var recipes = [Recipe]()
override func viewDidLoad() {
super.viewDidLoad()
recipeTableView.dataSource = self
recipeTableView.delegate = self
//recipeTableView.rowHeight = UITableView.automaticDimension
//recipeTableView.estimatedRowHeight = UITableView.automaticDimension
self.recipeTableView.register(UINib(nibName: cellIdentifier, bundle: nil), forCellReuseIdentifier: cellIdentifier)
localDatabaseManager.loadRecipes { [weak self] (recipes) in
guard let recipes = recipes else {
return
}
self?.recipes = recipes
DispatchQueue.main.async {
self?.recipeTableView.reloadData()
}
}
}
// override func viewWillAppear(_ animated: Bool) {
// recipeTableView.estimatedRowHeight = 256
// recipeTableView.rowHeight = UITableView.automaticDimension
// }
}
extension RecipeTableView: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
recipes.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? RecipeTableViewCell else {
return UITableViewCell()
}
let recipe = recipes[indexPath.row]
cell.configure(with: recipe)
//cell.layer.cornerRadius = 32
//cell.layer.masksToBounds = true
return cell
}
}
extension RecipeTableView: UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
}
And my cell swift file
import Foundation
import UIKit
import Kingfisher
import Cosmos
class RecipeTableViewCell: UITableViewCell {
#IBOutlet weak var recipeNameLabel: UILabel!
#IBOutlet weak var recipeDescriptionLabel: UILabel!
#IBOutlet weak var recipeImageView: UIImageView!
#IBOutlet weak var recipeCosmosView: CosmosView!
override func prepareForReuse() {
super.prepareForReuse()
recipeNameLabel.text = nil
recipeDescriptionLabel.text = nil
recipeImageView.image = nil
}
func configure(with recipe: Recipe) {
recipeNameLabel?.text = recipe.name
recipeDescriptionLabel?.text = recipe.description
//let imageBytes = recipe.imageData
//let imageData = NSData(bytes: imageBytes, length: imageBytes.count)
//let image = UIImage(data: imageData as Data)
//recipeImageView?.image = image
let imageUrl = URL(string: recipe.imageData)
recipeImageView?.kf.setImage(with: imageUrl)
recipeCosmosView.settings.fillMode = .precise
recipeCosmosView.rating = recipe.rating
}
}
here is what my custom cell looks like
here is how these cells are shown in the app
I already found similar questions, but everywhere the same answer. Need to add the following lines. So I tried.
override func viewWillAppear(_ animated: Bool) {
recipeTableView.estimatedRowHeight = 256
recipeTableView.rowHeight = UITableView.automaticDimension
}
But it did not work
I think you need to call another tableView method for set the height for each cell according to his content
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// add estimated height here ....
//...
return indexPath.row * 20
}

Is there a way to get the id of a UITableViewCell?

my problem: I want to open some kind of Profil if a user pushes a Button in a Table-View Cell. The Cells Data is downloaded from Parse.
The idea is based on Instagram, if you click on the username-button on Insta the profile from the user who posted the image will open. I want to create the same code, but i can't create the code to get the user. Can you help me?
Heres some code:
import UIKit
import Parse
class HomeController: UIViewController, UITableViewDelegate, UITableViewDataSource {
private let reuseIdentifer = "FeedCell"
var delegate: HomeControllerDelegate?
var newCenterController: UIViewController!
let tableView = UITableView()
//Für Parse:
var users = [String: String]()
var comments = [String]()
var usernames = [String]()
var lastnames = [String]()
var imageFiles = [PFFileObject]()
var wischen: UISwipeGestureRecognizer!
var wischen2: UISwipeGestureRecognizer!
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
getData()
configureNavigationBar()
configurateTableView()
wischen = UISwipeGestureRecognizer()
wischen.addTarget(self, action: #selector(handleMenuToggle))
wischen.direction = .right
wischen.numberOfTouchesRequired = 1
view.addGestureRecognizer(wischen)
wischen2 = UISwipeGestureRecognizer()
wischen2.addTarget(self, action: #selector(handleMenuToggle))
wischen2.direction = .left
wischen2.numberOfTouchesRequired = 1
view.addGestureRecognizer(wischen2)
}
#objc func handleMenuToggle() {
delegate?.handleMenuToggle(forMenuOption: nil)
}
#objc func showProfile() {
let vc: AProfileViewController!
vc = AProfileViewController()
vc.modalPresentationStyle = .fullScreen
present(vc, animated: true)
}
func configureNavigationBar() {
navigationController?.navigationBar.barTintColor = .darkGray
navigationController?.navigationBar.barStyle = .black
navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.font: UIFont(name: "Noteworthy", size: 22)!, NSAttributedString.Key.foregroundColor: UIColor.white]
//navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
navigationItem.title = "Mobile Job Board"
navigationItem.leftBarButtonItem = UIBarButtonItem(image: #imageLiteral(resourceName: "ic_menu_white_3x").withRenderingMode(.alwaysOriginal), style: .plain, target: self, action: #selector(handleMenuToggle))
navigationItem.rightBarButtonItem = UIBarButtonItem(image: #imageLiteral(resourceName: "ic_mail_outline_white_2x").withRenderingMode(.alwaysOriginal), style: .plain, target: self, action: #selector(showCreateNewArticle))
}
//MARK: Table View
//skiped table view configuration
}
// - MARK: Table view data source
func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return comments.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifer, for: indexPath) as! FeedCell
imageFiles[indexPath.row].getDataInBackground { (data, error) in
if let imageData = data {
if let imageToDisplay = UIImage(data: imageData) {
cell.postImage.image = imageToDisplay
}
}
}
cell.descriptionLabel.text = comments[indexPath.row]
cell.userButton.setTitle("\(usernames[indexPath.row]) \(lastnames[indexPath.row])", for: UIControl.State.normal)
cell.userButton.addTarget(self, action: #selector(showProfile), for: .touchUpInside)
return cell
}
//skiped
}
Thanks a lot!
Tom
The issue here is that your button works on a selector and it has no idea about the sender or where it was called from.
I would do this by creating a custom table view cell (e.g. FeedCell) which allows you to set a delegate (e.g. FeedCellDelegate). Set your class as the delegate for the cell and pass into the cell it's current indexPath. You can then return the indexPath in the delegate call.
Example: Note that code has been removed for simplicity and this code has not been tested. This is simply to guide you in the right direction.
View Controller
import UIKit
class HomeController: UIViewController {
// stripped additional information for example
func showProfile(_ username: String) {
let vc: AProfileViewController!
vc = AProfileViewController()
vc.username = username
vc.modalPresentationStyle = .fullScreen
present(vc, animated: true)
}
}
extension HomeController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return comments.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifer, for: indexPath) as! FeedCell
cell.delegate = self
cell.descriptionLabel.text = comments[indexPath.row]
cell.userButton.setTitle("\(usernames[indexPath.row]) \(lastnames[indexPath.row])", for: UIControl.State.normal)
cell.setIndex(indexPath)
return cell
}
}
extension HomeController: FeedCellDelegate {
func didPressButton(_ indexPath: IndexPath) {
let userName = usernames[indexPath.row]
showProfile(username)
}
}
Feed Cell
import UIKit
protocol FeedCellDelegate {
didPressButton(_ indexPath: IndexPath)
}
class FeedCell: UICollectionViewCell {
var delegate: FeedCellDelegate?
var indexPath: IndexPath
#IBOutlet weak var userButton: UIButton
setIndex(_ indexPath: IndexPath) {
self.indexPath = indexPath
}
#IBAction userButtonPressed() {
if(delegate != nil) {
delegate?.didPressButton(indexPath)
}
}
}
You can generically and in a type safe way get the parent responder of any responder with:
extension UIResponder {
func firstParent<T: UIResponder>(ofType type: T.Type ) -> T? {
return next as? T ?? next.flatMap { $0.firstParent(ofType: type) }
}
}
So:
Get the parent tableviewCell of your button in the target action function
Ask your tableview for the index path
Use the index path.row to index into your users array:
#objc func showProfile(_ sender: UIButton) {
guard let cell = firstParent(ofType: UITableViewCell.self),
let indexPath = tableView.indexPath(for: cell) else {
return
}
let user = users[indexPath.row]
... do other stuff here ...
}

How do I add a UIButton into my UITableViewCell in Swift 3?

I have an existing UITableView that displays data and is working fine.
However I now want to add an info button into this UITableViewCell.
I added the UIButton directly into the TableViewCell in storyboard. I then tried to declare this button as an outlet but I got the error
"Outlets cannot be connected to repeating content."
I read around the subject and decided to create a new subclass called "
import UIKit
class PersonalStatsTableViewCell: UITableViewCell {
#IBOutlet weak var personalStatsInfoButton: UIButton!
var selectedCellTitle: String?
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
As you can see I have declared the UIButton personalStatsInfoButton in this sub-class.
With more reading around the subject I believe I need to add something like:
personalStatsInfoButton.tag = indexPath.row
personalStatsInfoButton.addTarget(self, action: "infoButtonClicked", forControlEvents: UIControlEvents.TouchUpInside)
and then have a function:
function infoButtonClicked(sender:UIButton){
let infoCell = sender.tag
print (infoCell)
}
My issue is I don't know whether I need to take all my existing tableView code and transfer it into the the new sub-class PersonalStatsTableViewCell or just the parts that deal with the info button.
Below is my existing VC code that initially deals with the TableView prior to adding in this new button.
import UIKit
class ShowCommunityViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var membersTableView: UITableView!
#IBOutlet weak var communityName: UILabel!
var communityIsCalled: String?
var comIds = [String]()
var communityId: Int?
var selectedCellTitle: String?
var cellId: Int?
var communityPlayerIds = [String]()
var communityPlayers = [String?]()
override func viewDidLoad() {
super.viewDidLoad()
communityName.text = (communityIsCalled)
self.membersTableView.delegate = self
self.membersTableView.dataSource = self
membersTableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.communityPlayers.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PersonalStatsTableViewCell", for: indexPath as IndexPath)
cell.textLabel?.text = self.communityPlayers[indexPath.row]
cell.textLabel?.font = UIFont(name: "Avenir", size: 12)
cell.textLabel?.textColor = UIColor.white // set to any colour
cell.layer.backgroundColor = UIColor.clear.cgColor
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.selectedCellTitle = self.communityPlayers[indexPath.row]
cellId = indexPath.row
}
override func viewDidAppear(_ animated: Bool) {
let myUrl = URL(string: "http://www.???.uk/???/specificCommunity.php?");
var request = URLRequest(url:myUrl!);
request.httpMethod = "POST";
let postString = "id=\(comIds[communityId!])";
request.httpBody = postString.data(using: String.Encoding.utf8);
let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
DispatchQueue.main.async
{
if error != nil {
print("error=\(error)")
return
}
do{
let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:AnyObject]
if let arr = json?["players"] as? [[String:String]] {
self.communityPlayerIds = arr.flatMap { $0["id"]!}
self.communityPlayers = arr.flatMap { $0["user_name"]!}
self.membersTableView.reloadData()
print ("names: ",self.communityPlayers)
}
} catch{
print(error)
}
}
}
task.resume()
}
}
You don't need to put any code in your class PersonalStatsTableViewCell you can manage all the things from ShowCommunityViewController what you need to done is in your cellForRowAt method add this
cell.personalStatsInfoButton.tag = indexPath.row
cell.personalStatsInfoButton.addTarget(self, action: #selector(infoButtonClicked(sender:), forControlEvents: UIControlEvents.TouchUpInside)
and add this function
function infoButtonClicked(sender:UIButton){
let infoCell = sender.tag
print (infoCell)
}
Your code and what you are thinking is correct, you just need to change the following line.
Apart from what Arun B has said, you need to make sure xcode knows what kind of class cell will belong to.
let cell = tableView.dequeueReusableCell(withIdentifier: "PersonalStatsTableViewCell", for: indexPath as IndexPath)
should be
let cell = tableView.dequeueReusableCell(withIdentifier: "PersonalStatsTableViewCell", for: indexPath as IndexPath) as! PersonalStatsTableViewCell
This happens if the custom class is not set up properly. Make sure that PersonalStatsTableViewCell is set as the Custom class of the UITableViewCell in your storyboard.

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.

Resources