Value of type '_' has no member - ios

In the cb.check(self.rowChecked[indexPath.row]) line under cellForRowAt I'm getting a "Value of type 'LolFirstTableViewController' has no member 'rowChecked'" even though I set up rowChecked to be an array of Booleans with tasks.count number of items. Do I need to initialize rowChecked somewhere else besides cellForRowAt or what am I doing wrong here? The point of this code is to make a checkbox show up in each cell of a table where you can click it to change the accessory to a check mark, and click it again to uncheck it. The check box itself is a separate custom class called CheckButton. I'm still learning Swift so any help would be greatly appreciated! Thank you!
import UIKit
class LoLFirstTableViewController: UITableViewController {
var tasks:[Task] = taskData
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 60.0
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tasks.count
}
#IBAction func cancelToLoLFirstTableViewController(_ segue:UIStoryboardSegue) {
}
#IBAction func saveAddTask(_ segue:UIStoryboardSegue) {
if let AddTaskTableViewController = segue.source as? AddTaskTableViewController {
if let task = AddTaskTableViewController.task {
tasks.append(task)
let indexPath = IndexPath(row: tasks.count-1, section: 0)
tableView.insertRows(at: [indexPath], with: .automatic)
}
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath) as! TaskCell
let task = tasks[indexPath.row]
cell.task = task
var rowChecked: [Bool] = Array(repeating: false, count: tasks.count)
if cell.accessoryView == nil {
let cb = CheckButton()
cb.addTarget(self, action: #selector(buttonTapped(_:forEvent:)), for: .touchUpInside)
cell.accessoryView = cb
}
let cb = cell.accessoryView as! CheckButton
cb.check(self.rowChecked[indexPath.row])
return cell
}
func buttonTapped(_ target:UIButton, forEvent event: UIEvent) {
guard let touch = event.allTouches?.first else { return }
let point = touch.location(in: self.tableView)
let indexPath = self.tableView.indexPathForRow(at: point)
var tappedItem = tasks[indexPath!.row] as Task
tappedItem.completed = !tappedItem.completed
tasks[indexPath!.row] = tappedItem
tableView.reloadRows(at: [indexPath!], with: UITableViewRowAnimation.none)
}

You are declaring rowChecked as a local variable and calling it with self.rowChecked as if it were a class property.
To solve this issue, remove the self. before rowChecked.
Old:
cb.check(self.rowChecked[indexPath.row])
New:
cb.check(rowChecked[indexPath.row])
There might be further issues, but that's the reason for the error as your code currently stands.

You have the line: var rowChecked: [Bool] = Array(repeating: false, count: tasks.count) inside the tableView:cellForRowAt method, so it's a local variable, it's not a property of the LolFirstTableViewController class.
That means you need to change this line: cb.check(self.rowChecked[indexPath.row]) to cb.check(rowChecked[indexPath.row]) (Removed self.).

Related

Swift TableView insert row below button clicked

