I am trying to initialize and then append Class object to array through delegate func. Delegate Double comes from button press with some data.
var expensesArray = [SpendedMoneyObject]()
var delegatedDouble:Double = 0.0
func setExpenses(expensesFromMainView: Double) {
delegatedDouble = expensesFromMainView
var aSpendedMoneyObject = SpendedMoneyObject(moneySpent: delegatedDouble)
expensesArray += [aSpendedMoneyObject]
self.tableView.reloadData()
}
Problem here is that I am trying to show array at TableViewCell, but it doesn't showing at all, I guess main problem is that expensesArray value is 1 and it's not stacking but replacing same array with other value. Will be really happy to hear what you think.
Edit:
I tried .append and it still the same also TableView func cellForRowAtIndexPath does not getting called.
class ExpensesTableViewController: UITableViewController, ExpensesEnteredDelegate{
//MARK : Properties
var expensesArray = [SpendedMoneyObject]()
var delegatedDouble:Double = 0.0
override func viewDidLoad() {
super.viewDidLoad()
}
func setExpenses(expensesFromMainView: Double) {
delegatedDouble = expensesFromMainView
var aSpendedMoneyObject = SpendedMoneyObject(moneySpent: delegatedDouble)
expensesArray.append(aSpendedMoneyObject)
self.tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return expensesArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "ExpensesCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! ExpensesTableViewCell
print("Iam here")
let expense = expensesArray[indexPath.row]
let fromDoubleToString = "\(expense.moneySpent)"
cell.loadItemsToCell(fromDoubleToString, date: expense.date)
return cell
}
Object class:
class SpendedMoneyObject {
var moneySpent: Double
var currentTime = NSDate().toShortTimeString()
var date: String
init(moneySpent: Double) {
self.date = currentTime
self.moneySpent = moneySpent
}}
Edit: I can now add more than one array by moving new ViewController creation from spendButton func which was creating newVC every time i clicked button. Here are edited code:
protocol ExpensesEnteredDelegate {
func setExpenses(expensesFromMainView: Double)
}
class MainViewController: UIViewController {
#IBOutlet weak var moneyTextField: UITextField!
var delegate: ExpensesEnteredDelegate? = nil
override func viewDidLoad() {
super.viewDidLoad()
// Defining ExpensesVC
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let newExpensesVC = storyboard.instantiateViewControllerWithIdentifier("ExpensesTableView") as! ExpensesTableViewController
delegate = newExpensesVC
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func spentButton(sender: AnyObject) {
// Delegating expenses Double value
if (delegate != nil) {
let myDouble = Double(moneyTextField.text!)
let expenses: Double = myDouble!
delegate!.setExpenses(expenses)
}
}}
But still array's data does not showing up in a tableView
Try this code example:
let aSpendedMoneyObject = SpendedMoneyObject(moneySpent: delegatedDouble)
expensesArray.append(aSpendedMoneyObject)
Or you can use .extend() method if you are looking to append more elements from a different array to your array.
instead of
expensesArray += [aSpendedMoneyObject]
try
expensesArray.append(aSpendedMoneyObject)
Related
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)
}
}
I create uiSegmentedControl in HomePageViewController. There are two items in segmented control. When I select first item , I add sensorItemViewController content as a subview in HomePageViewController with displayContentController method. And when clicked second item, I want to access methods of SensorTabItemViewController class which it's name is reloadMyTableView from HomePageViewConroller. I accessed from sensorItemVC but I get "unexpectedly found nil while unwrapping an Optional value" exception. How can access SensorItemTabViewController from HomePageViewControler correctly ? Thank you all response
HomePageViewController.swift :
let segmentedControlItems = ["Table", "RefreshTableView"]
var viewControllerArray: Array<UIViewController> = []
var segmentedControl : UISegmentedControl!
var sensorItemVC: SensorTabItemViewController!
class HomePageViewController: UIViewController,UIScrollViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
segmentedControl=UISegmentedControl(items: segmentedControlItems)
segmentedControl.selectedSegmentIndex=0
segmentedControl.tintColor=myKeys.darkBlueColor
segmentedControl.layer.cornerRadius = 0.0;
segmentedControl.layer.borderWidth = 1.5
segmentedControl.frame=CGRectMake(0, frameHeight/2, frameWidth, 35)
segmentedControl.addTarget(self, action: "changeSegmentedControlItem", forControlEvents: .ValueChanged)
self.view.addSubview(segmentedControl)
let sensorItemViewController = self.storyboard!.instantiateViewControllerWithIdentifier("sensorTabItemViewController")
viewControllerArray.append(sensorItemViewController)
}
func changeSegmentedControlItem(){
print(segmentedControl.selectedSegmentIndex)
if(segmentedControl.selectedSegmentIndex==0){
displayContentController(viewControllerArray[0])
}
else{
sensorItemVC.reloadMyTableView("Temp value", light: "Light value", noise: "noise Value", motion: "motion Value")
}
}
func displayContentController (content:UIViewController) {
self.addChildViewController(content)
print(self.segmentedControl.frame.height)
content.view.frame=CGRectMake(0, self.frameHeight/2+self.segmentedControl.frame.height, self.frameWidth,
self.frameHeight-(segmentedControl.frame.height*2+self.frameHeight/2))
self.view.addSubview(content.view)
content.didMoveToParentViewController(self)
}
}
SensorTabItemViewController. swift as below :
class SensorTabItemViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
let sensorName=["Sıcaklık Sensörü","Işık Sensörü","Gürültü Sensörü","Hareket Sensörü"]
var sensorDetails=["","","",""]
var sensorImages: Array<UIImage> = []
override func viewDidLoad() {
super.viewDidLoad()
print("sensorTab")
let tempImg=UIImage(named: "temp_ic") as UIImage?
let lightImg=UIImage(named: "light_ic") as UIImage?
let noiseImg=UIImage(named: "noise_ic") as UIImage?
let motionImg=UIImage(named: "motion_ic") as UIImage?
sensorImages.append(tempImg!)
sensorImages.append(lightImg!)
sensorImages.append(noiseImg!)
sensorImages.append(motionImg!)
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func reloadTableView(){
sensorDetails=[]
sensorDetails.append(temp)
sensorDetails.append(light)
sensorDetails.append(noise)
sensorDetails.append(motion)
tableView.reloadData()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sensorName.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("sensorCell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text=sensorName[indexPath.row]
cell.imageView?.image=sensorImages[indexPath.row]
cell.detailTextLabel?.text=sensorDetails[indexPath.row]
return cell
}
}
You never set the value of sensorItemVC. That is why it is nil. I guess that
let sensorItemViewController = self.storyboard!.instantiateViewControllerWithIdentifier("sensorTabItemViewController")
should be replaced with
sensorItemVC = self.storyboard!.instantiateViewControllerWithIdentifier("sensorTabItemViewController") as! SensorTabItemViewController
So I want to create a IOS application that generates a group of students, adds them to a course and then shows students. I can show students in a list in a table view but now I want to let the user touch a student's name and be taken to a page with information about that student (name highest grade etc). The student class is flawless, the course works and the only problem I have is that I can't get a student from one view to the other.
Here's what I have so far:
//
// DataTableViewController.swift
// assignment8
//
import Foundation
import UIKit
class DataTableViewController: UITableViewController {
var delegate:StudentSelectionDelegate! = nil
var students = [Student]();
var course = Course();
// MARK: - UITableViewDataSource
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
func didSelectStudent(controller:UITableViewController, student:Student!) {
controller.navigationController?.popViewControllerAnimated(true)
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
self.course = courseStorage.getCourse();
self.students = course.getArrayOfStudentSortedByLastName();
return course.count;
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let row = indexPath.row
let currentStudent = students[row];
if (delegate != nil) {
delegate.didSelectStudent(self,student:currentStudent)
}
else {
print ("delegate is nil :(");
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("studentCell", forIndexPath: indexPath)
cell.textLabel?.text = students[indexPath.row].lastName + ", " +
students[indexPath.row].firstName;
return cell
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
print("ping");
if segue.identifier == "studentSegue" {
let nextScene = segue.destinationViewController as! studentViewController
// Pass the selected object to the new view controller.
if let indexPath = self.tableView.indexPathForSelectedRow {
let selectedStudent = students[indexPath.row]
print (selectedStudent.firstName);
nextScene.student = selectedStudent;
}
}
}
}
and
//
// DataViewController.swift
// assignment8
//
import UIKit
class DataViewController: UIViewController {
#IBOutlet weak var dataLabel: UILabel!
var dataObject: String = ""
let tableData = ["One","Two","Three"];
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.
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.dataLabel!.text = dataObject
}
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int)
-> Int {
return self.tableData.count;
}
}
and
//
// studentViewController.swift
// assignment8
//
import UIKit
protocol StudentSelectionDelegate {
func didSelectStudent(controller: UITableViewController, student:Student)
}
class studentViewController: UIViewController {
var delegate = StudentSelectionDelegate.self;
var name = String();
var student = Student();
#IBOutlet weak var StudentName: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func didSelectStudent(controller:UITableViewController, student:Student!) {
student.description;
print ("pong")
StudentName.text = student.firstName + " " + student.lastName;
controller.navigationController?.popViewControllerAnimated(true);
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// override func viewWillAppear(animated: Bool) {
// StudentName.text = name
// }
}
This is my storyboard so far.
So, any time I try clicking a student it will print the message that I've decided to use if the delegate is nil. So far I've tried looking at all the other answers on SO but none of them have fixed my issue.
To be able to send information from one view controller to another you should use segues. It seems like that's what you're doing according to the image. If you don't know how to use a segue, you can find a good answer here: Sending data with Segue with Swift
With segues you'll be able to set the delegate of the next view controller:
protocol MyDelegate {
func myFunction()
}
class FirstViewController: UIViewController, MyDelegate {
func myFunction() {
// do what the function does
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let secondVC = segue.destinationViewController as? SecondViewController {
secondVC.delegate = self
}
}
}
class SecondViewController: UIViewController {
var delegate: MyDelegate!
}
Before you segue to the second view controller (you're preparing for the segue), you set the delegate variable of SecondViewController to self, because FirstViewController conforms to MyDelegate protocol so it can be used there. Now, in SecondViewController you can use delegate.myFunction() and it will do whatever is written inside the FirstVC's function, because the FirstVC is SecondVC's delegate.
I have a list of Cities in a TableView and want to pass the data from the cell in TableView to a UIViewController. Now when I pass the data I also want to pass the Latitude and Longitude of those Cities to the UIViewController. Here is the TableViewController code.
class MasterTableViewController: UITableViewController
{
let fruits = ["London", "Melbourne", "Singapore", "Brazil", "Germany", "Monza", "Dallas", "Auckland", "Brussels", "Shanghai", "Sepang", "Barcelona"]
override func awakeFromNib() {
super.awakeFromNib()
}
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: - Segues
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDetail" {
if let indexPath = self.tableView.indexPathForSelectedRow() {
let fruit = fruits[indexPath.row]
(segue.destinationViewController as! ViewController).detailItem = fruit
}
}
}
// MARK: - Table View
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fruits.count
}
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
if (indexPath.row == 0){
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
let fruit = fruits[indexPath.row]
cell.textLabel!.text = fruit
return cell
}
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
}
I can pass City but how would you pass the latitude of the longitude of the cities to the UIViewController. Here is the code for the UIViewController.
class ViewController: UIViewController {
#IBOutlet weak var currentTemperatureLabel: UILabel?
#IBOutlet weak var currentHumidityLabel: UILabel?
#IBOutlet weak var currentPrecipitationLabel: UILabel?
#IBOutlet weak var currentWeatherIcon: UIImageView?
#IBOutlet weak var currentWeatherSummary: UILabel?
#IBOutlet weak var refreshButton: UIButton?
#IBOutlet weak var activityIndicator: UIActivityIndicatorView?
#IBOutlet weak var detailDescriptionLabel: UILabel?
// Location coordinates
let coordinate: (lat: Double, lon: Double) = (37.8267,-122.423)
// TODO: Enter your API key here
private let forecastAPIKey = ""
var detailItem: AnyObject? {
didSet {
// Update the view.
self.configureView()
}
}
func configureView() {
if let detail: AnyObject = self.detailItem {
if let label = self.detailDescriptionLabel {
label.text = detail.description
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.configureView()
retrieveWeatherForecast()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func retrieveWeatherForecast() {
let forecastService = ForecastService(APIKey: forecastAPIKey)
forecastService.getForecast(coordinate.lat, lon: coordinate.lon) {
(let currently) in
if let currentWeather = currently {
dispatch_async(dispatch_get_main_queue()) {
if let temperature = currentWeather.temperature {
self.currentTemperatureLabel?.text = "\(temperature)º"
}
if let humidity = currentWeather.humidity {
self.currentHumidityLabel?.text = "\(humidity)%"
}
if let precipitation = currentWeather.precipProbability {
self.currentPrecipitationLabel?.text = "\(precipitation)%"
}
if let icon = currentWeather.icon {
self.currentWeatherIcon?.image = icon
}
if let summary = currentWeather.summary {
self.currentWeatherSummary?.text = summary
}
self.toggleRefreshAnimation(false)
}
}
}
}
#IBAction func refreshWeather() {
toggleRefreshAnimation(true)
retrieveWeatherForecast()
}
func toggleRefreshAnimation(on: Bool) {
refreshButton?.hidden = on
if on {
activityIndicator?.startAnimating()
} else {
activityIndicator?.stopAnimating()
}
}
}
Add a property for the location to ViewController.
You can then pass the city's location in MasterTableViewController prepareForSegue, similar to how you're passing the city (detailItem) now.
Update:
To pass another parameter, you would add it to your ViewController
var coordinateItem: AnyObject? {
didSet {
// Update the view.
self.configureView()
}
}
and then pass it in prepareForSegue
(segue.destinationViewController as! ViewController).coordinateItem = location
Update 2:
Yes, you can initialize an array of coordinates, and pass a latitude and longitude coordinate.
var locations : [[Double]] = [[51.50722, -0.12750], [-37.8136, 144.9631], ...]
In this case, your coordinateItem would be a [Double].
You can access the two doubles by coordinateItem[0] and coordinateItem[1]
The general concept is the same, regardless of whether you're passing an array or a String.
[This code working very well] This is my situation: I have 2 view controllers, and the second must have TableView. In first view controller i have label and button, when I pressed him, he put me to the second view.Also i passing, when button was pressed: 2 parameters - current time, and another time, which was counted since the program was compile. And my problem is how to put this two parameters to tableView. It must work similar to MasterDetailApplication, where when you press + button it's create a Date in tableView. In my program it must create Date and time when i pressed button and go to the next ViewController. This is my code :
//Parameters.swift
import Foundation
struct Parameters {
let toPass : String
let toPass2: String
}
//SecondViewController
import UIKit
class SecondViewController: UIViewController {
var timer = NSTimer()
var counter = 0
#IBOutlet weak var labelCounter: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.hidesBackButton = true
labelCounter.text = String(counter)
timer = NSTimer.scheduledTimerWithTimeInterval(1,target:self, selector: Selector("update"),userInfo: nil, repeats :true)
}
func update(){
labelCounter.text = String(++counter)
if counter == 15 {
timer.invalidate()
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd hh:mm:ss"
if (segue.identifier == "segueTest") {
var transfer = segue.destinationViewController as TableViewController
transfer.toPass = labelCounter.text
transfer.toPass2 = "\(formatter.stringFromDate(NSDate()))"
}
}
}
//TableViewCOntroller
import UIKit
class TableViewController: UITableViewController {
#IBOutlet weak var label1: UILabel!
var toPass: String!
var toPass2: String!
var objects = [Parameters]()
override func viewDidLoad() {
super.viewDidLoad()
self.objects = [Parameters(toPass: toPass2, toPass2: toPass)]
// self.view.backgroundColor = UIColor(red :184.0, green: 219.0, blue: 243.0)
// self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
// tableView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.objects.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("tableCell", forIndexPath: indexPath) as UITableViewCell
var param : Parameters
param = objects[indexPath.row]
cell.textLabel.text = param.toPass
cell.detailTextLabel?.text = param.toPass2 + " sec"
return cell
}
}
But I have another problem: when I put my button, and when I move to the tableViewController, how to do that my 2 parameters will be saved and stay in that tableViewController? When I close the app, this parameters are lost. How could I save them?