swift. UserDefaults and UISwitch - swift

I'm trying to get UserDefaults to work with a UISwitch, but the switch state is not saving when I force close the app and reopen it.
Update: Got it to work. The switch state will stay in either the "on" or "off" state even when the app is closed.
My code:
let defaults = UserDefaults.standard
#IBAction func switchAction(_ sender: UISwitch) {
defaults.set(true, forKey: "saveTrue")
defaults.set(false, forKey: "saveFalse")
if sender.isOn == false {
sender.setOn(defaults.bool(forKey: "saveFalse"), animated: true)
} else if sender.isOn == true {
sender.setOn(defaults.bool(forKey: "saveTrue"), animated: true)
}
}
ANSWER:;;;
let defaults = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
if let switchValue = getSwitchValue(), switchValue {
switchOutlet.setOn(true, animated: true)
} else {
switchOutlet.setOn(false, animated: true)
}
}
#IBAction func Switch(_ sender: UISwitch) {
if sender.isOn == false {
setSwitchStatus(status: false)
sender.setOn(false, animated: true)
} else if sender.isOn == true {
setSwitchStatus(status: true)
sender.setOn(true, animated: true)
}
}
func setSwitchStatus(status: Bool?) {
if status != nil {
defaults.set(status, forKey: "save1")
}
}
func getSwitchValue() -> Bool? {
return defaults.bool(forKey: "save1")
}

I'm not sure this is what you're looking for but I'd do it like this:
let defaults = UserDefaults.standard
#IBOutlet mySwitch: UISwitch!
//or any other function that is called 'when the app is reopened'
override func viewDidAppear() {
self.mySwitch.setOn(defaults.bool(forKey: "switchDefaultsKey"), animated: true)
}
#IBAction func switchAction(_ sender: UISwitch) {
defaults.set(sender.isOn, forKey: "switchDefaultsKey")
}

Related

Sending a string from one viewcontroller to another using delegate in swift