I am new to Swift and I am using Swift 4.2 . I have a TableView with a label and button . When I press a button I would like to add a new row directly below the row in which the button was clicked . Right now when I click a button the new row gets added to the bottom of the TableView every time. I have been looking at posts on here but haven't been able to get it working this is my code base . I have a method called RowClick I get the indexpath of the row that was clicked but do not know how to use that to get the new row to appear directly below the clicked row .
class ExpandController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var TableSource: UITableView!
var videos: [String] = ["FaceBook","Twitter","Instagram"]
override func viewDidLoad() {
super.viewDidLoad()
TableSource.delegate = self
TableSource.dataSource = self
TableSource.tableFooterView = UIView(frame: CGRect.zero)
// Do any additional setup after loading the view.
}
#IBAction func RowClick(_ sender: UIButton) {
guard let cell = sender.superview?.superview as? ExpandTVC else {
return
}
let indexPath = TableSource.indexPath(for: cell)
InsertVideoTitle(indexPath: indexPath)
}
func InsertVideoTitle(indexPath: IndexPath?)
{
videos.append("Snapchat")
let indexPath = IndexPath(row: videos.count - 1, section: 0)
TableSource.beginUpdates()
TableSource.insertRows(at: [indexPath], with: .automatic)
TableSource.endUpdates()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return videos.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let videoTitle = videos[indexPath.row]
let cell = TableSource.dequeueReusableCell(withIdentifier: "ExpandTVC") as! ExpandTVC
cell.Title.text = videoTitle
cell.ButtonRow.tag = indexPath.row
cell.ButtonRow.setTitle("Rows",for: .normal)
return cell
}
}
This is how my table looks I clicked the Facebook Rows button and it appended the string SnapChat . The Snapchat label should appear in a row below Facebook instead . Any suggestions would be great !
I think the easiest solution without re-writing this whole thing would be adding 1 to the current row of the IndexPath you captured from the action.
let indexPath = TableSource.indexPath(for: cell)
var newIndexPath = indexPath;
newIndexPath.row += 1;
InsertVideoTitle(indexPath: newIndexPath);
I did this from memory because I am not near an IDE, so take a look at the change and apply that change if needed in any other location.
class ExpandController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var TableSource: UITableView!
var videos: [String] = ["FaceBook","Twitter","Instagram"]
override func viewDidLoad() {
super.viewDidLoad()
TableSource.delegate = self
TableSource.dataSource = self
TableSource.tableFooterView = UIView(frame: CGRect.zero)
// Do any additional setup after loading the view.
}
#IBAction func RowClick(_ sender: UIButton) {
guard let cell = sender.superview?.superview as? ExpandTVC else {
return
}
let indexPath = TableSource.indexPath(for: cell)
var newIndexPath = indexPath;
newIndexPath.row += 1;
InsertVideoTitle(indexPath: newIndexPath);
}
func InsertVideoTitle(indexPath: IndexPath?)
{
videos.append("Snapchat")
let indexPath = IndexPath(row: videos.count - 1, section: 0)
TableSource.beginUpdates()
TableSource.insertRows(at: [indexPath], with: .automatic)
TableSource.endUpdates()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return videos.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let videoTitle = videos[indexPath.row]
let cell = TableSource.dequeueReusableCell(withIdentifier: "ExpandTVC") as! ExpandTVC
cell.Title.text = videoTitle
cell.ButtonRow.tag = indexPath.row
cell.ButtonRow.setTitle("Rows",for: .normal)
return cell
}
}
Your current code calls append to add the new item at the end of the array. What you want to do is insert a new row at indexPath.row+1. Array has an insert(element,at:) function.
You have to handle the case where the user has tapped the last row and not add 1 to avoid an array bounds error:
func InsertVideoTitle(indexPath: IndexPath)
{
let targetRow = indexPath.row < videos.endIndex ? indexPath.row+1 : indexPath.row
videos.insert("Snapchat" at:targetRow)
let newIndexPath = IndexPath(row: targetRow, section: 0)
TableSource.beginUpdates()
TableSource.insertRows(at: [newIndexPath], with: .automatic)
TableSource.endUpdates()
}

Swift 3.0 multiple selection with select all cell

