Check UISwitch status on viewDidLoad - ios

I am having problem with status of UISwitch at start. Why is my switch always in the on state?
#IBOutlet weak var switch: UISwitch!
override func viewDidLoad() {
super.viewDidLoad()
if let sw = switch {
if sw.on {
print("on")
} else {
print("off")
}
}
}

The switch will be whatever you set it in the storyboard / interface builder. If you set it to on in the storyboard, it will always be on when the app first loads, and vice versa for setting it to off.
If you want to set it to off when your view first loads (programatically), regardless of what is set in the storyboard, use switch.on = false
If you want the switch's state to be saved when the app is closed, you should look into using NSUserDefaults (here)
Here is a screenshot of the state set in the storyboard:

Related

How to change background color in iOS/XCode on click

I'm trying to learn iOS programming. To start I want to change the background color of my view when a button is clicked. My entire code looks as follows, but when I click the button no change happens. I'm using Xcode 13.1. Also I'm using a storyboard.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var myBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
NSLog("The app has launched")
}
#IBAction func changeColorClicked(_ sender: UIButton) {
self.myBtn.backgroundColor=UIColor.green
NSLog("I want to change color to green")
}
}
I see the NSLog message when I click, just no color change.
Check a few things:
First make sure your IBOutlet and IBAction are connected to the button itself.
You don't need to declare self here as the button as its already declared above and you don't need to call an instance of the view controller you're using to access the button.
You can also declare it like this to change the colour of the button in the function:
myBtn.backgroundColor = .green
To change the button's background colour when pressed.
Update on this thread if you can get it working.

Connect Outlets to Tab View Controller Result in Nil Error

I've created a new window controller that hosts a tabViewController inside my app. I've added classes to the window controller, and have the same class across all the view controllers in the tab view.
I can connect buttons and give them an action and it works perfectly, however, I try to connect an outlet and attempt to change something via the outlet, it returns nil and crashes the program. For example, this exact code works in the pre-made viewController of my app, but returns:
Unexpectedly found nil while implicitly unwrapping an Optional value
when running it through the new tab view controller I created.
What's weird to me is I can use a regular view controller and the outlets connect fine, but if I want to use a tab view controller, these nil errors are happening.
I made sure that the nil was not related to grabbing the inputs for the button by printing the audio devices, and the audio devices are there and able to be printed. It seems as if the button is not there even though it is connected.
I have also tried to simply change an NSTextField color after connecting it to an outlet and this returns the same nil error.
Any idea what I might be doing wrong here? Thanks so much for the help.
class FirstLaunchViewController: NSViewController {
var FLWindow: FirstLaunchWindowController?
var selectedAudioDevice = [String]()
#IBOutlet weak var deviceListPopUpButton: NSPopUpButton!
#IBOutlet weak var visualizeButton: NSButton!
override func viewDidLoad() {
super.viewDidLoad()
self.preferredContentSize = NSMakeSize(self.view.frame.size.width, self.view.frame.size.height)
populateDeviceList()
}
#IBAction func CloseStartupGuide(_ sender: Any) {
self.view.window?.windowController?.close()
}
#IBAction func popUpDidChange(_ sender: Any) {
print("changed")
}
//grab inputs for button
fileprivate func populateDeviceList() {
deviceListPopUpButton.removeAllItems()
for device in AudioDevice.allInputDevices() {
var teststring = ""
teststring = device.uid!
print(device.name)
deviceListPopUpButton.addItem(withTitle: device.name)
deviceListPopUpButton.lastItem?.tag = Int(device.id)
selectedAudioDevice.append(device.uid!)
}
}
}
}

IOS Swift 4 UIView isHidden with tapGestureRecognizer

I got a weird problem.
I made a simple Single View App with a TabBarController, added Subviews to the first Item (ViewController) and made them hidden with the interface builder properties.
Now I want to recognize taps within the entire view to make them visible one after another and hide them again in the end.
The gestureRecogniser is placed from the interface builder. All outlets are properly connected and do work.
Anyway, when I tap the first time the UIViews won't show but the isHidden property is set correctly. I've tried many things and searched SO but nothing really helped in this case. Force-Wrapping everything into the main thread doesn't help either and shouldn't make a difference in this case anyway.
This is my code:
//
// ViewController.swift
//
import UIKit
class ViewController: UIViewController {
var step = 0
#IBOutlet weak var firstViewOutlet: UIView! // properly connected
#IBOutlet weak var secondViewOutlet: UIView! // properly connected
#IBOutlet weak var thirdViewOutlet: UIView! // properly connected
#IBOutlet var tapRecognizer: UITapGestureRecognizer! // properly connected
override func viewDidLoad() {
super.viewDidLoad()
self.tapRecognizer.addTarget(self, action: #selector (self.tapAction(_:)))
print("viewDidLoad")
// Tried to hide them manually on load. Didn't work so I switched back to the interface builder property (checkbox)
// hideSubviews()
}
override func viewDidLayoutSubviews() {
print("viewDidLayoutSubviews")
}
#objc func tapAction(_ sender:UITapGestureRecognizer){
print("Tapped: \(self.step)") // Always works and shows the correct step value
switch self.step {
case 0:
print("Untap should show! \(self.step)") // Shows after first tap
DispatchQueue.main.async {
self.firstViewOutlet.isHidden = false
print("Value of first view state: \(self.firstViewOutlet.isHidden)") // shows false but visible after SECOND tap
self.step += 1
}
// Alternative doesn't change anything
// self.firstViewOutlet.isHidden = false
case 1:
print("Upkeep should show! \(self.step)") // Shows second first tap
DispatchQueue.main.async {
self.secondViewOutlet.isHidden = false
print("Value of second view state: \(self.secondViewOutlet.isHidden)") // shows false but visible after THIRD tap
self.step += 1
}
// Alternative doesn't change anything
// self.secondViewOutlet.isHidden = false
case 2:
print("Draw should show! \(self.step)") // Shows after third tap
DispatchQueue.main.async {
self.thirdViewOutlet.isHidden = false
print("Value of third view state: \(self.thirdViewOutlet.isHidden)") // shows false but visible after FOURTH tap
self.step += 1
}
// Alternative doesn't change anything
// self.thirdViewOutlet.isHidden = true
case 3:
print("Draw should clear! \(self.step)")
hideSubviews() // works after FIFTH tap
// Alternative doesn't change anything
// self.firstViewOutlet.isHidden = true
// self.secondViewOutlet.isHidden = true
// self.thirdViewOutlet.isHidden = true
// self.step = 0
default:
return
}
}
func hideSubviews(){
DispatchQueue.main.async {
self.thirdViewOutlet.isHidden = true
self.firstViewOutlet.isHidden = true
self.secondViewOutlet.isHidden = true
self.step = 0
}
}
}
Funny enough, after the first cicle everything works as espected.
I even tried to add view.layoutIfNeeded(), view.layoutSubviews(), view.setNeedsDisplay() and view.setNeedsLayout() to the outlets and to self.view but it didn't change anything either.
Any suggestions are appreciated. I bet it's a small and stupid bug that I just can't see.
It seems it's any UI change. Even changing the labels colors doesn't work on the first tap.
Steps to reproduce:
Create a new project (Single View Application).
Click ViewController, Editor->Embed in->Tap Bar Controller
Click Library icon, drag Container view to ViewController
Set [hidden] property for this Container view to true in Interface Builder
Create Outlet from Container View to ViewController
Click Library icon, drag Tap Gesture Recognizer to ViewController (not into container view!)
Create Outlet from Container View to ViewController
Copy my code or write from scratch

How to use one IBAction for multiple buttons in Swift?

I have multiple buttons each one with the ability to switch the language of the app. Instead of having to create multiple IBActions for each button is there a way to have them all connected to one IBAction and change the language based on the button pressed? I'm thinking a switch statement would be good to use in this situation but not exactly sure how to set it up.
In Interface Builder, select the Attributes Inspector and set the Tag for each button with a unique number, then you can do something like this:
#IBAction changeLanguage(sender: AnyObject) {
guard let button = sender as? UIButton else {
return
}
switch button.tag {
case 1:
// Change to English
case 2:
// Change to Spanish
case 3:
// Change to French, etc
default:
print("Unknown language")
return
}
}
To connect the action to multiple buttons: in Interface Builder, right-click ViewController in the view hierarchy, then left-click to drag the action connection to each button.
Yes, a switch statement is the way to go here. For a UIButton, you link it to a selector that is called when the user interacts with the button, generally the TouchUpInside event. The addTarget method, and valid selector signatures (apple.com) Of these, you want to use a method in the format #IBAction func doSomething(sender: UIButton) or #IBAction func doSomething(sender: UIButton, forEvent event: UIEvent), so that a reference to the button that triggered the event is passed to the selector.
In your ViewController code, you'll have references to your UIButtons (possibly in a storyboard, or created manually.) Let's say you have
#IBOutlet weak var frenchButton: UIButton!
#IBOutlet weak var spanishButton: UIButton!
#IBOutlet weak var englishButton: UIButton!
You would connect all of them to the same method, and branch the logic based on which one was the sender. e.g.:
#IBAction func changeLanguage(sender: UIButton) {
switch sender {
case frenchButton:
// Change Language to French
print ("C'est si bon")
case spanishButton:
// or Spanish
print ("Muy Bueno")
case englishButton:
// or English
print ("It's pretty cool")
default:
break
}
}
Note: Case statements in Swift must be exhaustive, so you have to include a default case, even though it should never be called.
Do not set tag if you have reference to the button.
You can just compare the reference instead of tags. This way, you won't introduce a new bug, because unlike a tag that you type yourself, reference is created by compiler automatically.
#IBOutlet weak var firstButton: UIButton!
#IBOutlet weak var secondButton: UIButton!
#IBOutlet weak var thirdButton: UIButton!
#IBAction changeLanguage(sender: UIButton) {
if sender == firstButton {
} else if sender == secondButton {
} else if sender == thirdButton {
}
}

How to set selected segment index in UISegmentedControl?

I'm trying to avoid an app crash here... I have a button that will remove a segment from a UISegmentedControl. If that button is pressed and the user has the segment to be removed selected, the segment will remove and no selection will be highlighted. However, when another button is pushed that does an action that retrieves the selectedSegmentIndex, the app crashes.
In short: Is there any way to force the selection of a segment in a UISegmentedControl?
edit it seems as though the UISegmentedControl is returning a selectedSegmentIndex of -1 when no segment is selected... let's see what I can do from here.
Use yourSegmentname.selectedSegmentIndex = 1; or whichever segment you want.
This code is for swift 2.0
#IBOutlet weak var segmentcontroll: UISegmentedControl!
#IBAction func segmentneeded(sender: AnyObject)
{
if(segmentcontroll.selectedSegmentIndex==0)
{
self.view.backgroundColor=UIColor.purpleColor()
segmentcontroll.selectedSegmentIndex=UISegmentedControlNoSegment
}
else if(segmentcontroll.selectedSegmentIndex==1)
{
self.view.backgroundColor=UIColor.yellowColor()
segmentcontroll.selectedSegmentIndex=UISegmentedControlNoSegment
}
else
{
self.view.backgroundColor=UIColor.grayColor()
segmentcontroll.selectedSegmentIndex=UISegmentedControlNoSegment
}
}

Resources