Perform a function if a variable changes - ios

I want to perform
func performSegue() {
self.performSegueWithIdentifier("toTabSegue", sender: self)
}
immediately when
var isUpdated:Bool = false
is true.
How do I set something in viewdidload so when isUpdated changes to true it performs a segue?

You can use a didSet observer:
var isUpdated = false {
didSet {
if isUpdated && !oldValue {
performSegue()
}
}
}
Note that Swift provides oldValue in didSet automatically.

Related

Save UISwitch's toggled data in UserDefaults

I've declared a boolean with default value true, if my UISwitch is on I want boolean variable to be true else false, my code works fine until I try to store that boolean in UserDefaults when I reset the xCode Simulator I check with print method but it is not really saved...
any solution will be appericated.
var userDefaultSamarxvo:Bool = true
let defaults = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
defaults.set(userDefaultSamarxvo,forKey: "Samarxvo") // set of userdefault
if userDefaultSamarxvo {
print("hello")
}else{
print("olleh")
}
}
#IBAction func samarxvoDidChange(_ sender: UISwitch) {
if sender.isOn {
userDefaultSamarxvo.toggle()
print("samarxo")
}else{
userDefaultSamarxvo.toggle()
print("samarxo 1 ")
}
}
In viewDidLoad you want to load the saved value from user defaults. When the switch changes you need to save the new value to user defaults.
Setting a local variable (userDefaultSamarxvo) doesn't change what is stored in the user defaults; Local variables don't bind to user defaults storage.
There is an added complication; bool(forKey) will return false if there is no value for the key in UserDefaults. If you want the initial value to be true then you need to handle that in some way. You can use object(forKey) which returns an optional
var userDefaultSamarxvo:Bool = true {
didSet {
UserDefaults.standard.set(userDefaultSamarxvo, forKey:switchKey)
}
}
let defaults = UserDefaults.standard
let switchKey = "Samarxvo"
#IBOutlet weak var theSwitch: UISwitch!
override func viewDidLoad() {
super.viewDidLoad()
if defaults.object(forKey: switchKey) != nil {
userDefaultSamarxvo = defaults.bool(forKey: switchKey)
}
self.theSwitch.isOn = userDefaultSamarxvo
}
#IBAction func samarxvoDidChange(_ sender: UISwitch) {
userDefaultSamarxvo = sender.isOn
}
I have used a didSet clause to update the user defaults value when the property changes.

How to save the state of an UISwitch in SWIFT 4? [duplicate]