I have added data in table view and I have manually added "select all" option to the list at first position, now when the user selects the first option which is 'select all' then the person manually option "Select all" is not selected. Select all, click then work all person or deselect working but signal selection all the person not working "Select all"
I have tried the code below but it's not working so can any one help me to solve this?
var unchecked:Bool = true
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// create a new cell if needed or reuse an old one
let cell = ObjTableview.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! SelectUserCell
// set the text from the data model
cell.selectionStyle = UITableViewCellSelectionStyle.none
cell.lblStudentName.text = getStudentName[indexPath.row]
if UnAll == "unselect" {
if indexPath.row == 0 {
cell.btnCheckbox.setImage(UIImage(named: "unSelectedItem"), for: .normal)
}
if indexPath.row == Int(selectedNumber) {
cell.btnCheckbox.setImage(UIImage(named: "unSelectedItem"), for: .normal)
}
if indexPath.row == Int(unSelectNumber) {
//var j = "\(i)"
cell.btnCheckbox.setImage(UIImage(named: "selectedItem"), for: .normal)
}
}else
{
if(unchecked){
cell.btnCheckbox.setImage(UIImage(named: "unSelectedItem"), for: .normal)
}
else{
cell.btnCheckbox.setImage(UIImage(named: "selectedItem"), for: .normal)
}
}
return cell
}
var UnAll = ""
var selectedNumber = ""
var unSelectNumber = ""
var checkselect:Bool = true
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
UnAll.removeAll()
selectedNumber.removeAll()
unSelectNumber.removeAll()
if(indexPath.row == 0){
btnCheckBoxClick(sender: UIButton())
}else
{
UnAll = "unselect"
btnCheckBoxClick(sender: UIButton())
if checkselect {
selectedNumber = "\(indexPath.row)"
checkselect = false
}else
{
unSelectNumber = "\(indexPath.row)"
checkselect = true
}
print("the selected index is : \(indexPath.row)")
}
}
#IBAction func btnCheckBoxClick(_ sender: Any) {
if(unchecked){
unchecked = false
}
else{
unchecked = true
}
ObjTableview.reloadData()
}
Create a struct for model data with a Bool property. You can modify this property by cell selection.
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var allCharacters:[Character] = []
override func viewDidLoad() {
super.viewDidLoad()
allCharacters = [Character(name: "All"),Character(name: "Luke Skywalker"),Character(name: "Leia Organa"),Character(name: "Advik Shah"),Character(name: "Aarav Modi")]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allCharacters.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
if cell == nil{
cell = UITableViewCell(style: .subtitle, reuseIdentifier: "Cell")
}
cell?.textLabel?.text = allCharacters[indexPath.row].name
if allCharacters[indexPath.row].isSelected
{
cell?.accessoryType = .checkmark
}
else
{
cell?.accessoryType = .none
}
cell?.selectionStyle = .none
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0
{
allCharacters[indexPath.row].isSelected = !allCharacters[indexPath.row].isSelected
for index in allCharacters.indices
{
allCharacters[index].isSelected = allCharacters[indexPath.row].isSelected
}
}
else
{
allCharacters[indexPath.row].isSelected = !allCharacters[indexPath.row].isSelected
if allCharacters.dropFirst().filter({ $0.isSelected }).count == allCharacters.dropFirst().count
{
allCharacters[0].isSelected = true
}
else
{
allCharacters[0].isSelected = false
}
}
tableView.reloadData()
}
}
struct Character
{
var name:String
// var otherDetails
var isSelected:Bool! = false
init(name:String) {
self.name = name
}
}
Creating Array of Struct objects from array of dictionary
let SubjectArray = json["students"] as! [[String:Any]]
allCharacters = SubjectArray.map({ Character(name: $0["studentName"] as! String) })
allCharacters.insert(Character(name:"All"), at: 0)
I like #Pranil's suggestion of using a separate section for the "All" row, so I have stolen that.
You can use an NSMutableIndexSet for tracking the selected rows. This is simpler than having to create a new struct or array of booleans or something. The only thing you do need to be aware of is if your tableview allows row reordering then the index set needs to be adjusted accordingly.
Here is my implementation. The "all" state is determined by the number of selected rows being equal to the number of rows in the data source array.
I have just used simple table view accessories for the checkmarks, but I am sure you can see how to adopt your image based approach in cellForRow(at:)
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableview: UITableView!
let names: [String]? = ["Luke Skywalker","Leia Organa","Advik Shah","Aarav Modi"]
var selectedRows = NSMutableIndexSet()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let names = self.names else {
return 0
}
return 0 == section ? 1 : names.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath)
var text: String
var accessory = UITableViewCellAccessoryType.none
if 0 == indexPath.section {
text = "All"
if self.selectedRows.count == self.names!.count {
accessory = .checkmark
}
} else {
text = names![indexPath.row]
if selectedRows.contains(indexPath.row) {
accessory = .checkmark
}
}
cell.textLabel!.text = text
cell.accessoryType = accessory
return cell
}
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
if indexPath.section == 0 {
if self.selectedRows.count == self.names!.count {
self.selectedRows = NSMutableIndexSet()
} else {
self.selectedRows = NSMutableIndexSet(indexesIn: NSRange(location: 0, length: self.names!.count))
}
tableView.reloadData()
} else {
self.selectedRows.contains(indexPath.row) ? self.selectedRows.remove(indexPath.row) : self.selectedRows.add(indexPath.row)
let rows = [IndexPath(row: 0, section: 0), indexPath]
tableView.reloadRows(at: rows, with: .none)
}
return nil
}
}
I think you are using only one section in the table view. I suggest you use two sections in the table view, so that first section will contain only one row (Select All) and the second section will contain other options. When you click on Select All, that is in the first row of the first section you can make all the rows in the second section as selected while reloading the table view.
// MARK: - struct for cell item
struct CellItem {
var name : String
var isSelected:Bool! = false
init(name: String) {
self.name = name
}
}
class ViewController: UITableViewController {
#IBOutlet var viewTable: UITableView!
// Declare a boolean varaible to toggle the checkbox in the first section of table view
var isSelectAllSelected : Bool = false
var cellData: [CellItem] = []
override func viewDidLoad() {
super.viewDidLoad()
cellData = [CellItem(name: "Luke Skywalker"),CellItem(name: "Leia Organa"),CellItem(name: "Advik Shah"),CellItem(name: "Aarav Modi")]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return 1
}
else
{
return cellData.count
}
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 0
}
// MARK: - Table view delegates
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = TableCell()
cell.selectionStyle = .none
if indexPath.section == 0 {
cell.textLabel?.text = "Select All"
if isSelectAllSelected{
cell.accessoryType = .checkmark
}
else{
cell.accessoryType = .none
}
}
else
{
cell.textLabel?.text = cellData[indexPath.row].name
if cellData[indexPath.row].isSelected{
cell.accessoryType = .checkmark
}
else{
cell.accessoryType = .none
}
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 0
{
cellData[indexPath.row].isSelected = !cellData[indexPath.row].isSelected
isSelectAllSelected = cellData[indexPath.row].isSelected
for index in cellData.indices
{
cellData[index].isSelected = cellData[indexPath.row].isSelected
}
}
else
{
cellData[indexPath.row].isSelected = !cellData[indexPath.row].isSelected
if cellData.filter({ $0.isSelected }).count == cellData.count
{
isSelectAllSelected = true
}
else
{
isSelectAllSelected = false
}
}
viewTable.reloadData()
} }
Hello u can take cheboxbutton action method inside view controller with addtarget method and assign tag indexpath.row so u can easily get the indexpath. from below code u can get the idea.
class ViewController:UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var ObjTableview: UITableView!
var arrStudent = ["1","2","3","4","5"]
var arrSelectedStudent :[Int] = []
var selectAll:Bool = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: UITableViewDataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrStudent.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// create a new cell if needed or reuse an old one
let cell = ObjTableview.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! SelectUserCell
// set the text from the data model
cell.selectionStyle = UITableViewCellSelectionStyle.none
// cell.lblStudentName.text = getStudentName[indexPath.row]
cell.lblStudentName.text = arrStudent[indexPath.row]
cell.btnCheckbox.tag = indexPath.row
cell.btnCheckbox.addTarget(self, action:#selector(btnCheckBoxClick(sender:)), for: .touchUpInside)
if selectAll {
cell.btnCheckbox.setImage(UIImage(named: "selectedItem"), for: .normal)
}else{
if arrSelectedStudent.contains(indexPath.row){
cell.btnCheckbox.setImage(UIImage(named: "selectedItem"), for: .normal)
}else{
cell.btnCheckbox.setImage(UIImage(named: "unSelectedItem"), for: .normal)
}
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
func btnCheckBoxClick(sender: UIButton) {
if sender.tag == 0{
selectAll = true
}else
{
selectAll = false
if let index = arrSelectedStudent.index(of: sender.tag) {
arrSelectedStudent.remove(at: index)
}else{
arrSelectedStudent.append(sender.tag)
}
}
ObjTableview.reloadData()
}}

Where to initialize struct for multiple instances in UITableViewController

I'm making a task-sharing app where you can share multiple lists of tasks with multiple individuals (like one with your spouse, one with your kid, etc.). Each list's data source is a struct called TaskList, so I will have multiple instances of TaskList. Where should I initialize those instances?
I'm new at this and any help would be greatly appreciated!
This is the code for the UITableViewController that creates the task list using struct TaskList:
import UIKit
class LoLFirstTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 60.0
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tasks.count
}
#IBAction func cancelToLoLFirstTableViewController(_ segue:UIStoryboardSegue) {
}
#IBAction func saveAddTask(_ segue:UIStoryboardSegue) {
if let AddTaskTableViewController = segue.source as? AddTaskTableViewController {
if let task = AddTaskTableViewController.task {
tasks.append(task)
let indexPath = IndexPath(row: tasks.count-1, section: 0)
tableView.insertRows(at: [indexPath], with: .automatic)
}
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath) as! TaskCell
let task = tasks[indexPath.row]
cell.task = task
if cell.accessoryView == nil {
let cb = CheckButton()
cb.addTarget(self, action: #selector(buttonTapped(_:forEvent:)), for: .touchUpInside)
cell.accessoryView = cb
}
let cb = cell.accessoryView as! CheckButton
cb.check(tasks[indexPath.row].completed)
return cell
}
func buttonTapped(_ target:UIButton, forEvent event: UIEvent) {
guard let touch = event.allTouches?.first else { return }
let point = touch.location(in: self.tableView)
let indexPath = self.tableView.indexPathForRow(at: point)
var tappedItem = tasks[indexPath!.row] as Task
tappedItem.completed = !tappedItem.completed
tasks[indexPath!.row] = tappedItem
tableView.reloadRows(at: [indexPath!], with: UITableViewRowAnimation.none)
}
}
This is the code for TaskList:
import UIKit
struct TaskList {
var buddy: String
var phoneNumber: String
var tasks: [Task]
}
First option. You can create some kind of manager and store that list in that object:
class TaskListsManager
{
var taskLists:[TaskList] = []
}
And then pass instance of that object between your viewcontrollers:
let taskListsManager = TaskListsManager()
firstViewController.taskListsManager = taskListsManager
secondViewController.taskListsManager = taskListsManager
Second option would be to create a singleton object:
class TaskListsManager
{
static let sharedInstance = TaskListsManager()
var taskLists:[TaskList] = []
}
And you can use it anywhere in your app:
let first = TaskListsManager.sharedInstance.taskLists.first

