My question is about the UISlider. I managed to implement everything but i don't know how i can save its status.
Ive looked everywhere but al the posts are in older versions of swift/xcode. So the question is how do i save its status so that when i go to another view and then come back the status is still the same.
Thanks very much!
import UIKit
class SettingsViewController: UIViewController {
var sequeInt = 0
let savedWordLength = NSUserDefaults.standardUserDefaults()
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBOutlet weak var wordLength: UISlider!
#IBOutlet weak var wordLengthValue: UILabel!
var selectedValue: Int = 5
#IBAction func valueChanged(sender: UISlider) {
selectedValue = Int(sender.value)
savedWordLength.setInteger(selectedValue, forKey: "myInt")
let ourInt = savedWordLength.integerForKey("myInt")
sequeInt = ourInt
print (sequeInt)
wordLengthValue.text = String(ourInt)
}
UISlider value property is a Float so you can use NSUserDefault's method setFloat to save its value and retrieve it next time your view appears using NSUserDefaults method floatForKey.
to save it:
NSUserDefaults.standardUserDefaults().setFloat(sender.value, forKey: "wordLength")
load it:
override func viewWillAppear(animated: Bool) {
wordLength.setValue(NSUserDefaults.standardUserDefaults().floatForKey("wordLength"), animated: false)
}
Follow these steps.
In your view will appear.
fontSlider.setValue(UserDefaults.standard.float(forKey: "slider_value"), animated: false)
Take another outlet from storyBoard as "editingDidEnd".
In that function:
UserDefaults.standard.set(fontSlider.value, forKey: "slider_value")
And finally in your ValueChanged Outlet.
UserDefaults.standard.set(fontSlider.value, forKey: "slider_value")
Related
I'm trying to save a bool value to UserDefaults from a UISwitch, and retrieve it in another view. However, I've tried following multiple tutorials and stack answers and none seem to work.
This is how I'm saving it:
class SettingsViewController: UITableViewController {
#IBOutlet weak var soundSwitchOutlet: UISwitch!
#IBAction func soundSwitch(_ sender: UISwitch) {
UserDefaults.standard.set(soundSwitchOutlet.isOn, forKey: "sound")
}
and this is how I'm trying to retrieve it in another view:
if let savedValue = UserDefaults.standard.bool(forKey: "sound") {
boolValue = savedValue
}
//this is inside viewDidLoad and "boolValue" was declared outside viewDidLoad//
For a reason this code is giving me errors and none of the things I've tried have worked. How can I save a bool to UserDefaults and retrieve it in another view?
Edit: I think I fixed the first part. However, the way I'm retrieving the boolean seems to be totally wrong. Also: No other stackExchange answer responds to what I'm asking, at least not in swift.
As Leo mentioned in the comments bool(forKey returns a non-optional Bool. If the key does not exist false is returned.
So it's simply
boolValue = UserDefaults.standard.bool(forKey: "sound")
Calling synchronize() as suggested in other answers is not needed. The framework updates the user defaults database periodically.
Do it like this.
In your first view controller.
create an IBoutlet connection to your UISwitch
And then the action for your UISwitch. so in the end, your first view controller should look like this.
import UIKit
class FirstViewController: UIViewController {
#IBOutlet weak var myswitch: UISwitch! // Outlet connection to your UISwitch (just control+ drag it to your controller)
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func myswitchAction(_ sender: Any) { // Action for your UISwitch
var myswitctBool : Bool = false // create a local variable that holds your bool value. assume that in the beginning your switch is offed and the boolean value is `false`
if myswitch.isOn == true { // when user turn it on then set the value to `true`
myswitctBool = true
}
else { // else set the value to false
myswitctBool = false
}
// finally set the value to user default like this
UserDefaults.standard.set(myswitctBool, forKey: "mySwitch")
//UserDefaults.standard.synchronize() - this is not necessary with iOS 8 and later.
}
}
End of the first view controller
Now in your second view controller
you can get the value of userdefault, which you set in first view controller. I put it in the viewdidload method to show you how it works.
import UIKit
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let myswitchBoolValuefromFirstVc : Bool = UserDefaults.standard.bool(forKey: "mySwitch")// this is how you retrieve the bool value
// to see the value, just print those with conditions. you can use those for your things.
if myswitchBoolValuefromFirstVc == true {
print("true")
}
else {
print("false")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Hope this will help to you. good luck
Use this line of code:
#IBAction func soundSwitch(_ sender: UISwitch) {
UserDefaults.standard.set(soundSwitchOutlet.isOn, forKey: "sound")
}
insteadof :
#IBAction func soundSwitch(_ sender: UISwitch) {
UserDefaults.standard.set(soundSwitchOutlet, forKey: "sound")
}
Try this:
#IBAction func soundSwitchs(_ sender: Any)
{
UserDefaults.standard.set(soundSwitchOutlet.isOn, forKey: "sound")
UserDefaults.standard.synchronize()
}
//this is inside viewDidLoad and "boolValue" was declared outside viewDidLoad//
boolValue = UserDefaults.standard.bool(forKey: "sound")
I am trying to self-learn OSX application development so I can make up all of my own bad habits 8).
Probably extraneous information
I have a trial app that works successfully - it resizes itself based on input from the user via a slider.
The key piece of code that does this is in one View controller ...
class JunkViewController2: NSViewController {
var myY: CGFloat!
#IBOutlet weak var mySlider: NSSlider!
#IBOutlet weak var myView: NSView!
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
self.preferredContentSize = NSMakeSize(self.view.frame.width, 83)
}
#IBAction func mySlider(sender: NSSlider) {
let mySplitViewController = self.childViewControllers[0] as! JunkSplitViewController
switch mySlider.intValue {
case 3:
myY = 140.0
mySplitViewController.splitViewItems[2].collapsed = false
mySplitViewController.splitViewItems[1].collapsed = false
mySplitViewController.showSubview(2)
mySplitViewController.showSubview(1)
mySplitViewController.showSubview(0)
case 2:
myY = 110.0
mySplitViewController.splitViewItems[2].collapsed = true
mySplitViewController.splitViewItems[1].collapsed = false
mySplitViewController.hideSubview(2)
mySplitViewController.showSubview(1)
mySplitViewController.showSubview(0)
default:
myY = 80.0
mySplitViewController.splitViewItems[2].collapsed = true
mySplitViewController.splitViewItems[1].collapsed = true
mySplitViewController.hideSubview(2)
mySplitViewController.hideSubview(1)
mySplitViewController.showSubview(0)
}
mySplitViewController.preferredContentSize = NSMakeSize(self.view.frame.width, myY - 50 + 3)
self.preferredContentSize = NSMakeSize(self.view.frame.width, myY + 3)
}
}
More pertinent information
In what is working, above, on the story board I have three duplicate ViewControllers connected to a SplitView controller. I do a bunch of what feels like belts and suspenders work to make sure that everything gets resized properly - but the key part (I think) is the .collapsed property.
I am now trying to accomplish the same thing, using a completely different method - dynamically adding / removing split view items. This should allow me to have only one of the small ViewControllers on my story board, and then instantiate it as needed.
Following that idea, here is my SplitViewController ...
class JunkSplitViewController: NSSplitViewController {
#IBOutlet weak var mySplitView: NSSplitView!
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
//mySplitView.adjustSubviews()
}
func makeChild() -> SmallViewController {
let mySmallGroup = NSStoryboard(name: "Main", bundle: nil).instantiateControllerWithIdentifier("smallVwCtl")
self.addSplitViewItem(mySmallGroup as! NSSplitViewItem)
return mySmallGroup as! SmallViewController
}
}
The main view controller invokes the makeChild function.
class JunkViewController: NSViewController {
#IBOutlet weak var mySlider: NSSlider!
#IBOutlet weak var myView: NSView!
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
self.preferredContentSize = NSMakeSize(self.view.frame.width, 83)
}
#IBAction func mySlider(sender: NSSlider) {
let mySplitViewController = self.childViewControllers[0] as! JunkSplitViewController
while mySlider.intValue.toIntMax() > mySplitViewController.splitViewItems.count.toIntMax() {
mySplitViewController.makeChild()
}
while mySlider.intValue.toIntMax() < mySplitViewController.splitViewItems.count.toIntMax(){
mySplitViewController.splitViewItems.removeLast()
}
}
}
I get an error at the self.addSplitViewItem(mySmallGroup as! NSSplitViewItem) line of JunkSplitViewController ... "Could not cast value of type Scratch2.SmallViewController to NSSplitViewItem"
I've tried a handful of combinations (forcing mySmallGroup, 'self.addSplitViewItem(mySmallGroup as! SmallViewController)`, etc.) Everything leads to a similar error, either at compile or run time.
I cannot find any documentation on SplitViewItem.
So the question - what will work as input to addSplitViewItem and still successfully connect a new instance of SmallViewController?
And gratefully accept any comments/feedback on the methodology
I hate it when I find my answer minutes after posting a question ...
Based on info I found here ...
func makeChild() -> SmallViewController {
let mySmallGroup = NSStoryboard(name: "Main", bundle: nil).instantiateControllerWithIdentifier("smallVwCtl") as! SmallViewController
self.addSplitViewItem(NSSplitViewItem(viewController: mySmallGroup))
return mySmallGroup
}
... but I'd still like to hear any feedback on methodology. Thanks.
I'm learning how to program and am playing with a Swift project in Xcode. The main storyboard has two view controllers. The first view controller is simply called ViewController and the second view controller is called HelpScreenViewController.
In ViewController I have a "help" button that switches the user to HelpScreenViewController. This button uses a segue called "goToHelpScreenSegue".
In HelpScreenViewController I have three buttons:
"Close" button to dismisses the view (no segue used)
"Send Feedback" button to generate a new email in the Mail app (no segue used)
"Reset Game" button to call a function that is coded within the first ViewController. This third button uses a segue called "resetGameSegue".
What I'm trying to do is...
...Get the "Reset Game" button on the HelpScreenViewController to reset the game by calling a function that's coded within the first view controller.*
To try and get this to work the way I want, I've used the following code:
WITHIN first main ViewController
import UIKit
import iAd
import AdSupport
import AVFoundation //audio
import GameplayKit
class ViewController: UIViewController, ADBannerViewDelegate, MyResetGameProtocol {
#IBOutlet weak var Banner: ADBannerView!
#IBOutlet weak var buttonA: UIButton!
#IBOutlet weak var buttonB: UIButton!
#IBOutlet weak var buttonC: UIButton!
#IBOutlet weak var buttonD: UIButton!
#IBOutlet weak var labelQuestion: UILabel!
#IBOutlet weak var labelScore: UILabel!
#IBOutlet weak var labelTotalQuestionsAsked: UILabel!
#IBOutlet weak var labelFeedback: UILabel!
#IBOutlet weak var buttonNext: UIButton!
var score :Int! = 0
var totalquestionsasked :Int! = 0
var allEntries : NSArray!
var shuffledQuestions: [AnyObject]!
var nextQuestion = -1
var currentCorrectAnswerIndex : Int = 0
var audioPlayer = AVAudioPlayer()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.Banner?.delegate = self
self.Banner?.hidden = true
LoadAllQuestionsAndAnswers()
if #available(iOS 9.0, *) {
shuffledQuestions = GKRandomSource.sharedRandom().arrayByShufflingObjectsInArray(allEntries as [AnyObject])
nextQuestion++
LoadQuestion(nextQuestion)
// Fallback on earlier versions
}else{
let randomNumber = Int(arc4random_uniform(UInt32(allEntries.count)))
LoadQuestionPreiOS9(randomNumber)
}
LoadScore()
AdjustInterface()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let viewController = segue.destinationViewController as! HelpScreenViewController
viewController.controller = self
}
func ResetGame() {
PlaySoundReset()
score = 0
totalquestionsasked = 0
SaveScore()
LoadScore()
}
func PlaySoundReset()
{
let alertSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("pcbeep", ofType: "wav")!)
do {
audioPlayer = try AVAudioPlayer(contentsOfURL: alertSound)
} catch {
}
audioPlayer.prepareToPlay()
audioPlayer.play()
}
func SaveScore()
{
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setInteger(score, forKey: "Score")
defaults.setInteger(totalquestionsasked, forKey: "Out of")
}
func LoadScore()
{
let defaults = NSUserDefaults.standardUserDefaults()
score = defaults.integerForKey("Score")
totalquestionsasked = defaults.integerForKey("Out of")
labelScore.text = "Score: \(score)"
labelTotalQuestionsAsked.text = "out of \(totalquestionsasked)"
}
and so on....
WITHIN the second HelpScreenViewController
import UIKit
protocol MyResetGameProtocol {
func ResetGame()
}
class HelpScreenViewController: UIViewController, MyResetGameProtocol {
var controller: MyResetGameProtocol? // reference to the delegate alias First Controller
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
#IBAction func SendFeedback(sender: AnyObject) {
UIApplication.sharedApplication().openURL(NSURL(string: "mailto:feedback#felice.ws?")!)
}
#IBAction func DismissView(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil) }
#IBAction func buttonResetGame(sender: AnyObject) {
controller.ResetGame()
}
}
Now, at the moment with the above code what happens is that if the user taps the "help" button in the first main ViewController (i.e. goToHelpScreenSegue), not only does it take the user to the help screen, but it also calls the function I want activated when the user taps on the "Reset Game" button instead. That is, at the moment, it's the "help" button that resets the game before taking the user to the help screen.
Now, within the help screen, the first two buttons work normally (but they're not using segues). Tapping on the third button (the Reset Game one) simply returns the user back to the main screen. It doesn't call the function, doesn't reset the game.
I've lost count of the times I've changed the code around to try and get it to work right, but I've obviously missed something really obvious.
In particular, I've tried using the following code instead within the main ViewController:
override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
if segue?.identifier == "resetGameSegue" {
let viewController = segue!.destinationViewController as! HelpScreenViewController
viewController.controller = self
}
However, this results in nothing happening. What I mean is that the button on the main screen works properly (taking the user to the help screen and not incorrectly calling the resetGame function). And, within the help screen the first two buttons work as expected, but the "Reset Game" button just returns the user to the first screen but without calling the ResetGame function.
I also tried removing the IBActions from both my code and the connections inspector for the "Reset Game" button, but that made no difference either.
Any assistance would be most appreciated as I'm just not getting it! :(
I'm agree with MikeG, that you should probably learn about how delegates should be implemented. But the thing you're doing wrong inside this code is that you're not actually calling ResetGame() function on your delegate. Try to implement your #IBAction function in this way:
#IBAction func buttonResetGame(sender: AnyObject) {
controller?.ResetGame()
}
And yeah, if I understand your logic correctly your HelpScreenViewController should not implement MyResetGameProtocol cause your ViewController is the one who's implementing it.
I am new to OS X app development. I manage to built the NSComboBox (Selectable, not editable), I can get it indexOfSelectedItem on action button click, working fine.
How to detect the the value on change? When user change their selection, what kind of function I shall use to detect the new selected index?
I tried to use the NSNotification but it didn't pass the new change value, always is the default value when load. It is because I place the postNotificationName in wrong place or there are other method should use to get the value on change?
I tried searching the net, video, tutorial but mostly written for Objective-C. I can't find any answer for this in SWIFT.
import Cocoa
class NewProjectSetup: NSViewController {
let comboxRouterValue: [String] = ["No","Yes"]
#IBOutlet weak var projNewRouter: NSComboBox!
#IBAction func btnAddNewProject(sender: AnyObject) {
let comBoxID = projNewRouter.indexOfSelectedItem
print(“Combo Box ID is: \(comBoxID)”)
}
#IBAction func btnCancel(sender: AnyObject) {
self.dismissViewController(self)
}
override func viewDidLoad() {
super.viewDidLoad()
addComboxValue(comboxRouterValue,myObj:projNewRouter)
self.projNewRouter.selectItemAtIndex(0)
let notificationCenter = NSNotificationCenter.defaultCenter()
notificationCenter.addObserver(
self,
selector: “testNotication:”,
name:"NotificationIdentifier",
object: nil)
NSNotificationCenter.defaultCenter().postNotificationName("NotificationIdentifier", object: projNewRouter.indexOfSelectedItem)
}
func testNotication(notification: NSNotification){
print("Found Combo ID \(notification.object)")
}
func addComboxValue(myVal:[String],myObj:AnyObject){
let myValno: Int = myVal.count
for var i = 0; i < myValno; ++i{
myObj.addItemWithObjectValue(myVal[i])
}
}
}
You need to define a delegate for the combobox that implements the NSComboBoxDelegate protocol, and then use the comboBoxSelectionDidChange(_:) method.
The easiest method is for your NewProjectSetup class to implement the delegate, as in:
class NewProjectSetup: NSViewController, NSComboBoxDelegate { ... etc
Then in viewDidLoad, also include:
self.projNewRouter.delegate = self
// self (ie. NewProjectSetup) implements NSComboBoxDelegate
And then you can pick up the change in:
func comboBoxSelectionDidChange(notification: NSNotification) {
print("Woohoo, it changed")
}
I have my code so it puts an annotation on the map each time the user clicks a button, but when the user closes out of the app, the annotation disappears. How do I make it so the annotations stays on the map even when the user closes the app? Below is my code:
import UIKit
import CoreLocation
import MapKit
class UpdateCar: UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var lblLocation: UILabel!
var locationManager = CLLocationManager()
var myPosition = CLLocationCoordinate2D()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func locationManager(manager: CLLocationManager!, didUpdateToLocation newLocation: CLLocation!, fromLocation oldLocation: CLLocation!) {
println("Updating Car Location \(newLocation.coordinate.latitude) , \(newLocation.coordinate.longitude) ")
myPosition = newLocation.coordinate
locationManager.stopUpdatingLocation()
lblLocation.text = "\(newLocation.coordinate.latitude) , \(newLocation.coordinate.longitude)"
}
#IBAction func findUserLocationAndDropPin(sender: UIButton) {
var userLocationCoordinates = CLLocationCoordinate2DMake(locationManager.location.coordinate.latitude, locationManager.location.coordinate.longitude)
var pinForUserLocation = MKPointAnnotation()
pinForUserLocation.coordinate = userLocationCoordinates
mapView.addAnnotation(pinForUserLocation)
mapView.showAnnotations([pinForUserLocation], animated: true)
}
}
You have to save it in a persistent store.
Few options:
CoreData, the native way of saving data, recommended, not too easy
NSUserDefaults, usually thought for small stuff, also native, not recommended, very easy though
Another API for managing a persistent store like Realm (similar to CoreData, a little easier but not native)
//when I need to save for example, the last date on which the user login my app will use the setObject function, this will save a value ("10/05/2015") in the "lastlogin" key
var lastLogin = "10/05/2015"
NSUserDefaults.standarUserDefaults().setObject(lastLogin, forkey: "lastLogin")
//And when I need to retrieve the stored value in the "lastlogin" key which I use is "objectForKey" function
NSUserDefaults.standarUserDefaults().objectForKey("lastLogin")
see following link:
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/index.html#//apple_ref/occ/instm/NSUserDefaults/setObject:forKey: