How to reload view after data changes in Swift - ios

I have a view that contains labels, and have a button to change the values of the labels. Instead of changing the values one by one in the button, how can I reload the whole view to update the labels.
#IBOutlet weak var one: UILabel!
#IBOutlet weak var two: UILabel!
#IBOutlet weak var three: UILabel!
....
#IBOutlet weak var updateLabels: UIButton!{
//doing something to change the value of the labels
//then wanna reload the whole view
viewDidLoad()
}
I had called the viewDidLoad() method, but didn't work.

You should never call viewDidLoad yourself. It's a framework function that the OS calls, as an indication that your views are ready to be setup.
It would serve better if you separated your function
func updateLabels() {
one.text = "one"
two.text = "two"
three.text = "three"
}
and now you can call the updateLabels function when you want.

Why dont you put all labels on a method. and fire it when ever you need to reload.
override func viewDidLoad() {
super.viewDidLoad()
updateLabels()
}
func updateLabels() {
one.text = "one"
two.text = "two"
three.text = "three"
}
#IBAction func updateLabels(_ sender: Any) {
updateLabels()
}

Your method of updating your labels is incorrect. What you need to do is as follows:
Declare your labels like you did ensuring they are linked in Interface Builder:
//Declare The Labels
#IBOutlet var one: UILabel!
#IBOutlet var two: UILabel!
#IBOutlet var three: UILabel!
Then create an IBAction function which is triggered by a UIButton:
/// Set The Text Labels Text
#IBAction func updateLabelText(){
//Set Label Text
one.text = "one"
two.text = "two"
three.text = "three"
}
Of course remembering to link this to the UIButton instance in Interface Builder.
Hope this helps.

Related

Disable all UIButtons in UITableViewCell once a separate UIButton is pressed

Problem I've found some questions asking how to disable a particular cell button in a table view, but what I want to do is to disable all instances of a button within a table view cell when another button is pressed.
Details I have a table view which is displaying a list of exercises and number of reps in a custom cell. Within the custom cell is also a button "swap" which allows a user to swap an exercise for another one before the workout starts.
When the user hits "start workout" (which triggers a timer) I want to disable all instances of the swap button (grey them all out and make non clickable).
Code
My workout cell class is here :
class WorkoutCell : UITableViewCell {
var delegate: WorkoutCellDelegate?
#IBAction func swapButtonPressed(_ sender: Any) {
delegate?.swapButtonTapped(cell: self)
}
#IBOutlet weak var exerciseName: UILabel!
#IBOutlet weak var repsNumber: UILabel!
}
protocol WorkoutCellDelegate {
func swapButtonTapped(cell: WorkoutCell)
}
What have I tried
The way I thought to do this was to add an IBOutlet (e.g. 'swapButton') for the button and then simply do something like :
#IBAction func startButtonPressed(_ sender: UIButton) {
WorkoutCell.swapButton.isenabled = false
}
But Xcode doesn't allow you to add IBOutlets to repeating cells so I'm a bit stuck.
I'm fairly new to delegates (managed to get it working for displaying the table view) so if it has something simple to do with that sorry!
Add a property to your viewcontroller:
var swapButtonsDisabled : Bool = false
In your cellForRow do something like this:
cell.swapButton.isEnabled = !self.swapButtonsDisabled
When the start button is pressed, set swapButtonDisabled to true and reload the tableView.
1- As you connect
#IBOutlet weak var exerciseName: UILabel!
create outlet for every btn
#IBOutlet weak var btn1: UIButton!
2- Add a property to the model array in the VC to hold the state of every cell
3- When you click the main btn fire the delegate method with the btn's cell
4- In VC delegate handle method disable the btns and change the state of the array index path
5- Don't forget to check state in cellForRow
You are pretty close. First I suggest you to be more specific and have the data you need in cell and use access control:
class WorkoutCell : UITableViewCell {
var workoutSwappable: (workout: Workout, canBeSwapped: Bool)? {
didSet {
swapButton.isEnabled = workoutSwappable?.canBeSwapped == true
// TODO: do additional setup here
}
}
weak var delegate: WorkoutCellDelegate? // Needs to be weak or you will have memory leaks
#IBAction private func swapButtonPressed(_ sender: Any) {
if let workoutSwappable = workoutSwappable, workoutSwappable.canBeSwapped == true {
delegate?.workoutCell(self, didTapWorkoutSwap: workoutSwappable.workout)
}
}
#IBOutlet private var exerciseName: UILabel!
#IBOutlet private var repsNumber: UILabel!
#IBOutlet private var swapButton: UIButton!
}
Ok so now in cell for row at index path all you need is something like:
cell.workoutSwappable = (self.items[0], self.canSwap)
On delegate you now have:
func workoutCell(_ sender: WorkoutCell, didTapWorkoutSwap workout: workout) {
self.currentWorkout = workout
self.canSwap = false
self.initializeTimer()
tableView.reloadData() // This will now flush all the buttons
}

