I'm stack doing my first app, I searched a lot of tutorials about tableviews, arrays and segues but I can't even figure it out how to resolve my problem, here I go:
I need that the app store a value in an array (class) so I can access it latter (not in the next segue), I did a different app more simple than the last one, just with a UITextfield input and a button to add it to the class. When I move from the user input part to the tableView, the tableView is empty. I will put the code here:
TABLE VIEWCONTROLLER
import UIKit
class NameTableViewController: UITableViewController {
var names = [Name]()
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return names.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "NameTableViewCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier", for: indexPath) as? NameTableViewCell else {
fatalError("The dequeueReusable cell is not an instance of NameTableViewCell")
}
let name = names[indexPath.row]
cell.nameLabel.text = name.name
return cell
}
USER INTERFACE VIEWCONTROLLER:
import UIKit
class ViewController: UIViewController {
var name = [Name]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBOutlet weak var nameTextField: UITextField!
#IBAction func addingButton(_ sender: UIButton) {
let writtenName = nameTextField.text ?? "No name written"
let name1 = Name(name: writtenName)
name.append(name1)
}
}
<!-- end snippet -->
VIEWCELL:
class NameTableViewCell: UITableViewCell {
#IBOutlet weak var nameLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
<!-- end snippet -->
NAME CLASS METHOD:
class Name {
var name: String
init(name: String) {
self.name = name
}
}
!-- end snippet -->
TableView
User Input
Sorry if this is a dumb question, as you may have notice I'm new programming and swift is the first language that I'm learning.
You can use nsuserdefaults https://developer.apple.com/documentation/foundation/nsuserdefaults and store a key decodable struct and later on call it everywhere.
// Save Data
struct People: Codable {
let name: String?
}
var peopleArray = [People]()
let mike = People(name: "mike")
peopleArray.append(mike)
UserDefaults.standard.set(peopleArray, forKey: "people")
// Request Stored Data
func getPeople() -> [People]?{
let myPeople = UserDefaults.standard.data(forKey: "people")
if myPeople == nil {
return nil
}
let peopleArray = try! JSONDecoder().decode([People].self, from: myPeople!)
return peopleArray
}
let people = getPeople()
if(people != nil){
for person in people {
print(person.name)
}
}
Related
So I have been trying to get my custom cells to show up on this tableview, but I am not sure as to why they are not showing up
I have already checked other stack overflow questions and tried their fixes, to no avail. Please ignore the aws stuff as you can see I have the text hard coded so I can just get them to appear for now.
This is the code within the class holding the tableview
import Foundation
import AWSDynamoDB
import AWSCognitoIdentityProvider
import UIKit
// this will be the main feed class showing the user data
class UserDetailTableViewController : UITableViewController {
// attributes for the custome cell
#IBOutlet weak var testing: UITextField!
#IBOutlet var Table: UITableView!
var response: AWSCognitoIdentityUserGetDetailsResponse?
var user: AWSCognitoIdentityUser?
var pool: AWSCognitoIdentityUserPool?
var questiondata : Array<Phototext> = Array()
override func viewDidLoad() {
tableView.delegate = self
tableView.dataSource = self
super.viewDidLoad()
self.pool = AWSCognitoIdentityUserPool(forKey: AWSCognitoUserPoolsSignInProviderKey)
if (self.user == nil) {
self.user = self.pool?.currentUser()
}
// grabbing data from our aws table
updateData()
self.refresh()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationController?.setToolbarHidden(true, animated: true)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.setToolbarHidden(false, animated: true)
}
#IBAction func Questions(_ sender: Any) {
performSegue(withIdentifier: "ask", sender: self)
}
// MARK: - IBActions
#IBAction func signOut(_ sender: AnyObject) {
self.user?.signOut()
self.title = nil
self.response = nil
self.refresh()
}
// reloads the prior view
func refresh() {
self.user?.getDetails().continueOnSuccessWith { (task) ->
AnyObject? in
DispatchQueue.main.async(execute: {
self.response = task.result
self.title = self.user?.username
// saving the user name from the main menu
username123 = self.user?.username! ?? "broken"
})
return nil
}
}
// function that calls to our aws dynamodb to grab data from the
// user
//and re update questions
// the array list
func updateData(){
let scanExpression = AWSDynamoDBScanExpression()
scanExpression.limit = 20
// testing to grabt the table data upon startup
let dynamoDBObjectMapper = AWSDynamoDBObjectMapper.default()
dynamoDBObjectMapper.scan(Phototext.self, expression:
scanExpression).continueWith(block: {
(task:AWSTask<AWSDynamoDBPaginatedOutput>!) -> Any? in
if let error = task.error as NSError? {
print("The request failed. Error: \(error)")
} else if let paginatedOutput = task.result {
// passes down an array of object
for Photo in paginatedOutput.items as! [Phototext] {
// loading in the arraylist of objects
// adding the objects to an arraylist
self.questiondata.append(Photo)
}
DispatchQueue.main.async {
//code for updating the UI
}
}
return ()
})
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// returning the number of rows
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath:
IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier:
"Questionpost", for: indexPath) as! QuestionCell
cell.QuestionText.text = "call it"
cell.Subject.text = "a day"
return cell
}
}
}
Here is the code for the QuestionCell class
import UIKit
class QuestionCell: UITableViewCell {
#IBOutlet weak var Subject: UILabel!
#IBOutlet weak var QuestionText: UITextView!
}
The cell class is called QuestionCell and the identifier I left on the cell in the storyboard is Questionpost
Here is a photo of my story board:
I have fixed it by declaring an extension with the proper types.
extension UserDetailTableViewController: UITableViewDataSource,UITableViewDelegate{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// returning the number of rows
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Questionpost", for: indexPath) as! QuestionCell
cell.QuestionText.text = "call it"
cell.Subject.text = "a day"
return cell
}}
good explanation of what's going on, you need to conform to the UITableViewDataSource and UITableViewDelegate when you inbed a tableview.
Redundant conformance of TableView to protocol UITableViewDataSource with Xib Files
Hi there, i have been trying to fix this for 4 days and still no luck so any help would be appreciated. I am trying to create a table view where workers can upload their profiles and users can scroll through to see which ones they like (see simulator photo) however when i use indexPath.row it fills out the whole cell when i only want it to fill out one label so i can configure the different labels with the data i want.
Here is my Table view controller code:
import UIKit
import FirebaseDatabase
import FirebaseStorage
struct Worker {
var name: String!
var price: String!
}
class SelectATaskerTableViewController: UITableViewController {
var ref: DatabaseReference!
var myList:[String] = []
#IBOutlet var myTableView: UITableView!
var handle: DatabaseHandle!
var storageHandle: StorageHandle!
var storageRef: StorageReference!
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = 111
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(_ animated: Bool) {
myTableView.delegate = self
myTableView.dataSource = self
ref = Database.database().reference()
storageRef = Storage.storage().reference()
handle = ref.child("WorkerProfile").child("Name").observe(.childAdded, with: { (snapshot) in
if let item = snapshot.value as? String {
self.myList.append(item)
self.myTableView.reloadData()
}
})
}
#IBAction func reset(_ sender: Any) {
Database.database().reference().child("WorkerProfile").removeValue()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return myList.count
}
var nameText: String!
var pricePerHourText: String!
var extraDetailsText: String!
var profilePicImage: UIImage!
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:MyCellTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "cell") as! MyCellTableViewCell
cell.firstName.text = myList[indexPath.row]
cell.pricePerHour.text = myList[indexPath.row]
// cell.extraDetails.text = extraDetailsText
// cell.profilePic.image = profilePicImage
// Configure the cell...
return cell
}
And my custom table view cell code
import UIKit
class MyCellTableViewCell: UITableViewCell {
#IBOutlet weak var firstName: UILabel!
#IBOutlet weak var pricePerHour: UILabel!
#IBOutlet weak var extraDetails: UILabel!
#IBOutlet var profilePic: UIImageView!
}
If you have any more questions about the details then please ask :) thank you!!
I'd recommend creating a new function which populates an array of dictionaries.
I haven't tested this but it should work somehow like this. If anyone is able to test this or sees an error right away, please tell me!
There might be some issue regarding userIDs. I'm not too familiar with firebase.
var myList:[[String:String]] = [] // Array of dictionaries now
#IBOutlet var myTableView: UITableView!
var handle: DatabaseHandle!
var storageHandle: StorageHandle!
var storageRef: StorageReference!
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = 111
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewWillAppear(_ animated: Bool) {
myTableView.delegate = self
myTableView.dataSource = self
ref = Database.database().reference()
storageRef = Storage.storage().reference()
handle = ref.child("WorkerProfile").observe(.childAdded, with: { (snapshot) in
if let item = snapshot.value as? NSDictionary {
let itemToAppend = ["name": snapshot["Name"] as? String ?? "",
"pricePerHour": snapshot["PricePerHour"] as? String ?? ""
]
self.myList.append(itemToAppend)
self.myTableView.reloadData()
}
})
}
#IBAction func reset(_ sender: Any) {
Database.database().reference().child("WorkerProfile").removeValue()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return myList.count
}
var nameText: String!
var pricePerHourText: String!
var extraDetailsText: String!
var profilePicImage: UIImage!
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:MyCellTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "cell") as! MyCellTableViewCell
cell.firstName.text = myList[indexPath.row]["name"]
cell.pricePerHour.text = myList[indexPath.row]["pricePerHour"]
// Configure the cell...
return cell
}
I am attempting to display data from Parse onto the following tableView controller. For some reason, the data is not displaying on the tableView (i.e. the rows are blank). I do not think that the data queried from Parse is being appended to the arrays. I am wondering what I'm doing wrong here.
Here's the current output:
I am using a custom prototype cell with identifier "CellTrack" class "TrackTableViewCell" and as shown below:
Here is my code in the TableViewController file:
import UIKit
import Parse
class MusicPlaylistTableViewController: UITableViewController {
var usernames = [String]()
var songs = [String]()
var dates = [String]()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
var query = PFQuery(className:"PlaylistData")
query.findObjectsInBackgroundWithBlock { (objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = objects! as? [PFObject] {
self.usernames.removeAll()
self.songs.removeAll()
self.dates.removeAll()
for object in objects {
let username = object["username"] as? String
self.usernames.append(username!)
print("added username")
let track = object["song"] as? String
self.songs.append(track!)
let date = object["createdAt"] as? String
self.dates.append(date!)
self.tableView.reloadData()
}
}
} else {
print(error)
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return usernames.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CellTrack", forIndexPath: indexPath) as! TrackTableViewCell
cell.username.text = usernames[indexPath.row]
cell.songTitle.text = songs[indexPath.row]
cell.CreatedOn.text = dates[indexPath.row]
return cell
}
}
And here is my code in the "TrackTableViewCell.swift" class:
import UIKit
class TrackTableViewCell: UITableViewCell {
#IBOutlet weak var songTitle: UILabel!
#IBOutlet weak var username: UILabel!
#IBOutlet weak var CreatedOn: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Execute your tableView.reloadData() in main thread.
dispatch_async(dispatch_get_main_queue(), {
self.tableViewCell.reloadData()
})
Try doing a guard let to see if those values are actually coming back as string or not. My guess would be that the value for created at never came back. Try it out and let me know.
guard let username = object["username"] as? String else {
print ("could not get username")
}
self.usernames.append(username)
print("added username")
guard let track = object["song"] as? String else {
print ("could not get song")
return
}
self.songs.append(track)
guard let date = object["createdAt"] as? String else {
print ("could not get createdAt")
return}
self.dates.append(date!)
func dequeueReusableCellWithIdentifier(_ identifier: String) -> UITableViewCell?
Return Value
A UITableViewCell object with the associated identifier or nil if no such object exists in the reusable-cell queue.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("CellTrack", forIndexPath: indexPath) as! TrackTableViewCell
if cell == nil {
// create a new cell here
cell = TrackTableViewCell(...)
}
cell.username.text = usernames[indexPath.row]
cell.songTitle.text = songs[indexPath.row]
cell.CreatedOn.text = dates[indexPath.row]
return cell
}
I have a tableview controller with a custom Prototype Cell. The cell contains 2 labels. I am trying to return 2 values from a Parse class. One field is called Notes and is a String value. The other field is called CreditAmount and is a number value. I am having difficulty returning the number value (Credit Amount) in my tableview.
Here is code for tableview controller:
import UIKit
import Parse
import Foundation
class TableViewController: UITableViewController {
var note = [String]()
var credit = [NSInteger]()
var refresher: UIRefreshControl!
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.reloadData()
updateNotes()
self.refresher = UIRefreshControl()
self.refresher.attributedTitle = NSAttributedString(string: "Pull to refresh")
self.refresher.addTarget(self, action: "refresh:", forControlEvents: UIControlEvents.ValueChanged)
self.tableView.addSubview(refresher)
}
func updateNotes() {
let query = PFQuery(className: "Paydown")
query.findObjectsInBackgroundWithBlock({ (objects:[AnyObject]?, error: NSError?) -> Void in
self.note.removeAll(keepCapacity: true)
self.credit.removeAll(keepCapacity: true)
if let objects = objects as? [PFObject] {
for object in objects {
// var noted = object as PFObject
self.note.append(object["Notes"] as! String)
self.credit.append(object["CreditAmount"] as! NSInteger)
}
self.tableView.reloadData()
} else {
//println(error)
}
self.refresher.endRefreshing()
})
}
func refresh() {
updateNotes()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return note.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! cell
myCell.notesLabel.text = note[indexPath.row]
myCell.amountLabel.text = credit[indexPath.row]
return myCell
}
}
Here is the code for my customer cell:
import UIKit
import Parse
class cell: UITableViewCell {
#IBOutlet weak var notesLabel: UILabel!
#IBOutlet weak var amountLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
The myCell.amountLabel.text = credit[indexPath.row] causes an error: cannot assign a value of type NSInteger (aka int) to a value of type String?. How do I get the number field to work?
Update
myCell.amountLabel.text = credit[indexPath.row]
To be
myCell.amountLabel.text = "\(credit[indexPath.row])"
I have a tableview that is populated with information from a JSON array. I want to make each selected cell segue into a viewController, and in that viewController I have a label the should display what the selected cell says. For example if my cell says California, when I click on the cell it'll open up my viewController and the label would say California.
Seems simple enough, and I've done this before successfully, however this time I'm using JSON to populate my tableView and I'm guessing I'm doing something wrong. With the code posted below, when I click on a cell the titleLabel doesn't even show up.
(My tableView file and DetailsViewController file are posted below, any other swift file I used can be found in my previous question populating Tableview with a function that uses SwiftyJSON)
import UIKit
class EarthTableViewController: UITableViewController {
var info = [AppModel]()
func getEarthquakeInfo(completion: (results : NSArray?) ->Void ){
DataManager.getEarthquakeDataFromFileWithSuccess {
(data) -> Void in
let json = JSON(data: data)
if let JsonArray = json.array {
for appDict in JsonArray {
var ids: String? = appDict["id"].stringValue
var title: String? = appDict["title"].stringValue
var time: String? = appDict["time"].stringValue
var information = AppModel(idEarth: ids, title: title, time: time)
self.info.append(information)
completion(results: self.info)
}
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
getEarthquakeInfo { (info) in
self.tableView.reloadData()
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath) as UITableViewCell
let infoArray = self.info
cell.textLabel!.text = self.info[indexPath.row].title
return cell
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "SEGUE" {
let vc = segue.destinationViewController as DetailsViewController
let cell = (sender as UITableViewCell)
let title = cell.textLabel!.text
vc.titleData = title
}
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return info.count
}
}
My DetailsViewController file:
import UIKit
class DetailsViewController: UIViewController {
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var idLabel: UILabel!
#IBOutlet weak var timeLabel: UILabel!
var titleData: String!
var idData: String!
var timeData: String!
override func viewDidLoad() {
super.viewDidLoad()
var earthInfo = EarthTableViewController()
var getEarthInfo: () = earthInfo.getEarthquakeInfo { (info) in
println("\(info)")
}
titleLabel.text = titleData
idLabel.text = idData
timeLabel.text = timeData
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}