"Initialization of immutable value never used" but is actually used - swift2

I keep getting this error of value is never used. I understand this error pops up with Swift 2.2 often, and it is because the value that is initialized is not used. BUT, I do use this value, and this error pops up 3 other times on errors that I do use and I don't know why I still get it.
Below is the code. "Difficulty" is he variable that the compiler says is not used, but as you can see from my code, it is in fact used. Anyone know why this happens?
class SettingsController: UIViewController {
// MARK: Properties
// Preferences for difficulty level of questions
let preferences = NSUserDefaults.standardUserDefaults()
let difficultyKey = "Difficulty"
let questionnumKey = "QuestionNum"
var difficulty: String = "EASY"
#IBOutlet weak var Easy: DLRadioButton!
#IBOutlet weak var Medium: DLRadioButton!
#IBOutlet weak var Hard: DLRadioButton!
override func viewDidLoad() {
super.viewDidLoad()
readUserDefaults()
setDifficulty()
}
func readUserDefaults(){
let difficulty = preferences.stringForKey(difficultyKey) // <--Error
}
func setDifficulty(){
if difficulty == "HARD"{
Hard.selected = true
}
else if difficulty == "MEDIUM"{
Medium.selected = true
}
else{
Easy.selected = true
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

In readUserDefaults() it should be
difficulty = preferences.stringForKey(difficultyKey)
You need to remove the let: you already have created the difficulty variable earlier.
You also need to use ??, the "nil coalescing operator": preferences.stringForKey(difficultyKey) ?? "EASY", for example, to give a value even if the method call returns nil.
Note: answer made from the comments by #eric-d and #leo-dabus.

Related

lldb error in swift

So I am trying to follow standford's swift lecture series.. However, when I am trying to play the following code, it get 'lldb' error. Any help will be appreciated.. Many thanks
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var display: UILabel!
var userIsIntheMiddleOfTyping = false
#IBAction func touchDigit(_ sender: UIButton) {
let digit = sender.currentTitle!
if userIsIntheMiddleOfTyping {
let textCurrentInDisplay = display.text!
display.text = textCurrentInDisplay + digit
} else {
display.text = digit
}
userIsIntheMiddleOfTyping = true
}
}
It is to note that when the debugger opens the following line of code is highlighted,
let digit = sender.currentTitle!
In the line of code below, you are forcing unwrapping of optional value.
let digit = sender.currentTitle!
The compiler is trying to tell you that.
How to solve the problem?
Make sure that the all the values are connected and are not nil. In this specific case, the #IBOutlet weak var display: UILabel! outlet might not be connected.
If you are not sure that if the value is nil or not, use conditional statements and handle the nil case. For example:
if let digit = sender.currentTitle {
print("Great, its working")
} else {
print("error: currentTitle is nil")
}

Swift 2.0 - variable copied in closure?

I have an array of dictionaries class instance, outlined below:
class SomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
private var array = [[String: AnyObject]]()
override func viewDidLoad() {
super.viewDidLoad()
}
// tableview delegates
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
print(“array address: \(unsafeAddressOf(array))”) // 0x000000015cf0ebd0
let option = UITableViewRowAction(style: .Default, title: “Option”, handler: { [weak self] (_, _) in
guard let strongSelf = self else { return }
print(“array address1: \(unsafeAddressOf(strongSelf.array))” // 0x000000015cd10c50
})
return [option]
}
}
why is the address of array is changed (0x000000015cf0ebd0 vs 0x000000015cd10c50) as I just capture it in UITableViewRowAction initialization?
Thanks,
It's a nature of unsafeAddressOf and Swift Arrays.
A simplified example you can test in the Playground.
(No closure, no strongSelf...)
import Foundation
var str = "Hello, playground"
class MyClass {
var array = [[String: AnyObject]]()
}
let obj1 = MyClass()
let ptr1 = unsafeAddressOf(obj1.array)
let ptr2 = unsafeAddressOf(obj1.array)
print(ptr1 == ptr2)
Tested in Xcode 7.3.1 (Swift 2.2.1) a few times and all printed "false".
The signature of unsafeAddressOf is:
func unsafeAddressOf(object: AnyObject) -> UnsafePointer<Void>
As you know Swift Arrays are value types and you cannot pass them to AnyObject. So, when "bridging to Objective-C" feature is available, your array is converted to NSArray. This conversion is done in a "hard-to-predict" manner, which means, at any time this conversion is made, Swift may allocate a new NSArray instance.
In general, you should not expect something "firm" from unsafeAddressOf when applied to Swift Arrays or other value types.
Because you are assigning self to variable strongSelf, causing the value of self to be copied to the new variable.
Remember that when you assign a variable to another, it's the value that's copied from one to another, not the reference to the memory allocation.
You can try this by printing exactly the same way you are doing the first time:
print("array address: \(unsafeAddressOf(self.array))")
You need to add self in order to access the array class member when inside a closure block.

Why am I receiving these errors when trying to pass a variable on a segue in swift?