I'm trying to make a button click in PopupViewController fill a textfield in DagbogsindlaegViewController with a string "svimmelhed, ".
I'm not getting any errors when running the code, but the text is not there when i run the app simulation and press "ButtonPressSvimmelhed" in the class PopupViewController.
Is there a kind stranger who can help me and tell me what i am doing wrong?
Code below:
import UIKit
import EventKit
class DagbogsindlaegViewController: UIViewController{
#IBAction func BackToSVC(_ sender: Any){
self.performSegue(withIdentifier: "BackToSVCSegue", sender: self)
}
#IBAction func ToCalenderButtonPress(_ sender: Any) {
self.performSegue(withIdentifier: "ToCalenderSegue", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
TitleTextField.delegate = self
DescriptionTextField.delegate = self
// Do any additional setup after loading the view.
}
#IBOutlet weak var TitleTextField: UITextField!
#IBOutlet weak var DescriptionTextField: UITextField!
func addEventToCalendar(title: String, description: String?, startDate: Date, endDate: Date, completion: ((_ success: Bool, _ error: NSError?) -> Void)? = nil) {
let eventStore = EKEventStore()
eventStore.requestAccess(to: .event, completion: { (granted, error) in
if (granted) && (error == nil) {
let event = EKEvent(eventStore: eventStore)
event.title = title
event.startDate = startDate
event.endDate = endDate
event.notes = description
event.calendar = eventStore.defaultCalendarForNewEvents
do {
try eventStore.save(event, span: .thisEvent)
} catch let e as NSError {
completion?(false, e)
return
}
completion?(true, nil)
} else {
completion?(false, error as NSError?)
}
})
}
#IBAction func ButtonPressGemDagbog(_ sender: Any) {
addEventToCalendar(title: "\(String(describing: TitleTextField.text!))", description: "\(String(describing: DescriptionTextField.text!))", startDate: NSDate() as Date, endDate: NSDate() as Date)
}
#IBAction func ButtonPressPopupMenu(_ sender: Any) {
let popOverVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PopupViewControllerID") as! PopupViewController
self.addChild(popOverVC)
popOverVC.view.frame = self.view.frame
self.view.addSubview(popOverVC.view)
popOverVC.didMove(toParent: self)
}
}
extension DagbogsindlaegViewController : UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
extension DagbogsindlaegViewController : TextFraPopupDelegate {
func Symptomer(Svimmelhed: String) {
TitleTextField.text = Svimmelhed
}
}
And the other view controller:
import UIKit
protocol TextFraPopupDelegate{
func Symptomer(Svimmelhed: String)
}
class PopupViewController: UIViewController {
var symptomDelegate: TextFraPopupDelegate?
override func viewDidLoad() {
super.viewDidLoad()
self.showAnimate()
self.view.backgroundColor = UIColor.black.withAlphaComponent(0.8)
// Do any additional setup after loading the view.
}
#IBAction func ButtonPressBackToDagbogsindlaeg(_ sender: Any) {
self.removeAnimate()
//self.view.removeFromSuperview()
}
func showAnimate()
{
self.view.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
self.view.alpha = 0.0;
UIView.animate(withDuration: 0.25, animations: {
self.view.alpha = 1.0
self.view.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
});
}
func removeAnimate()
{
UIView.animate(withDuration: 0.25, animations: {
self.view.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
self.view.alpha = 0.0;
}, completion:{(finished : Bool) in
if (finished)
{
self.view.removeFromSuperview()
}
});
}
#IBAction func ButtonPressSvimmelhed(_ sender: UIButton) {
if sender.isSelected {
sender.isSelected = false
} else {
sender.isSelected = true
}
symptomDelegate?.Symptomer(Svimmelhed: "Svimmelhed, ")
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
}
}
As mentioned in the comments the delegate is not set.
However in Swift there is a more convenient way to pass the string back to the presenting view controller, a callback closure. You get rid of the protocol and of the duty to set the delegate
Delete
protocol TextFraPopupDelegate{
func Symptomer(Svimmelhed: String)
}
In PopupViewController replace
var symptomDelegate: TextFraPopupDelegate?
with
var callback : ((String) -> Void)?
and
#IBAction func ButtonPressSvimmelhed(_ sender: UIButton) {
if sender.isSelected {
sender.isSelected = false
} else {
sender.isSelected = true
}
symptomDelegate?.Symptomer(Svimmelhed: "Svimmelhed, ")
}
with
#IBAction func ButtonPressSvimmelhed(_ sender: UIButton) {
sender.isSelected.toggle()
callback?("Svimmelhed, ")
}
In DagbogsindlaegViewController in ButtonPressPopupMenu add the closure
#IBAction func ButtonPressPopupMenu(_ sender: Any) {
let popOverVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PopupViewControllerID") as! PopupViewController
self.addChild(popOverVC)
popOverVC.view.frame = self.view.frame
popOverVC.callback = { string in
self.TitleTextField.text = string
}
self.view.addSubview(popOverVC.view)
popOverVC.didMove(toParent: self)
}
Finally delete
extension DagbogsindlaegViewController : TextFraPopupDelegate {
func Symptomer(Svimmelhed: String) {
TitleTextField.text = Svimmelhed
}
}
Notes:
The syntax (_ success: Bool, _ error: NSError?) -> Void)? is outdated. Since Swift 3 the parameter labels are gone, this is sufficient: (Bool, NSError?) -> Void)?
Don't use NS... classes in Swift if there are native counterparts for example Date
Please conform to the naming convention to name variables and functions / methods with a starting lowercase letter.
The syntax "\(String(describing: TitleTextField.text!))" is double redundant. You create a string from a string from a string. Replace it with TitleTextField.text!

Could not cast value of type 'Pong.MenuVC' (0x1072ea808) to 'Pong.GameViewController'

