NSUserDefault give EXC_BAD_ACCESS trying to get values - swift

I'm using NSUserDefaults in my app to store some flag values. My function increases the value each time that a condition has occurred. Occasionally it works, but most of the time it crashes and get an EXC_BAD_ACCESS message.
var sample1: Int = countWord.integer(forKey: "countWord1")
var sample2: Int = countWord.integer(forKey: "countWord2")
var sample3: Int = countWord.integer(forKey: "countWord3")
Those are the lines where I get the error.
EDIT
This is how I initialize and setcountword
let countWord = UserDefaults.standard
countWord.set(sample1+1, forKey: "countWord1")
Application crashes after repeatedly iterated function

I don't think these are the lines your app is crashing. For exc-bad-access you usually have to trace way back. You can use Instrument to trace it.
The variables defined in the controller and methods are well handled by ARC. This usually happens when you have two controller, for example, ViewController A is trying to access ViewController B's strong variable after ViewController B is deallocated.

Related

NSTextField: Converting String to Int aborts (nil) outside of Xcode

I have a MacOS app that has been working fine for around a year. An NSTextField on a screen containing 20 NSTextFields started aborting with "unexpectedly found nil while unwrapping an Optional value". So far, I've done the following:
Removed and reassigned the textfield's IBOutlet link
Deleted and rebuilt the textfield
This fixes the app when I run in Xcode in my Development account. When I generate an archive and transfer it to my Production account, it still aborts.
I'm going to assume this is still the culprit, since I don't really get much from the core dump (because I probably don't understand what I'm looking at).
Here's my code. (game_number is an Int)
game_number = Int(gameNumberTextField.stringValue)!
When I split the code and do this:
let theNumber = (gameNumberTextField.stringValue)!
game_number = Int(theNumber)
theNumber is a String and correct, but game_number is nil
NSTextField parent class NSControl has a property called integerValue which returns an Int:
game_number = gameNumberTextField.integerValue
You should unwrap the optional value like this:
guard let theNumber = gameNumberTextField.integerValue else {
// Value not found, handle this case
return
}
Hope this helps!

What does it mean thread 1 exc_bad_instruction (code=exc_i386_invop subcode=0x0)

I got this problem when I tried to delegate scores from GameViewController to ViewController:
It works normally if I remove bestName.
The first time you run your app there will be no values in UserDefaults.
This means that in viewDidLoad, the call to:
UserDefaults.standard.string(forKey:)
will return a nil value. But you are assigning the result to a non-optional variable.
Change the line to:
if let name = UserDefaults.standard.string(forKey:"bestName") {
bestName = name
}
There is no problem with the call to integer(forKey:) because it returns 0 if there is no existing value.

Using NSSpeechStatusNumberOfCharactersLeft to update a progress indicator for NSSpeechSynthesizer

I'm new to Swift and OS X programming. I'm trying to use a progress monitor to indicate the progress of my speech synthesizer speaking text.
let speechSynthesizer = NSSpeechSynthesizer()
speechSynthesizer.delegate = self;
speechSynthesizer.startSpeakingString(contents)
I would like to set
progressIndicator.maxValue = Double(NSSpeechStatusNumberOfCharactersLeft.characters.count)
and then periodically update the progressIndicator with NSSpeechStatusNumberOfCharactersLeft, which according to Apple's documentation should hit 0.
Every way I try to access this key, it returns the same inaccurate number, so I'm obviously not using it correctly. The only example I found was in Objective-C
NSNumber *n = [[self.speechSynth objectForProperty:NSSpeechStatusProperty error:NULL] objectForKey:NSSpeechStatusNumberOfCharactersLeft];
and I tried to translate that to Swift, but still, no dice.
let count = try speechSynthesizer.objectForProperty(NSSpeechStatusProperty).objectForKey(NSSpeechStatusNumberOfCharactersLeft)
I've also tried
speechSynthesizer.valueForKey(NSSpeechStatusNumberOfCharactersLeft))
speechSynthesizer.valueWithName(NSSpeechStatusNumberOfCharactersLeft, inPropertyWithKey: NSSpeechStatusProperty))
which throw runtime exceptions. Any thoughts? Thanks in advance!
Your second attempt is pretty close to correct:
let count = try speechSynthesizer.objectForProperty(NSSpeechStatusProperty).objectForKey(NSSpeechStatusNumberOfCharactersLeft)
Without an error message (and since I don't have a Swift 2 compiler handy) I'm guessing the reason that this fails is that the return value of objectForProperty isn't known to be an dictionary, so you can't look up values in it.
Here's my quick & dirty Swift 3 playground for testing this:
import PlaygroundSupport
import Cocoa
let synth = NSSpeechSynthesizer()
synth.startSpeaking("I'm not standing still, I am lying in wait")
// quick way to test for progress without setting up an app and delegate
PlaygroundPage.current.needsIndefiniteExecution = true
let timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
let statusDict = try! synth.object(forProperty: NSSpeechStatusProperty) as! [String: Any]
print(statusDict[NSSpeechStatusNumberOfCharactersLeft])
}
(Obviously, you don't need all the timer stuff or playground business if you're running this in an app with a synthesizer delegate.)
The key bit (no pun intended) is to cast the return value of objectForProperty so that Swift knows it's a dictionary, then look up the number of characters in that dictionary.
Now, this code runs correctly, but it doesn't completely work for setting a progress bar — when the synthesizer finishes speaking, NSSpeechStatusNumberOfCharactersLeft is likely to be some nonzero value. (In that case, another status key, NSSpeechStatusOutputBusy will become false.) So your progress bar will get to not quite 100%, and you can use either the NSSpeechStatusOutputBusy key or the delegate didFinishSpeaking callback to take your bar the rest of the way, remove your progress UI, or whatever.