This question already has answers here:
How do i keep UISwitch state when changing ViewControllers?
(3 answers)
Closed 5 years ago.
I would like to save the State of an UISwitch after to change between View Controllers. Any help would be greatly appreciated!
I have a first View Controller with an UISwitch, to control the music in the background in different View Controllers:
#IBOutlet weak var SwitchMusic: UISwitch!
let defaults = UserDefaults.standard
var switchON : Bool = false
#IBAction func checkState(_ sender: UISwitch) {
if (sender.isOn == true)
{
switchON = true
defaults.set(switchON, forKey: "switchON")
MusicHelper.sharedHelper.playBackgroundMusic()
}
if (sender.isOn == false)
{
switchON = false
defaults.set(switchON, forKey: "switchON")
MusicHelper.sharedHelper.stopBackgroundMusic()
}
}
And a Second View Controller to load or no the music in the background if the switch is On or Off:
override func viewDidLoad() {
super.viewDidLoad()
if defaults.value(forKey: "switchON") != nil{
let switchON: Bool = defaults.value(forKey: "switchON") as! Bool
if switchON == true{
MusicHelper.sharedHelper.playBackgroundMusic()
}
else if switchON == false{
MusicHelper.sharedHelper.stopBackgroundMusic()
}
}
}
Also I have a class with the music:
class MusicHelper {
let defaults = UserDefaults.standard
static let sharedHelper = MusicHelper()
var musicBackgroundIntro:AVAudioPlayer = AVAudioPlayer()
func playBackgroundMusic() {
do {
let audioPath = Bundle.main.path(forResource: "Music", ofType: "mp3")
try musicBackgroundIntro = AVAudioPlayer(contentsOf: NSURL(fileURLWithPath: audioPath!) as URL)
musicBackgroundIntro.numberOfLoops = -1
musicBackgroundIntro.prepareToPlay()
musicBackgroundIntro.play()
} catch {
print("Cannot play the file")
}
}
func stopBackgroundMusic() {
musicBackgroundIntro.stop()
}
}
Now it is working perfectly the music in the background between View Controllers, and it is possible to turn off and on... but unfortunately do not save the current state of the UISwitch, and always when I enter in the First View Controller the state of the Switch is On.
Also any idea that how will be possible to apply in a Slider too?
Any help would be greatly appreciated!
Thanks
The easiest way for you would be to create a static var isSwitchOn: Bool = false
This state will be preserved between back and forth transitions.
You should reflect the state, if music is playing...
class MusicHelper {
public isPlaying: Bool {
get {
return musicBackgroundIntro.isPlaying
}
}
// your stuff here..
}
That way in other view controllers:
SwitchMusic.isOn = MusicHelper.sharedHelper.isPlaying
If you need other view controllers to update in response to this, you can add a delegate event (aka observer) if necessary.
Try something like that: Use the UISwitch as an #IBOutlet.
#IBOutlet weak var checkState: UISwitch!
override func viewDidLoad() {
super.viewDidLoad()
self.checkState.addTarget(self, action: #selector(action(sender:)), for: .valueChanged)
}
// Save state
func action(sender: UISwitch) {
let userDefaults = UserDefaults.standard
userDefaults.set(sender.isOn, forKey:"identifier")
}
// Retrieve state
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let userDefaults = UserDefaults.standard.bool(forKey: "identifier")
self.checkState.setOn(userDefaults, animated: false)
}
You can give the switch a default value when it's created in viewcontroller1.
Assign the (default.value(forKey:"switchOn") as! Bool ) ?? false to that switch.

How to return bool from a button click in alert with Swift

override func shouldPerformSegueWithIdentifier(identifier: String, sender: AnyObject!) -> Bool {
let appearance = SCLAlertView.SCLAppearance(
showCloseButton: false,
showCircularIcon: false
)
let alertView = SCLAlertView(appearance: appearance)
alertView.addButton("First") {
return true
}
alertView.addButton("Second") {
return false
}
alertView.showSuccess("warning", subTitle: "something")
}
This code above wants a return true/false before the last curly bracket but if I do that I lose the button return.
So is there any way to archive this?
I use SCLAlertView for my alert (if someone knows how to do it with uialert I would like to see it)
Thanks in advance.
to add to the first comment, I did it like this with the use of a UISwitch in a header cell with a bool variable declared in the top of the class
#IBAction func `switchAction`(_ sender: UISwitch) {
selected = sender.isOn
if selected == false {
//do you stuff here change false to true if you need it that way
}
}
then in this method setup like this
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
var enable: Bool = false
if selected == false {
enable = true
} else {
enable = false
}
return enable
}
you can use block- closesure
var alertAction :((result:Bool)->())?
use it :
alertView.addButton("Second") {
alertAction?(false)
}
implement:
alertAction = {result in
// do s.t
}

Swift 2, method 'setOn' with Objective-C selector 'setOn:' conflicts with setter for 'on' with the same Objective-C selector

Swift 2, I have a class inherits from objc's UIView and it has 'on' variable, and related methods 'setOn:animated' and 'setOn:' like below:
public class AView: UIView {
var on: Bool = false
public func setOn(on: Bool, animated: Bool) {
self.on = on
// do something more about animating
}
public func setOn(on: Bool) {
setOn(on, animated: false)
}
And I got an error message: method 'setOn' with Objective-C selector 'setOn:' conflicts with setter for 'on' with the same Objective-C selector
I think willSet or didSet is not a solution because setOn:animated: is called twice even if I add some guard conditions:
var on: Bool = false {
willSet {
if self.on != newValue {
setOn(self.on, animated: false)
}
}
}
....
....
let a = AView()
a.setOn(true, animated: true) // setOn:animated: is called twice
Is there a solution without changing a variable name and methods name?
Workaround: My solution is add extra internal variable and expose it with computed property. I don't like adding extra variable and definitely there will be a better solution.
private var isOn: Bool = false
var on: Bool {
set(newOn) {
setOn(newOn, animated: false)
}
get {
return isOn
}
}
public func setOn(on: Bool, animated: Bool) {
self.isOn = on
// do something ...
}
Similarly as in Compiler error: Method with Objective-C selector conflicts with previous declaration with the same Objective-C selector, you can also hide properties from
the Objective-C runtime with #nonobjc:
public class AView: UIView {
#nonobjc var on: Bool = false
public func setOn(on: Bool, animated: Bool) {
self.on = on
// do something more about animating
}
public func setOn(on: Bool) {
setOn(on, animated: false)
}
}
which prevents a conflicting Objective-C setter from being auto-generated.
Instead of willSet you need to use didSet
var on: Bool = false
{
didSet
{
if self.on != oldValue
{
setOn(self.on, animated: false)
}
}
}

Setting initial state of UISwitch

I have a UISwitch in the settings menu in my app and I am having difficulties trying to get the initial state to be 'on'. Even if I set the initial state to be 'on' in the attributes inspector, it still sets it to 'off' when the is opened for the first time.
Basically at the moment, the switch will be set to 'off' when the app opened for the first time however it does save the state if you change it so that works fine.
Here is my code:
#IBAction func dupOffOnSwitch(sender: AnyObject) {
if dupSwitch.on == true {
autoAdjust = true
println(autoAdjust)
} else {
autoAdjust = false
println(autoAdjust)
}
override func viewWillAppear(animated: Bool) {
dupSwitch.on = NSUserDefaults.standardUserDefaults().boolForKey("autoAdjustSettings")
println(NSUserDefaults.standardUserDefaults().boolForKey("autoAdjustSettings"))
}
'autoAdjust' is declared under import UIKit as true.
In order to set NSUserDefaults.standardUserDefaults().boolForKey("autoAdjustSettings") to true for the first time you ever launch your app, you can replace the application:didFinishLaunchingWithOptions: method of your AppDelegate class with this code:
func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
//If app has never been launched...
if !NSUserDefaults.standardUserDefaults().boolForKey("isNotFirstLaunch") {
//Set autoAdjustSettings and isNotFirstLaunch to true
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "autoAdjustSettings")
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "isNotFirstLaunch")
//Sync NSUserDefaults
NSUserDefaults.standardUserDefaults().synchronize()
}
return true
}
Of course, you can do the previous code in your UIViewController subclass but the AppDelegate should be the place for those settings.
Once done, your UIViewController subclass should look like this:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var dupSwitch: UISwitch!
#IBAction func dupOffOnSwitch(sender: AnyObject) {
dupSwitch.on = (sender as UISwitch).on //Bool
NSUserDefaults.standardUserDefaults().setBool(dupSwitch.on, forKey: "autoAdjustSettings")
NSUserDefaults.standardUserDefaults().synchronize()
}
override func viewDidLoad() {
super.viewDidLoad()
dupSwitch.on = NSUserDefaults.standardUserDefaults().boolForKey("autoAdjustSettings")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Unless you have a good reason to, I don't think you need to use the viewWillAppear: method in your UIViewController subclass for your NSUserDefaults statements. viewDidLoad: should be the right place for that.
I fixed my issue by adding this:
dupSwitch.on = NSUserDefaults.standardUserDefaults().boolForKey("autoAdjustSettings")
println(NSUserDefaults.standardUserDefaults().boolForKey("autoAdjustSettings"))
userReturnedAuto = NSUserDefaults.standardUserDefaults().boolForKey("userReturnedAuto")
if userReturnedAuto == false {
dupSwitch.on = true
userReturnedAuto = true
NSUserDefaults.standardUserDefaults().setBool(userReturnedAuto, forKey: "userReturnedAuto")
NSUserDefaults.standardUserDefaults().setBool(userReturnedAuto, forKey: "autoAdjustSettings")
}
Probably not the ideal solution but it works.

Resources