I have built an app using Xcode and swift 5.
Every time I click the "Easy", "Medium", "Hard" or "2 Player" button I get an error:
Could not cast value of type 'Pong.MenuVC' (0x1072ea808) to
'Pong.GameViewController'
Does anyone know how to fix it?
Thank you for your help.
Code of MenuVC:
enum gameType {
case easy
case medium
case hard
case player2
}
class MenuVC : UIViewController {
#IBAction func Player2(_ sender: Any) {
moveToGame(game: .player2)
}
#IBAction func Easy(_ sender: Any) {
moveToGame(game: .easy)
}
#IBAction func Medium(_ sender: Any) {
moveToGame(game: .medium)
}
#IBAction func Hard(_ sender: Any) {
moveToGame(game: .hard)
}
```
**Code with Thread 1: signal SIGABRT:**
```swift
func moveToGame(game : gameType) {
let gameVC = self.storyboard?.instantiateViewController(withIdentifier: "gameVC") as! GameViewController
currentGameType = game
self.navigationController?.pushViewController(gameVC, animated: true)
}
}
Code of GameViewController:
import UIKit
import SpriteKit
import GameplayKit
var currentGameType = gameType.medium
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
if let scene = SKScene(fileNamed: "GameScene") {
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
scene.size = view.bounds.size
// Present the scene
view.presentScene(scene)
}
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
override var shouldAutorotate: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if UIDevice.current.userInterfaceIdiom == .phone {
return .allButUpsideDown
} else {
return .all
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override var prefersStatusBarHidden: Bool {
return true
}
}
In your storyboard the id gameVC is of type MenuVC not GameViewController so change class name of the vc
let gameVC = self.storyboard?.instantiateViewController(withIdentifier: "gameVC") as! GameViewController

how to save the state of radio button?

i am trying to save the state of my radio button but it doesn't working for me any idea how to do that? i am using userdefaults for that now
class WTSettingsVC: UIViewController {
#IBOutlet weak var checkBttn: DLRadioButton!
#IBOutlet weak var checkBttn2: DLRadioButton!
var switchON : Bool = false
var button : Bool = false
let defaults = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
checkBttn.isSelected = UserDefaults.standard.bool(forKey: "issaved")
checkBttn2.isSelected = UserDefaults.standard.bool(forKey: "issaved")
}
override func viewWillAppear(_ animated: Bool) {
super .viewWillAppear(animated)
self.setCommonNavigationBar(title: "Settings", largeTitle: true, tranpernt: false, tint: WTConstant.LMColors.greenTheme, fontColor: .white)
checkBttn?.isEnabled = UserDefaults.standard.bool(forKey: "switchState")
checkBttn?.addTarget(self, action: #selector(bttnAction(_:)), for: .touchUpInside)
}
#IBAction func bttnAction(_ sender: DLRadioButton) {
if sender.tag == 1 {
sender.isEnabled = true
switchON = true
defaults.set(switchON, forKey: "switchON")
}else if sender.tag == 2{
sender.isEnabled = true
switchON = false
defaults.set(switchON, forKey: "switchON")
}
}
}
UserDefaults.standard.set(sender.isEnabled, forKey: "switchState")
UserDefaults.standard.synchronize()
}
}
Don't use the same key to store state of two buttons. And use same key for storing and retrieving the state of a button.
class WTSettingsVC: UIViewController {
#IBOutlet weak var checkBttn: DLRadioButton!
#IBOutlet weak var checkBttn2: DLRadioButton!
override func viewDidLoad() {
super.viewDidLoad()
checkBttn.isSelected = UserDefaults.standard.bool(forKey: "checkBttnSelected")
checkBttn2.isSelected = UserDefaults.standard.bool(forKey: "checkBttn2Selected")
checkBttn.addTarget(self, action: #selector(bttnAction(_:)), for: .touchUpInside)
checkBttn2.addTarget(self, action: #selector(bttnAction(_:)), for: .touchUpInside)
}
#IBAction func bttnAction(_ sender: DLRadioButton) {
if sender == checkBttn {
UserDefaults.standard.set(true, forKey: "checkBttnSelected")
UserDefaults.standard.set(false, forKey: "checkBttn2Selected")
}else if sender == checkBttn2 {
UserDefaults.standard.set(false, forKey: "checkBttnSelected")
UserDefaults.standard.set(true, forKey: "checkBttn2Selected")
}
}
}
It seems that your code is pretty obviously nested improperly. For example, the following code isn't actually executing in the bttnAction function:
UserDefaults.standard.set(sender.isEnabled, forKey: "switchState")
UserDefaults.standard.synchronize()
This code needs to be placed within the curly bracket above it. Try rewriting your code similarly to this:
class WTSettingsVC: UIViewController {
#IBOutlet weak var checkBttn: DLRadioButton!
#IBOutlet weak var checkBttn2: DLRadioButton!
var switchON : Bool = false
var button : Bool = false
let defaults = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
checkBttn.isSelected = UserDefaults.standard.bool(forKey: "issaved")
checkBttn2.isSelected = UserDefaults.standard.bool(forKey: "issaved")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.setCommonNavigationBar(title: "Settings", largeTitle: true, tranpernt: false, tint: WTConstant.LMColors.greenTheme, fontColor: .white)
checkBttn?.isEnabled = UserDefaults.standard.bool(forKey: "switchState")
checkBttn?.addTarget(self, action: #selector(bttnAction(_:)), for: .touchUpInside)
}
#IBAction func bttnAction(_ sender: DLRadioButton) {
if sender.tag == 1 {
sender.isEnabled = true
switchON = true
defaults.set(switchON, forKey: "switchON")
} else if sender.tag == 2 {
sender.isEnabled = true
switchON = false
defaults.set(switchON, forKey: "switchON")
}
UserDefaults.standard.set(sender.isEnabled, forKey: "switchState")
UserDefaults.standard.synchronize()
}
}
Because these lines of code were outside of the closing bracket for that function, the lines weren't actually included in any function and, thus, would never be called.

