Setting and Saving UISwitch Value Error - swift

My problem is that the UISwitch I have in my settings page keeps reverting to an off state once you leave the settings page meaning there is no way of using the switch properly. I did some searching around and found this question and answer:
How do i keep UISwitch state when changing ViewControllers?
I read this page and added the answer to my code:
#IBOutlet weak var NumSwitch: UISwitch!
override func viewDidLoad() {
super.viewDidLoad()
NumSwitch.isOn = UserDefaults.standard.bool(forKey: "switchState")
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func SaveSwitchPressed(_ sender: UISwitch) {
UserDefaults.standard.set(sender.isOn, forKey: "switchState")
}
However when I run this code I get:
Thread 1: EXC_BAD_INSTRUCTION(code=EXC_1386_INVOP,subcode=0x0)
(Highlighting the line: 'NumSwitch.isOn = UserDefaults.standard.bool(forKey: "switchState")')
[I am using Xcode 8.2.1]
I have connected two UIViewControllers to one ViewController Class so maybe that is causing the problem. I have tried many many other methods to make my switch work properly and this one seems to have worked for other people. Is there anything obvious that I am doing wrong?
[I would have liked to have added this as a comment on the aforementioned question but I do not have the reputation to do so]

If everything is hooked up to your outlets correctly then the following should work:
#IBOutlet weak var NumSwitch: UISwitch!
override func viewDidLoad() {
super.viewDidLoad()
let isOn = UserDefaults.standard.bool(forKey: "switchState")
// If the below statement prints `nil` this is what's causing the crash
print(NumSwitch)
NumSwitch.setOn(isOn, animated: false)
}
#IBAction func SaveSwitchPressed(_ sender: UISwitch) {
UserDefaults.standard.set(sender.isOn, forKey: "switchState")
}
The error Thread 1: EXC_BAD_INSTRUCTION(code=EXC_1386_INVOP,subcode=0x0) usually means that you're trying to force unwrap an optional value. The only thing that could be causing that in your code is if NumSwitch is nil.
I'd also suggest not naming your properties with capital letters, as this can be misleading. Capitalised names are usually used to indicate declared types/classes/structs etc.

Related

Cannot get the SceneView to appear on ViewController

I am brand new to Swift so please go easy on me!
I am basically having trouble with rendering an ARKIT ARSCNView with getting the error:
Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
Here is my code:
Initializing the view here by connecting to the Storyboard
#IBOutlet weak var sceneView: ARSCNView!
Here is the ViewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
setNeedsStatusBarAppearanceUpdate()
// crashes here
sceneView.delegate = self
}
Heres the ViewDidAppear:
override func viewDidAppear(_ animated: Bool) {
DispatchQueue.main.async {
self.animatePulsatingLayer()
self.dowloadModel()
}
}
The animatePulsatingLayer just plays an animation while the model is downloading.
The Download model just downloads the model to weak var node: SCNNode!
I have seen this code working before but since I have integrated SwiftUI into the project it has stopped working.
Any help would be appreciated.
This error mostly occurs when you remove or do not add the reference of the outlet with the .storyboard or .xib files.
I suggest you check them by right-clicking to the view on the storyboard and check if there is a connection.
Like this:
if there is no such connection you can simply connect them like this:

Error message when setting UICollectionView data source and delegate with custom class