Variable array with UITextfiles

I create in the ViewControler a variable with an array of UITextFields like this:
var arrayTextFields = [textField1, textField2, textField3]
I want to use it in the ViewDidLoad or in a function but I can’t.
What do I have to do?
Assuming you have connected the outlets to UITextViews You need to define it within the class declaration and not in any of the methods.
class ViewController: UIViewController {
// Outlets
#IBOutlet var textField1: UITextField!
#IBOutlet var textField2: UITextField!
#IBOutlet var textField3: UITextField!
// define and initialize empty array, can be accessed anywhere within the class
var arrayTextFields: [UITextField] = []
override func viewDidLoad(animated: Bool) {
// set the array in viewDidLoad
arrayTextFields = [textField1, textField2, textField3]
}
}
You have to make sure you connect it to your source file by dragging it from the storyboard while holding "control". then if you follow the code mentioned above, you should have access to do whatever you want.

Passing data between view controllers inside page view controllers in Swift

Sorry if this particular problem has been asked about, I followed the answers on other threads but none of them seemed to work, but I just started learning Swift so all of this is pretty new to me.
So, I have a text field in two View Controllers and I want the third View Control to display a result based on the input from the other two controllers when I press a button.
I followed this tutorial and placed the text fields, label and button like I said before.
I placed my code (which you can see below) inside ViewControl.swift.
The problem is that when I attempt to run it I get a "Thread 1 :EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)" error in the last two lines.
class ViewController: UIViewController {
var a: String = ""
var b: String = ""
#IBOutlet weak var aTextField: UITextField!
#IBOutlet weak var bTextField: UITextField!
#IBOutlet weak var calculateButton: UIButton!
#IBOutlet weak var resultLabel: UILabel!
#IBAction func calculateButtonPressed(_ sender: UIButton) {
let a = aTextField.text!;
let b = bTextField.text!;
I think that the error is from the data not passing between the views (because before I had everything in the same view and it worked fine), but since I only have one ViewController.swift file I couldn't figure out how to use a Segue.
Do not declare same variables multiple times. Remove let before a & b . You have already declared a & b globally and then tried to redeclare it inside IBAction
class ViewController: UIViewController {
var a: String = ""
var b: String = ""
#IBOutlet weak var aTextField: UITextField!
#IBOutlet weak var bTextField: UITextField!
#IBOutlet weak var calculateButton: UIButton!
#IBOutlet weak var resultLabel: UILabel!
#IBAction func calculateButtonPressed(_ sender: UIButton) {
a = aTextField.text!;
b = bTextField.text!;
Make sure your control outlets are setted properly.
In your two variables a & b are re-declared.Just update your code like below
#IBAction func calculateButtonPressed(_ sender: UIButton) {
self.a = aTextField.text!
self.b = bTextField.text!
}

swift photo reveal timer set up

I am trying to add a photo reveal quiz piece to a larger app that I'm creating. The picture of the set up looks like this so far(rough draft so to speak)
The 16 labeled items are there just to give a sense of the end product(they will be white tiles in the app). How can I program it so that they begin disappearing when they user taps reveal picture? NSTimer? Should they be labels or UIViews or ?? Thanks for any hints.
I can get this far, but would want to add code to make the tiles disappear randomly and roughly each second
import UIKit
class ViewController: UIViewController {
var gameTimer : NSTimer!
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var tile15: UILabel!
#IBOutlet weak var tile16: UIView!
#IBOutlet var photoTilesHandler: [UIView]!
//#IBOutlet weak var viewTile: UIView!
//#IBOutlet var pictureTiles: [UILabel]!
#IBOutlet var buttonHandler: [UIButton]!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func revealButton(sender: AnyObject) {
Hide()
print("button pressed")
}
func Hide() {
var dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
dispatch_after(dispatchTime, dispatch_get_main_queue(), {
self.tile15.hidden = true
})
}
override func viewDidDisappear(animated: Bool) {
gameTimer.invalidate()
}
}
Put all of your UILabels/UIViews/etc in an IBOutletCollection. Then inside of dispatch_after's callback do the following steps:
0.- You might want to keep track of which tiles are already facedown. So this way you can know at every time which index you have already used and pick always new ones.
One way to achieve this is storing the full list of indexes available to select and instead of taking into account your IBOutletCollection for the following steps take as reference your unused indexes list and, after you randomly pick one, remove it from the list.
1.- Determine a/(a set of) random integers between 0...[your IBOutletCollection].length - 1]
2.- Use this numbers as an index to set the hidden property of [your IBOutletCollection] corresponding element to true
As your other question, my recommendation would be to use UIViews with your UILabel inside or UIButtons. The tap zone of labels is a bit hard to use.