update UIViewController in Real Time from Popover Viewcontroller in Swift 4

right now i'm experimenting with SceneKit DebugOptions.
i'm trying to update/ show Scenekits Debug Options in real time, using switch controllers from a Popover ViewController.
i've tried many things, like UserDefaults, Delegation and Protocols, but stil i wasn't able to see the result in real time, every time i have to kill the app en relaunch it to see the results.
so, i would be greatfull if someone would have an answer to my question :D
extension i added to my MainVC
extension ViewController: UIPopoverPresentationControllerDelegate, DebugOptions {
func wireFrameEnabled(enabled: Bool) {
if enabled == true {
print(enabled)
}
}
func showCameraEnabled(enabled: Bool) {
}
func showAllDebugOptions(enabled: Bool) {
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let popoverController = segue.destination.popoverPresentationController, let button = sender as? UIButton else { return }
popoverController.delegate = self
popoverController.sourceRect = button.bounds
let debugMenuVC = popoverController.presentedViewController as! DebugMenuVC
debugMenuVC.delegate? = self
}
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
}
Protocol
protocol DebugOptions {
func wireFrameEnabled(enabled: Bool)
func showCameraEnabled(enabled: Bool)
func showAllDebugOptions(enabled: Bool)
}
DebugMenuVC
class DebugMenuVC: UIViewController {
#IBOutlet weak var bgView: UIView!
#IBOutlet weak var showWireFrameSwitch: UISwitch!
#IBOutlet weak var showCameraSwitch: UISwitch!
#IBOutlet weak var showAllSwitch: UISwitch!
var delegate: DebugOptions?
override func viewWillLayoutSubviews() {
preferredContentSize = CGSize(width: 150, height: 300)
}
override func viewDidLoad() {
super.viewDidLoad()
buttonCheck()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
#IBAction func aSwitchBtnWasPressed( _ sender: UISwitch ) {
if (sender.tag == 0) && (sender.isOn == true) {
userDefaults.set(true, forKey: SHOW_WIRE_FRAME)
delegate?.wireFrameEnabled(enabled: true)
} else if (sender.tag == 0) && (sender.isOn == false) {
userDefaults.set(false, forKey: SHOW_WIRE_FRAME)
delegate?.wireFrameEnabled(enabled: false)
}
}
func buttonCheck() {
if userDefaults.bool(forKey: SHOW_WIRE_FRAME) == true{
showWireFrameSwitch.isOn = true
} else {
showWireFrameSwitch.isOn = false
}
}
}
in debubMenuVC.delegate shouldn't be an optional. thats the reason the delegation method always failed :D
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let popoverController = segue.destination.popoverPresentationController, let button = sender as? UIButton else { return }
popoverController.delegate = self
popoverController.sourceRect = button.bounds
let debugMenuVC = popoverController.presentedViewController as! DebugMenuVC
debugMenuVC.delegate? = self
}

Swift App runs but no buttons appear

