-2

I am still new to Swift and coding in general and I am trying to create some kind of option for the user to change colored themes.

But I am clueless on how to access a switch statement in a swift file (or how to encapsulate it) and how to access the set variable?

So far I let the user choose a theme in a settings view controller and the name of the theme is saved in UserDefaults in the key "theme".

In a file called themes.swift I have created a switch statement to check for the names. Each case can obviously set a couple of variables I have declared above the switch statement.

But I get the error that "Statements are not allowed at the top level"?

How can I fix this? And what can I do to let the switch statement run each time a view controller is presented to check for the correct colors or let it run once a new theme is selected and set the variables? I understand the error message but I have no idea on how to fix this.

For instance this is how I have set up the themes.swift file so far:

import UIKit

var theme = UserDefaults.standard.string(forKey: "themes")

var background: UIColor?
var labelColor: UIColor?
var buttonColor: UIColor?


switch theme {
    case "Red":
        background = UIColor(named: "darkRed")
        labelColor = UIColor(named: "labelRed")
        buttonColor = UIColor(named: "buttonRed")
    case "Blue":
        background = UIColor(named: "darkBlue")
        labelColor = UIColor(named: "labelBlue")
        buttonColor = UIColor(named: "buttonBlue")
    default:
        return
}

So how can I access those variables?

Besides the top level error, can I just access the variables like I would normally do because they are global variables?

Eg. startButton.setTitleColor(buttonColor, for: .normal) ?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
RjC
  • 827
  • 2
  • 14
  • 33
  • 2
    Code needs to be in a function. – rmaddy Jan 22 '18 at 19:29
  • 2
    Please **read** the error message. It's very clear. – vadian Jan 22 '18 at 19:34
  • 2
    As maddy said, a switch statement is code that must be in a function to be executed. This is probably a good time for you to dive into enumerations. You can declare an enumeration of themes here, and then add derived values (functions built into the enumeration) to return the theme attributes. – Jerry Jan 22 '18 at 19:34

1 Answers1

1

You are getting this error because you have your switch statement just sitting inside some class or struct (it's not clear where you have this code implemented). To fix your error you will need to put that switch inside a function. Perhaps you could create a function called setTheme, like so:

var theme = UserDefaults.standard.string(forKey: "themes")

var background: UIColor?
var labelColor: UIColor?
var buttonColor: UIColor?

func setTheme() {
  //First, check to make sure theme is not nil
  guard let theme = self.theme else { return }
  switch theme {
  case "Red":
    background = UIColor(named: "darkRed")
    labelColor = UIColor(named: "labelRed")
    buttonColor = UIColor(named: "buttonRed")
  case "Blue":
    background = UIColor(named: "darkBlue")
    labelColor = UIColor(named: "labelBlue")
    buttonColor = UIColor(named: "buttonBlue")
  default:
    return
  }
}

Another option would be to make your UIColor? attributes computed variables. For example:

var background: UIColor? {
  guard let theme = self.theme else { return nil }
  switch theme {
    case "Red": return UIColor(named: "darkRed")
    case "Blue": return UIColor(named: "darkBlue")
    default: return nil
  }
}
creeperspeak
  • 5,403
  • 1
  • 17
  • 38
  • Thanks for the helpful answer. I was already working on this but I get the error: "Expression pattern of type 'String' cannot match values of type 'String?'" - When I use self.theme as you wrote I get the error: "Use of unresolved identifier 'self'"? What could be the problem? – RjC Jan 22 '18 at 20:19
  • OK, @RjC, so you are getting 2 errors. The first one is happening because `theme` is optional (it can be nil), so for your switch statements to work properly you will need to unwrap that optional first. I edited my samples to show one way of doing this, using `guard` statements. – creeperspeak Jan 22 '18 at 20:30
  • @RjC The second error is because it appears you do not have this code inside any class or struct. Where are you implementing this? If you have it implemented in a class file, or in one of your `UIViewController` classes, or inside your `AppDelegate` you will stop getting the error where `self` can't be identified. Or if you're not going to put this inside a class or struct you can just leave the `self` part out - I just assumed this would go inside a class or struct. – creeperspeak Jan 22 '18 at 20:32
  • Thanks for your answers. I got it to work with casting the theme variable as a String: `var theme: String = UserDefaults.standard.object(forKey: "Themes") as! String` - I don't know if this is the right way or if there is an easier way, but it works perfectly fine without any errors. – RjC Jan 23 '18 at 11:45
  • 1
    This is ok, but will crash if there is no string saved in UserDefaults. It'd be better to use a nil-coalescing operator to act as a "default" value. For example, if you want "Red" to be the default of the user hasn't set a different theme you could say `var theme = UserDefaults.standard.string(forKey: "Themes") ?? "Red"` This will make it a `String` rather than `String?`, and will assign the default value of "Red" if no other value is found. – creeperspeak Jan 23 '18 at 21:45