Passing data from several VC's to a last one in Swift

As you can appreciate in this pic we have an App with three different VC's and a Last one with some variable data depending of the options selected on the previous ones.
So, for instance, in this case the user had selected a blue color, a suited style and a L as size.
Our idea is to pass data from the first VC, second VC, and the third VC to the gaps in Last VC.
Any suggestions? It would be very appreciated.
Create a model class where you can store those properties in :
class MyChoices {
var color : String? // or you could use enums for each of them
var style : String? // that would be a better choice, but for the
var size : String? // sake of simplicity I use strings in this example
}
then you pass a variable of type MyChoices from one VC to another in your prepareForSegue method
EDIT (some more info, see answer from FactorJose)
In VC 1 add your variable
class VC1: UIViewController {
#IBOutlet weak var nextOutlet: UIButton!
#IBOutlet weak var colourLabel: UILabel!
var choice : MyChoice?
...
and then further on :
#IBAction func redButton(sender: AnyObject) {
nextOutlet.hidden = false
colourLabel.text = "Red colour selected"
choice.color = "Red"
}
for all those IBActions.
then in your prepareForSegue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let nextVC = segue.destinationViewController as! VC2
nextVC.choice = self.choice
}
VC2 and VC3 are very similar again
Hi all! As you can appreciate in this pic we have an App with three different VC's and a Last one with some variable data depending of the options selected on the previous ones.
So, for instance, in this case the user had selected a blue color, a suited style and a L as size.
Our idea is to pass data from the first VC, second VC, and the third VC to the gaps in Last VC.
Any suggestions guys? It would be very appreciated
Code :
class VC1: UIViewController {
#IBOutlet weak var nextOutlet: UIButton!
#IBOutlet weak var colourLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
nextOutlet.hidden = true
}
#IBAction func redButton(sender: AnyObject) {
nextOutlet.hidden = false
colourLabel.text = "Red colour selected"
}
#IBAction func blueButton(sender: AnyObject) {
nextOutlet.hidden = false
colourLabel.text = "Blue colour selected"
}
#IBAction func greenButton(sender: AnyObject) {
nextOutlet.hidden = false
colourLabel.text = "Green colour selected"
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {}
}
VC2 and VC3 are the same as VC1 (same outlets and buttons)
lastVC
#IBOutlet weak var colourLabel: UILabel!
#IBOutlet weak var styleLabel: UILabel!
#IBOutlet weak var sizeLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
And the last class to store the strings
import UIKit
class MyChoices {
var colour : String?
var style : String?
var size : String?
}
What can we do?
An alternative to Glenn's answer is to use NSUserDefaults. Think of it like a mini key-value database for PropertyLists.
You can add a new key-value to it with
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(clothingColor, forKey: "Clothing Color")
And then retrieve a previously saved key-value by doing
let defaults = NSUserDefaults.standardUserDefaults()
let clothingColor = defaults.objectForKey("Clothing Color")
Since the user defaults is shared and stored in disk, the information will persist across your different view controllers. It also respects encapsulation, which is good object orientation practice, since your size controller won't have to know anything about color or style and vice versa.

Resources