I am trying to build upon answer which I was given here. What I am trying to is very simple - I want a text field which you can enter text into. You press the go button and it takes you to a new view and replaces the text on a label on that page with whatever the user entered in the box. The is the code I am using on the first page.
import UIKit
class ViewController: UIViewController {
#IBOutlet var entry: UITextField!
let dictionary = entry.text // Line 7 ERROR
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.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "viewTwo"
{
if let destinationVC = segue.destinationViewController as? viewTwo{
destinationVC.dictionary = self.dictionary // Line 24 ERROR
}
}
}
#IBAction func goToViewTwo(sender: AnyObject) {
performSegueWithIdentifier("viewTwo", sender: self)
}
}
I am only including the code from the first view because i know the code from the second view is working.
I didn't encounter an error until I tried to use the text field - before when I just had a pre-choses text to transfer over it worked. Before, instead of having let dictionary = entry.text I had let dictionary = "foo" and it worked.
So my question is exactly the same thing but have a text field instead of pre-chosen text - what I really want to know is why my code didn't work before.
The errors I got were on line 7 (I have labeled the lines above which had the errors) - 'ViewController.Type' does not have member names 'entry' and there was also an error on line 24 but I suspect this is related to this error and will be fixed if this error is also fixed. Just incase though, the error on line 24 was: 'ViewController.Type' does not have member names 'dictionary'
Thank you.
You should set the dictionary to var dictionary = "" in the declaration. You use var instead of let here, so that you can change the value of the dictionary later.
Then inside your #IBAction func goToViewTwo(sender: AnyObject){} method, you set the self.dictionary = entry.text
#IBAction func goToViewTwo(sender: AnyObject) {
dictionary = entry.text
performSegueWithIdentifier("viewTwo", sender: self)
}
Alternatively, you can just do the following inside prepareForSegue() method.
This way, you dont need to declare a dictionary to hold the text value of your UITextField, you can just pass the text value from your entry to the second view controller's dictionary variable.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "viewTwo"
{
if let destinationVC = segue.destinationViewController as? viewTwo{
destinationVC.dictionary = self.entry.text
}
}
}
A dictionary is not constant, so declare it as lazy var, not let:
lazy var dictionary: String {
return entry.text
}()

Swift Saving data and crash when I attempt to save another value on to original variable

My main issue is one of saving and retrieving data outside of Core Data.
I am looking to save 1 variable with persistent data.
The routine crashes after second button press.
override func viewDidLoad() {
super.viewDidLoad()
var amy="2"
NSUserDefaults.standardUserDefaults().setObject((amy), forKey: "ggpass")
}
#IBAction func pass(sender: AnyObject) {
// Retrieve the original Variable
NSUserDefaults.standardUserDefaults().synchronize()
var aname5 = (NSUserDefaults.standardUserDefaults().objectForKey("ggpass"))! as String
gpass = (aname5.toInt())!
gpass=gpass+1
///Save Data
NSUserDefaults.standardUserDefaults().setObject((gpass), forKey: "ggpass")
}
You are creating the NSUserDefaults as a string, reading it assuming it's a string, and then writing it back as a number - that won't work. You need to either stick to numbers for your values, or strings. Here's a version sticking to strings - a bit clumsy, but closest to your existing code:
#IBAction func pass(sender: AnyObject) {
var aname5 = NSUserDefaults.standardUserDefaults().objectForKey("ggpass") as? String
if let gpass = aname5?.toInt() {
NSUserDefaults.standardUserDefaults().setObject("\(gpass+1)", forKey: "ggpass")
}
}
Note that you don't need the synchronize() call in iOS8 or Yosemite, see http://www.codingexplorer.com/nsuserdefaults-a-swift-introduction/.
Retrive the original value of amy by using this code:
amy = NSUserDefaults.standardUserDefaults().integerForKey("ggpass")
Then assign its value to aname5.
var aname5 = amy
Your code now looks like:
#IBAction func pass(sender: AnyObject) {
amy = NSUserDefaults.standardUserDefaults().integerForKey("ggpass")
var aname5 = amy
gpass = (aname5.toInt())!
gpass++
///Save Data
NSUserDefaults.standardUserDefaults().setObject((gpass), forKey: "ggpass")
}

How to create global variable in Swift?

I am trying to set a global variable. In my case, just a boolean flag that indicates if a view is being presented for the first time:
var initialLoadFlag: Bool = true
After the view is presented, I want to set this flag to false:
var initialLoadFlag: Bool = false
And then check for it thenceforth:
if initialLoadFlag {
showWelcomeMessage()
}
So, I would like to create initialLoadFlag as a global variable. Where and how? I've tried:
In the viewDidLoad area of my view controller
In the application() method in my AppDelegate.swift file
In the AppDelegate class
No luck. I'm getting a Use of unresolved identifier 'initialLoadFlag' error message
(Note: I realize that in this question I betray my ignorance of how scope is handled in Swift. Please forgive me... I'm on a deadline, and still new to the language.)
Thanks for your help.
You can define a struct with static field:
struct MyViewState {
static var initialLoadFlag = false
}
Usage:
// set
MyViewState.initialLoadFlag = true
// get
let state = MyViewState.initialLoadFlag
println("My view state:\(state)")
Remarks:
Such hacks as singletons and global vars are usually needed in case of bad design. Maybe you can store your state in NSUserDefaults? Or store it in some session object that can be injected in any ViewController that needs to be aware about context.
You could store a flag in the master controller and set it to true when you perform the segue to the details controller. E.g.
class MasterViewController: UIViewController {
var firstTimePresenting = true
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDetail" {
if firstTimePresenting {
println("First time!")
firstTimePresenting = false
}
}
}
}

Resources