I am creating a sort of manual slideshow (i.e., the pictures move when the user taps a forward or backward button), and it is made with a Collection View. I had to create a custom collection cell view class, which I finished, but now I'm getting an error message in the iOS Simulator, "fatal error: unexpectedly found nil while unwrapping an Optional value" even though my code builds successfully. The error is in the ibCollectionView.dataSource = self line, and because I'm new to Swift and OOP (I learned about a month ago for the first time), I am confused by this error message, especially because there are no ? operators. I have included the problem part of my code (the part Xcode showed with the error message) below. Thank you!
import UIKit
class FluidIntakeMainMenuViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
//MARK: - Collection View Properties
#IBOutlet weak var ibCollectionView: UICollectionView!
#IBOutlet weak var ibCollectionViewLayout: UICollectionViewLayout!
var cellArray:[customCollectionViewCell] = Array(repeatElement(customCollectionViewCell(), count: 6))
let displayedCellDimensions = CGSize(width: 343, height: 248)
//MARK: - Xcode-generated Methods
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
ibCollectionView.dataSource = self
ibCollectionView.delegate = self
}
//My code for this class continues down here...
First and most important thing is to check the IBOutlet connection
that you made in your storyboard.
Try to remove the connection in storyboard and then reconnect it.
Secondly put a debugger on to check if it's still nil.
ibCollectionView.dataSource = self
I think you forgot about this:
override func viewDidLoad() {
super.viewDidLoad()
// Register cell classes
ibCollectionView?.register(YourCustomCell.self, forCellWithReuseIdentifier: "Cell")
And use "Cell" identifier in cellForItemAt...

Learning Swift & Xcode - #IBAction func reset for display if UITextField is empty

Disclaimer: I am teaching myself Swift & Xcode so my question is rather simple.
I'm building a simple application to get started, which has a text field connected to a String output.
The lesson I'm on currently has an excerpt which reads:
"The reset method simply needs to clear out the text of both the nameField and the lyricsView—you can do this by setting each of their text properties to an empty string."
I understand this probably involves an if statement, but I think the explanation on this is rather poor.
Here's the viewcontroller:
class ViewController: UIViewController {
#IBOutlet weak var nameField: UITextField!
#IBOutlet weak var lyricsView: UITextView!
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.
}
#IBAction func reset(_ sender: Any) {
}
#IBAction func displayLyrics(_ sender: Any) {
}
}
Can someone explain what they mean by setting the properties of nameField and lyricsView to an empty string in order to reset?
Thanks!
If you want to clear the text of a textField or a textView, just set the text property to an empty string. As your lesson hint:
The reset method simply needs to clear out the text of both the
nameField and the lyricsView—you can do this by setting each of their
text properties to an empty string.
The reset method should like this:
#IBAction func reset(_ sender: Any) {
nameField.text = ""
lyricsView.text = ""
}
To clear those fields I'd use:
#IBAction func reset(_ sender: Any) {
nameField?.text = ""
lyricsView?.text = ""
}
The question mark will safely execute the code even if, for some reasons, those fields are not loaded yet, or have been freed or removed.
ADD this to reset method to remove the content:-
nameField.text = ""
lyricsView.text = ""
When you enter something into nameField something shows up in your lyricsView. So, there should be a way to clear what you've entered (and what is displayed). Hence, the reset function (I guess it's bound to a button).
Once you hit reset the text in nameField and lyricsView should disappear. You can do this by assigning both to something called an empty string, which is just two double-quotes:
let anEmptyString = ""
You'd need to assign the "" to the nameField and lyricsView text property.

ViewController + Storyboard setting up validation with controlTextDidChange

Trying to setup validation for a few text fields in a new (and very small) Swift Mac app. Following various other topics here on SO and a few other examples, I can still not get controlTextDidChange to propagate (to my ViewController).
E.g: How to live check a NSTextField - Swift OS X
I have read at least a dozen variations of basically that same concept. Since none of the accepted answers seem to work I am just getting more and more confused by something which is generally a fairly simple task on most platforms.
I have controlTextDidChange implemented to just call NSLog to let me know if I get anything.
AppDelegate should be part of the responder chain and should eventually handle controlTextDidChange but I see nothing there either.
Using the current Xcode I start a new project. Cocoa app, Swift, Storyboard and nothing else.
From what I can gather the below isolated example should work. In my actual app I have tried some ways of inserting the ViewController into the responder chain. Some answers I found suggested it was not always there. I also tried manually adding the ViewController as the delegate in code theTextField.delegate = self
Nothing I have done seems to get text changed to trigger any events.
Any ideas why I have so much trouble setting up this delegation?
My single textfield example app
Storyboard is about as simple as it gets:
AppDelegate
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate, NSTextFieldDelegate, NSTextDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
func controlTextDidChange(notification: NSNotification) {
let object = notification.object as! NSTextField
NSLog("AppDelegate::controlTextDidChange")
NSLog("field contains: \(object.stringValue)")
}
}
ViewController
import Cocoa
class ViewController: NSViewController, NSTextFieldDelegate, NSTextDelegate {
#IBOutlet var theTextField: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
func controlTextDidChange(notification: NSNotification) {
let object = notification.object as! NSTextField
NSLog("ViewController::controlTextDidChange")
NSLog("field contains: \(object.stringValue)")
}
}
I think the samples you're following are a bit out-of-date.
Try...
override func controlTextDidChange(_ notification: Notification) {
...as the function definition for your method in your NSTextFieldDelegate.

class ViewController has no intitalizers

Here is the line of code causing the error
class ViewController: UIViewController, UITextFieldDelegate {
I'm following a tutorial so I can't imagine why this went wrong.
It was working just fine until I added this function into my code:
//Check if user is already logged in when opening app if so display dashboard page
override func viewDidAppear(animated: Bool){
if PFUser.currentUser() != nil{
if self.theUser.user_db_obj.email == "mike#chicagodrumlessons.com"{
self.performSegueWithIdentifier("adminLogin", sender: self) //dislay admin page
}
else{
self.performSegueWithIdentifier("userLogin", sender: self) //display user page
}
}
}
Here is the only lines of code where the delegate is referenced I believe
override func viewDidLoad() {
super.viewDidLoad()
self.email_tf.delegate = self
self.pass_tf.delegate = self
}
Any idea what caused this error and how to fix it?
My guess is you declare non-optional properties and they aren't initialized when the object is. The compiler is telling you you need an init or two to provide the non-optional properties values before the object can be initialized (or make the properties optionals).