Making a counter app - Do I have to do something after saving to Core Data?

Trying my hand in Swift and creating my first "app". I'm essentially creating a cookie-clicker clone where you just click an image in the center of your screen repeatedly to increment your score.
I'm experiencing some issues where clicking the image once will increment my score by 1, but upon clicking it again, the score stays 1.
I'm almost positive I'm supposed to do something after saving to CoreData - I just don't know what. Do I have to refresh the View? Sorry for the newbie question
#IBAction func tapHomeImage(sender: AnyObject) {
//Score is the name of my Entity, with "points" being an attribute
let entity = NSEntityDescription.entityForName("Score", inManagedObjectContext: managedObjectContext!)
let score = Score(entity: entity!, insertIntoManagedObjectContext: managedObjectContext!)
// **As an aside question, is there a more efficient way to code the below? The issue I have is that score.points is of type NSNumber
let intScore = score.points as Int
let incrementedIntScore = intScore + 1
score.points = NSNumber(integer: incrementedIntScore)
var error: NSError?
managedObjectContext?.save(&error)
//homeScoreLabel is an IBOutlet for the Score displayed on the page
homeScoreLabel?.text = "\(score.points)"
}
Thank you very much!
You don't need to do anything after saving, you need to do something before calling this method. You need to find an instance of Score that already exists, and use that.
When you get to this line:
let score = Score(entity: entity!, insertIntoManagedObjectContext: managedObjectContext!)
You create a new instance of the Score entity, every time this method runs. So when you do this:
let intScore = score.points as Int
let incrementedIntScore = intScore + 1
score.points = NSNumber(integer: incrementedIntScore)
You're working with a brand new instance every time. The score is initially zero, and you always increase it to 1.
What you should do:
Use a single instance of Score and save that as a property of your view controller. That is, have something like this:
var score: Score?
Assign a value to this property once, when the view controller loads. Since you're saving data, you should use executeFetchRequest to look up a previously-saved instance. If no previous instance exists, then create a new one via insertIntoManagedObjectContext.
Use that instance in this IBAction.
There are other ways to fix the code. The key is to make sure that you use the same instance of Score every time instead of creating a new one at every tap.

"Can't unwrap Optional.None" and I can't figure out why

This produces "fatal error: Can't unwrap Optional.None" and I don't seem to get why
var motionManager = CMMotionManager()
motionManager.accelerometerUpdateInterval = 0.2
motionManager.startAccelerometerUpdates()
var accelerationData = motionManager.accelerometerData
var accel = accelerationData.acceleration.x
If anyone can help me out, that would be great.
The issue is accelerationData is nil and you aren't checking for this. From the docs:
If no accelerometer data is available, the value of this property is nil.
You should check to make sure there is actually data before calling methods on it like this
if let accelerationData = motionManager.accelerometerData {
var accel = accelerationData.acceleration.x
}
That will ensure that if there is no data your app won't crash. Now to make sure you get some data.
You aren't getting any data because you're asking for data immediately after you initialize the core motion manager. You can show this by waiting a few seconds before checking. You can add NSThread.sleepForTimeInterval(3) right above the if let and run the project and it will enter the if let. Make sure you are using an actual device though, the simulator won't generate any motion data.