Swift 3 - Setting variable in TableViewController swift file depending on cell clicked

I'm trying to set the a string depending on which cell in a tableView is clicked. The BlueLineTableViewController is the one which should capture the user's click.
import UIKit
class BlueLineTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return bluelinestations.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "bluelinecell", for: indexPath)
let station = bluelinestations[indexPath.row]
cell.textLabel?.text = station.name
cell.imageView?.image = UIImage(named: station.image)
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let row = indexPath.row
if row == 0 {
BlueBelmontTableViewController().feed = "http://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key=mykey&mapid=40890&outputType=JSON"
}
if row == 1 {
BlueBelmontTableViewController().feed="http://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key=mykey&mapid=40820&outputType=JSON"
}
}
The BlueBelmontTableViewController's feed variable should change/be set to another url depending on which cell is clicked in the BlueLineTableViewController.
import UIKit
class BlueBelmontTableViewController: UITableViewController {
class Destinations {
var destination: String = ""
var time: String = ""
}
var feed = ""
var dataAvailable = false
var records = [Destinations]()
override func viewDidLoad() {
super.viewDidLoad()
parseData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
for r in records {
r.time = ""
r.destination = ""
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataAvailable ? records.count : 15
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if (dataAvailable) {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let destinationRow = records[indexPath.row]
cell.textLabel?.text = destinationRow.destination
cell.detailTextLabel?.text = destinationRow.time
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "PlaceholderCell", for: indexPath)
return cell
}
}
func parseData() {
guard let feedURL = URL(string: feed) else {
return
}
let request = URLRequest(url: feedURL)
let task = URLSession.shared.dataTask(with: request) {(data, response, error) in
if error != nil
{
print("Error")
}
else {
if let content = data {
do {
let json = try JSONSerialization.jsonObject(with: content, options: []) as? [String:Any] ?? [:]
print(json)
if let ctattimetable = json["ctatt"] as? [String:Any] {
if let estArrivalTime = ctattimetable["eta"] as? [[String:Any]] {
for item in estArrivalTime{
if let headingTowards = item["destNm"] as? String,
let arrivalTime = item["arrT"] as? String {
let record = Destinations()
record.destination = headingTowards
record.time = arrivalTime
self.records.append(record)
}
self.dataAvailable = true
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
}
catch {
}
}
}
}
task.resume()
}
}
I've tried setting the url in the didSelectRowAt method depending on the indexPath.row as can be seen in BlueLineTableViewController, but it does not seem to do anything. Does anybody know how I would go about doing this?
Below is the Main.storyboard of this part of my project:
Your are not able to pass value because you are setting feed property to the completely new instance of BlueBelmontTableViewController not the one that is added in navigation stack using your segue that you have created from your UITableViewCell to BlueBelmontTableViewController.
What you need to do is override prepareForSegue in your BlueLineTableViewController to pass your value to BlueBelmontTableViewController.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! BlueBelmontTableViewController
if let indexPath = self.tableView.indexPathForSelectedRow {
if indexPath.row == 0 {
vc.feed = "http://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key=mykey&mapid=40890&outputType=JSON"
}
if indexPath.row == 1 {
vc.feed = "http://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key=mykey&mapid=40820&outputType=JSON"
}
}
}
instead of
BlueBelmontTableViewController().feed = "http://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key=mykey&mapid=40890&outputType=JSON"
use
self.feed = "http://lapi.transitchicago.com/api/1.0/ttarrivals.aspx?key=mykey&mapid=40890&outputType=JSON"
beacause BlueBelmontTableViewController() is initialing new instance of BlueBelmontTableViewController and you want to change the instance you already have so you should use self instead of creating new instance.

Checkbox UIButton title not toggling when tapped

This code is for a tableViewController that lists tasks. When the UIButton is tapped, it's supposed to toggle the button's title from an empty string to a check mark. For some reason when I tap the button in the simulator, nothing happens and there are no errors showing in the console. Anyone know why it's not toggling? The reference code is below. Any help would be greatly appreciated! Thanks everybody!
Here's the UITableViewController code:
import UIKit
class LoLFirstTableViewController: UITableViewController {
var tasks:[Task] = taskData
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 60.0
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tasks.count
}
#IBAction func cancelToLoLFirstTableViewController(_ segue:UIStoryboardSegue) {
}
#IBAction func saveAddTask(_ segue:UIStoryboardSegue) {
if let AddTaskTableViewController = segue.source as? AddTaskTableViewController {
if let task = AddTaskTableViewController.task {
tasks.append(task)
let indexPath = IndexPath(row: tasks.count-1, section: 0)
tableView.insertRows(at: [indexPath], with: .automatic)
}
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath) as! TaskCell
let task = tasks[indexPath.row]
cell.task = task
var rowChecked: [Bool] = Array(repeating: false, count: tasks.count)
if cell.accessoryView == nil {
let cb = CheckButton()
cb.addTarget(self, action: #selector(buttonTapped(_:forEvent:)), for: .touchUpInside)
cell.accessoryView = cb
}
let cb = cell.accessoryView as! CheckButton
cb.check(rowChecked[indexPath.row])
return cell
}
func buttonTapped(_ target:UIButton, forEvent event: UIEvent) {
guard let touch = event.allTouches?.first else { return }
let point = touch.location(in: self.tableView)
let indexPath = self.tableView.indexPathForRow(at: point)
var tappedItem = tasks[indexPath!.row] as Task
tappedItem.completed = !tappedItem.completed
tasks[indexPath!.row] = tappedItem
tableView.reloadRows(at: [indexPath!], with: UITableViewRowAnimation.none)
}
Here's the code for the UIButton:
import UIKit
class CheckButton : UIButton {
convenience init() {
self.init(frame:CGRect.init(x: 0, y: 0, width: 20, height: 20))
self.layer.borderWidth = 2
self.layer.cornerRadius = 10
self.titleLabel?.font = UIFont(name:"Georgia", size:10)
self.setTitleColor(.black, for: .normal)
self.check(false)
}
func check(_ yn:Bool) {
self.setTitle(yn ? "✔" : "", for: .normal)
}
override init(frame:CGRect) {
super.init(frame:frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
You only every call check with cb.check(rowChecked[indexPath.row]) and rowChecked is always an array of [false, false, false, ...].
This should probably be cb.check(tasks[indexPath.row].completed) based on what you're doing in buttonTapped.

Resources