I wrote a Swift app but only the window appears when it runs. I can't see any buttons.
Here is my code... I've tried removing the .white attribute thinking maybe it was hidden behind a layer. Nothing.
//
// ViewController.swift
// BraviaRemote
//
// Created by Ed Gilroy on 7/2/17.
// Copyright © 2017 Edward Williams. All rights reserved.
//
import Cocoa
import Alamofire
class ViewController: NSViewController, NSTextFieldDelegate {
#IBAction func MenuButton(_ sender: NSButtonCell) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAABgAw==")
}
#IBAction func ReturnButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAgAAAJcAAAAjAw==")
}
#IBAction func InfoButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAAA6Aw==")
}
#IBAction func GuideButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAgAAAKQAAABbAw==")
}
#IBAction func SelectButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAABlAw==")
}
#IBAction func ChnUpButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAAAQAw==")
}
#IBAction func ChnDownButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAAARAw==")
}
#IBAction func VolUpButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAAASAw==")
}
#IBAction func VolDownButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAAATAw==")
}
#IBAction func LeftButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAAA0Aw==")
}
#IBAction func RightButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAAAzAw==")
}
#IBAction func UpButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAAB0Aw==")
}
#IBAction func DownButton(_ sender: NSButton) {
triggerRemoteControl(irccc: "AAAAAQAAAAEAAAB1Aw==")
}
#IBAction func OnOffButton(_ sender: NSSegmentedControl){
}
#IBOutlet weak var IPField: NSTextField!
var IPAddress: String? {
didSet {
if IPField != nil { IPAddress = "http://\(IPAddress!)/sony/IRCC?" }
else {IPAddress = "http://192.168.2.7/sony/IRCC?"}
if let ip = IPAddress { print (ip) } //Unwraps optional
}
}
override func controlTextDidChange(_ obj: Notification) {
if let txtField = obj.object as? NSTextField {
if txtField.tag == 0 {
//Validation (for later)
IPAddress = txtField.stringValue
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
func viewDidLoad() {
super.viewDidLoad()
}
}
override func viewDidAppear() {
// Window Properties, including solid colour, lack of resize, movable by background.
view.window?.titlebarAppearsTransparent = true
view.window?.backgroundColor = NSColor.white
view.window?.styleMask.remove(.resizable)
view.window?.isMovableByWindowBackground = true
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
struct SOAPEncoding: ParameterEncoding {
let service: String
let action: String
let IRCCC: String
func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var urlRequest = try urlRequest.asURLRequest()
guard parameters != nil else { return urlRequest }
if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
urlRequest.setValue("text/xml", forHTTPHeaderField: "Content-Type")
}
let soapBody = "<?xml version=\"1.0\" encoding=\"utf-8\"?><s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body><u:\(action) xmlns:u=\"\(service)\"><IRCCCode>\(IRCCC)</IRCCCode></u:X_SendIRCC></s:Body></s:Envelope>"
urlRequest.httpBody = soapBody.data(using: String.Encoding.utf8)
return urlRequest
}
}
func triggerRemoteControl(irccc: String) {
Alamofire.request(IPAddress!,
method: .post,
parameters: ["parameter" : "value"],
encoding: SOAPEncoding(service: "urn:schemas-sony-com:service:IRCC:1",
action: "X_SendIRCC", IRCCC: irccc)).responseString { response in
print(response)
}
}
}
Three errors:
First, you are overriding viewDidLoad() and defining another viewDidLoad() inside of it.
Your code:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
func viewDidLoad() {
super.viewDidLoad()
}
}
Should just look like this:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
Second, you are overriding viewDidAppear but never calling super.
Your code:
override func viewDidAppear() {
// Window Properties, including solid colour, lack of resize, movable by background.
view.window?.titlebarAppearsTransparent = true
view.window?.backgroundColor = NSColor.white
view.window?.styleMask.remove(.resizable)
view.window?.isMovableByWindowBackground = true
}
Should look like this:
override func viewDidAppear() {
super.viewDidAppear()
// Window Properties, including solid colour, lack of resize, movable by background.
view.window?.titlebarAppearsTransparent = true
view.window?.backgroundColor = NSColor.white
view.window?.styleMask.remove(.resizable)
view.window?.isMovableByWindowBackground = true
}
Third, you are overriding the IPAdress didSet and then setting it again. This will cause an infinite loop. You are also comparing a textField to nil, which it will never be, because it's a NSTextField!, instead of checking whether it's empty or not. I can't really make sense of what you're trying to achieve here but you should rip all this overriding nonsense out until you can clearly formulate your intention.