How to save user preference of dark or light mode - swift

I have these buttons in my app so user can switch from light to dark mode in the app, how can I save this preference so whichever mode the user selected will still be active the next time they open the app?
I'm on Xcode 14.2
Code example please.
#IBAction func darkButton(_ sender: Any) {
overrideUserInterfaceStyle = .dark
}
#IBAction func lightButton(_ sender: Any) {
overrideUserInterfaceStyle = .light
}
Full code below
import UIKit
class ViewController: UIViewController {
// All Input Texts
#IBOutlet weak var machineODInputText: UITextField!
#IBOutlet weak var pipeODInputText: UITextField!
#IBOutlet weak var pipeLengthInputText: UITextField!
#IBOutlet weak var driveLengthInputText: UITextField!
#IBOutlet weak var muckUpInputText: UITextField!
#IBOutlet weak var jackingSpeedInputText: UITextField!
#IBOutlet weak var weightOfBenoBagInputText: UITextField!
#IBOutlet weak var noOfBenoBagsInputText: UITextField!
#IBOutlet weak var benoQtyForTanksInputText: UITextField!
#IBOutlet weak var noOfBenoBagsPerPalletInputText: UITextField!
// All Result Texts
#IBOutlet weak var lubricationPumpSpeedResult: UILabel!
#IBOutlet weak var volumePerMeterResult: UILabel!
#IBOutlet weak var volumePerPipeResult: UILabel!
#IBOutlet weak var volumeForDriveResult: UILabel!
#IBOutlet weak var benoQtyForLubricationResult: UILabel!
#IBOutlet weak var benoQtyForDriveResult: UILabel!
#IBOutlet weak var noOfPalletsForDriveResult: UILabel!
// All Buttons
#IBAction func lightButton(_ sender: Any) {
overrideUserInterfaceStyle = .light
UserDefaults.standard.set("light", forKey: "mode")
}
#IBAction func darkButton(_ sender: Any) {
overrideUserInterfaceStyle = .dark
UserDefaults.standard.set("dark", forKey: "mode")
}
#IBAction func calculateButton(_ sender: Any) {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 0
let formatter2 = NumberFormatter()
formatter2.numberStyle = .decimal
formatter2.maximumFractionDigits = 2
let pi = Double.pi / 4
let TBMOD = (Double(machineODInputText.text!) ?? 1) / 1000.0
let pipeOD = (Double(pipeODInputText.text!) ?? 1) / 1000.0
let muckup = (Double(muckUpInputText.text!) ?? 2.5)
let advanceSpeed = (Double(jackingSpeedInputText.text!) ?? 1)
let volPerPipe = (Double(pipeLengthInputText.text!) ?? 1)
let volForDrive = (Double(driveLengthInputText.text!) ?? 1)
let noOfBenoBagsForLub = (Double(noOfBenoBagsInputText.text!) ?? 1)
let weightOfEachBenoBag = (Double(weightOfBenoBagInputText.text!) ?? 1)
let amountOfBenoBagsInTamks = (Double(benoQtyForTanksInputText.text!) ?? 1)
let noOfBenoBagsPerPallet = (Double(noOfBenoBagsPerPalletInputText.text!) ?? 1)
// Calculate Volume per Meter (Ltr per meter)
let volPerMtrResults1 = ((pi * (TBMOD) * (TBMOD)) - (pi * (pipeOD) * (pipeOD))) * muckup * 1000
let volPerMtrResult = formatter.string (from: NSNumber(value: volPerMtrResults1))
volumePerMeterResult.text = volPerMtrResult
// Calculate Lubrication Pump Capacity (Ltr per min)
let pumpCapacityResults1 = (advanceSpeed / 1000) * volPerMtrResults1
let lubPerMtrResult = formatter.string(from: NSNumber(value: pumpCapacityResults1))
lubricationPumpSpeedResult.text = lubPerMtrResult
// Calculate Volume per pipe (M³ per pipe)
let volPerPipeResults1 = (volPerMtrResults1 / 1000) * volPerPipe
let volPerPipeResult = formatter2.string(from: NSNumber(value: volPerPipeResults1))
volumePerPipeResult.text = volPerPipeResult
// Calculate Volume for drive (M³ for drive)
let volPerDriveResults1 = (volPerMtrResults1 / 1000) * volForDrive
let volPerDriveResult = formatter.string(from: NSNumber(value: volPerDriveResults1))
volumeForDriveResult.text = volPerDriveResult
// Calculate Amount of beno for lubrication
let ammountOfBenoForLubResults1 = noOfBenoBagsForLub * volPerDriveResults1 * weightOfEachBenoBag
let ammountOfBenoForLubResult = formatter.string(from: NSNumber(value: ammountOfBenoForLubResults1))
benoQtyForLubricationResult.text = ammountOfBenoForLubResult
// Calculate beno quantity for drive
let amountOfBenoForDriveResults1 = ammountOfBenoForLubResults1 + (amountOfBenoBagsInTamks * 1000)
let amountOfBenoForDriveResult = formatter.string(from: NSNumber(value: amountOfBenoForDriveResults1))
benoQtyForDriveResult.text = amountOfBenoForDriveResult
// Calculate number of pallets for drive
let ammountOfBenoPerPalletResults1 = amountOfBenoForDriveResults1 / weightOfEachBenoBag / noOfBenoBagsPerPallet
let ammountOfBenoPerPalletResult = formatter2.string(from: NSNumber(value: ammountOfBenoPerPalletResults1))
noOfPalletsForDriveResult.text = ammountOfBenoPerPalletResult
UserDefaults.standard.set(machineODInputText.text, forKey: "TBMOD")
UserDefaults.standard.set(pipeODInputText.text, forKey: "pipeOD")
UserDefaults.standard.set(muckUpInputText.text, forKey: "muckUp")
UserDefaults.standard.set(jackingSpeedInputText.text, forKey: "speed")
UserDefaults.standard.set(pipeLengthInputText.text, forKey: "pipeLength")
UserDefaults.standard.set(driveLengthInputText.text, forKey: "driveLength")
UserDefaults.standard.set(noOfBenoBagsInputText.text, forKey: "noOfBenoBags")
UserDefaults.standard.set(weightOfBenoBagInputText.text, forKey: "weightOfBenoBag")
UserDefaults.standard.set(benoQtyForTanksInputText.text, forKey: "benoQtyForTanks")
UserDefaults.standard.set(noOfBenoBagsPerPalletInputText.text, forKey: "benoBagsPerPallet")
}
// Adding toolbar to top of keyboard with "Done" button (toolbar.swift file)
override func viewDidLoad() {
super.viewDidLoad()
machineODInputText.inputAccessoryView = toolBar()
pipeODInputText.inputAccessoryView = toolBar()
pipeLengthInputText.inputAccessoryView = toolBar()
driveLengthInputText.inputAccessoryView = toolBar()
muckUpInputText.inputAccessoryView = toolBar()
jackingSpeedInputText.inputAccessoryView = toolBar()
weightOfBenoBagInputText.inputAccessoryView = toolBar()
noOfBenoBagsInputText.inputAccessoryView = toolBar()
benoQtyForTanksInputText.inputAccessoryView = toolBar()
noOfBenoBagsPerPalletInputText.inputAccessoryView = toolBar()
}
// load old data into input feilds
override func viewDidAppear(_ animated: Bool) {
if let a = UserDefaults.standard.object(forKey: "TBMOD") as? String {
machineODInputText.text = a
}
if let a = UserDefaults.standard.object(forKey: "pipeOD") as? String {
pipeODInputText.text = a
}
if let a = UserDefaults.standard.object(forKey: "muckUp") as? String {
muckUpInputText.text = a
}
if let a = UserDefaults.standard.object(forKey: "speed") as? String {
jackingSpeedInputText.text = a
}
if let a = UserDefaults.standard.object(forKey: "pipeLength") as? String {
pipeLengthInputText.text = a
}
if let a = UserDefaults.standard.object(forKey: "driveLength") as? String {
driveLengthInputText.text = a
}
if let a = UserDefaults.standard.object(forKey: "noOfBenoBags") as? String {
noOfBenoBagsInputText.text = a
}
if let a = UserDefaults.standard.object(forKey: "weightOfBenoBag") as? String {
weightOfBenoBagInputText.text = a
}
if let a = UserDefaults.standard.object(forKey: "benoQtyForTanks") as? String {
benoQtyForTanksInputText.text = a
}
if let a = UserDefaults.standard.object(forKey: "benoBagsPerPallet") as? String {
noOfBenoBagsPerPalletInputText.text = a
}
// load dark/light mode last selected by user
let mode = UserDefaults.standard.string(forKey: "mode")
if mode == "dark" {
overrideUserInterfaceStyle = .dark
} else {
overrideUserInterfaceStyle = .light
}
machineODInputText.clearsOnBeginEditing = true
pipeODInputText.clearsOnBeginEditing = true
pipeLengthInputText.clearsOnBeginEditing = true
driveLengthInputText.clearsOnBeginEditing = true
muckUpInputText.clearsOnBeginEditing = true
jackingSpeedInputText.clearsOnBeginEditing = true
weightOfBenoBagInputText.clearsOnBeginEditing = true
noOfBenoBagsInputText.clearsOnBeginEditing = true
benoQtyForTanksInputText.clearsOnBeginEditing = true
noOfBenoBagsPerPalletInputText.clearsOnBeginEditing = true
}
}

you can save it in UserDefaults as follows.
#IBAction func darkButton(_ sender: Any) {
overrideUserInterfaceStyle = .dark
UserDefaults.standard.set("dark", forKey: "mode")
}
#IBAction func lightButton(_ sender: Any) {
overrideUserInterfaceStyle = .light
UserDefaults.standard.set("light", forKey: "mode")
}
When reopening the application do as follow.
let mode = UserDefaults.standard.string(forKey: "mode")
if mode == "dark" {
overrideUserInterfaceStyle = .dark
} else {
overrideUserInterfaceStyle = .light
}
Where you need to add the above code depends on your scenario. I suggest to add it inside AppDelegate -> didFinishLaunchingWithOptions.

Related

UISwitch saving values to use in a function

When the user turns switch on, I would like a random value to display on a UILabel, then take that same random value, and use it to multiply and find another value. I think my problem is that I am trying to use a let statement to hold the value, then trying to call back to that let value from another function, but I don't know another way to to this.
I already can get the random value to appear on a UILabel after the switch is active. Then when the switch is not active, a value of 0 is left on the UILabel.
The IBOutlet for the switch:
#IBOutlet weak var tipSwitch: UISwitch!
This is the action for the switch:
#IBAction func switchChanged(_ sender: UISwitch) {
if sender.isOn{
sender.setOn(false, animated: true)
percentPlaceholder.text! = String(0) + "%"
}
else{
sender.setOn(true, animated: true)
let randomTip = Int.random(in: 1...100)
percentPlaceholder.text! = String(randomTip)
calculateTipSwitch()
}
}
This is the calculateTipSwitch function:
func calculateTipSwitch() {
var tipAmountSwitch = Float()
var totalCostSwitch = Float()
if let billAmountSwitch = Float(billCost.text!) {
tipAmountSwitch = billAmountSwitch * randomTip / 100
totalCostSwitch = tipAmountSwitch + billAmountSwitch
}
else {
tipAmountSwitch = 0
totalCostSwitch = 0
}
tipDollarAmt.text! = String(format: "%.2f", tipAmountSwitch)
totalBill.text! = String(format: "%.2f", totalCostSwitch)
}
Here is all of my code if you want a better understanding of what I'm trying to accomplish:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var billCost: UITextField!
#IBOutlet weak var percentPlaceholder: UILabel!
#IBOutlet weak var tipDollarAmt: UILabel!
#IBOutlet weak var totalBill: UILabel!
#IBOutlet weak var tipSlider: UISlider!
#IBOutlet weak var tipSegment: UISegmentedControl!
#IBOutlet weak var tipStepper: UIStepper!
#IBOutlet weak var tipSwitch: UISwitch!
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let allowed = CharacterSet(charactersIn: ".1234567890")
return string.rangeOfCharacter(from: allowed) != nil
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
billCost.resignFirstResponder()
return true
}
override func viewDidLoad() {
super.viewDidLoad()
percentPlaceholder.text = ""
tipDollarAmt.text = ""
totalBill.text = ""
}
#IBAction func sliderChanged(_ sender: UISlider) {
percentPlaceholder.text! = String(Int(sender.value)) + "%"
tipStepper.value = Double(Int(tipSlider.value))
calculateTip()
}
#IBAction func selectorChanged(_ sender: UISegmentedControl) {
}
#IBAction func stepperChanged(_ sender: UIStepper) {
percentPlaceholder.text! = String(sender.value) + "%"
tipSlider.value = Float(tipStepper.value)
calculateTipStep()
}
#IBAction func switchChanged(_ sender: UISwitch) {
if sender.isOn{
sender.setOn(false, animated: true)
percentPlaceholder.text! = String(0) + "%"
}
else{
sender.setOn(true, animated: true)
let randomTip = Int.random(in: 1...100)
percentPlaceholder.text! = String(randomTip)
}
}
func calculateTip()
{
var tipAmount = Float()
var totalCost = Float()
if let billAmount = Float(billCost.text!) {
tipAmount = billAmount * tipSlider.value / 100
totalCost = tipAmount + billAmount
}
else {
tipAmount = 0
totalCost = 0
}
tipDollarAmt.text! = String(format: "%.2f", tipAmount)
totalBill.text! = String(format: "%.2f", totalCost)
}
func calculateTipStep() {
var tipAmountStep = Float()
var totalCostStep = Float()
if let billAmountStep = Float(billCost.text!) {
tipAmountStep = billAmountStep * Float(tipStepper.value) / 100
totalCostStep = tipAmountStep + billAmountStep
}
else {
tipAmountStep = 0
totalCostStep = 0
}
tipDollarAmt.text! = String(format: "%.2f", tipAmountStep)
totalBill.text! = String(format: "%.2f", totalCostStep)
}
func calculateTipSwitch() {
var tipAmountSwitch = Float()
var totalCostSwitch = Float()
if let billAmountSwitch = Float(billCost.text!) {
tipAmountSwitch = billAmountSwitch * randomTip / 100
totalCostSwitch = tipAmountSwitch + billAmountSwitch
}
else {
tipAmountSwitch = 0
totalCostSwitch = 0
}
tipDollarAmt.text! = String(format: "%.2f", tipAmountSwitch)
totalBill.text! = String(format: "%.2f", totalCostSwitch)
}
}
Basically my problem is that I can't use that random number in another function, so I just need help on how to call back to that randomTip.
You can add a parameter to calculateTipSwitch, and pass the random number as an argument to the calculateTipSwitch method. Change calculateTipSwitch to:
func calculateTipSwitch(tipPercentage: Int) {
var tipAmountSwitch = Float()
var totalCostSwitch = Float()
if let billAmountSwitch = Float(billCost.text!) {
tipAmountSwitch = billAmountSwitch * tipPercentage / 100.0
totalCostSwitch = tipAmountSwitch + billAmountSwitch
}
else {
tipAmountSwitch = 0
totalCostSwitch = 0
}
tipDollarAmt.text! = String(format: "%.2f", tipAmountSwitch)
totalBill.text! = String(format: "%.2f", totalCostSwitch)
}
Then, in switchChanged:
let randomTip = Int.random(in: 1...100)
percentPlaceholder.text! = String(randomTip)
calculateTipSwitch(tipPercentage: randomTip)
In the switchChanged() function , you set the randomTip to percentPlaceholder.text , so in the other functions , you could just call for it.
let randomTip = percentPlaceholder.text
Or another way to do this, is to declare the randomTip variable outside the function, as a property of the class.
class ViewController : UIViewController {
//IBOutlets here
var randomTip : String?
//functions here
}
Then when you set a value to it in switchChanged(), it can be called in the other functions.

app reverts all input variables to defaults after some time

I wrote my fist app, very simple, that creates a user defined number of badges at random times during a user defined window of time. It works fine but after some time (not sure how long, 2-4 hours), all of the user input information reverts to the defaults of the program. The issue is it is supposed to run each day but it is annoying to have to set it each morning. I am not sure if this is a coding issue or if the app 'reboots' when it is not doing anything in the background. Note that this occurs on my iPhone 8 but not on the simulator (or I am not patient enough for it to occur on the simulator).
I have put several print and label to try to identify when it occurs; I am sure I am putting them in the correct places. I apologize for including so much code - I tried to weed some of the mistakes out but I do not know where the problem is.
import UserNotifications
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var EarlyTimePicker: UITextField!
#IBOutlet weak var LateTimePicker: UITextField!
#IBOutlet weak var NumQuestions: UITextField!
#IBOutlet weak var myLabel_Questions: UILabel!// Attached to the label box
#IBOutlet weak var myLabel_StartEndTime: UILabel!
#IBOutlet weak var myLabel_TestResetTime: UILabel!
#IBOutlet weak var myLabel_CurrentEarlyTime: UILabel!
private var earlyTimePicker: UIDatePicker?
private var lateTimePicker: UIDatePicker?
override func viewDidLoad() {
super.viewDidLoad()
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in //ask for permission in order to show messages on the lock screen
if granted {
print("Yay!")
} else {
print("D'oh")
}
}
earlyTimePicker = UIDatePicker()
earlyTimePicker?.datePickerMode = .time //change to .time
earlyTimePicker?.addTarget(self, action: #selector(ViewController.earlyTimeChanged(earlyTimePicker:)),for: .valueChanged)
lateTimePicker = UIDatePicker()
lateTimePicker?.datePickerMode = .time //change to .time
lateTimePicker?.addTarget(self, action: #selector(ViewController.lateTimeChanged(lateTimePicker:)),for: .valueChanged)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.viewTapped(gestureRecognizer:)))
view.addGestureRecognizer(tapGesture)
EarlyTimePicker.inputView = earlyTimePicker
LateTimePicker.inputView = lateTimePicker
}
#objc func viewTapped(gestureRecognizer: UITapGestureRecognizer){
view.endEditing(true)
}
var earlyTime=480
var earlyTimehour=0
var earlyTimeminute=0
#objc func earlyTimeChanged(earlyTimePicker: UIDatePicker){
let earlyTimeFormatter = DateFormatter()
earlyTimeFormatter.dateFormat = "h:mm a"
earlyTimeFormatter.amSymbol = "AM"
earlyTimeFormatter.pmSymbol = "PM"
EarlyTimePicker.text = earlyTimeFormatter.string(from: earlyTimePicker.date)
view.endEditing(true)
let earlyTimedate = earlyTimePicker.date
let earlyTimecomponents = Calendar.current.dateComponents([.hour, .minute], from: earlyTimedate)
earlyTimehour = earlyTimecomponents.hour!
earlyTimeminute = earlyTimecomponents.minute!
earlyTime = earlyTimecomponents.hour! * 60 + earlyTimecomponents.minute!
print("earlyTimehour: \(earlyTimecomponents.hour!)")
print("earlyTimeminute: \(earlyTimecomponents)")
print("earlyTime: \(earlyTime)")
print("Current Time: \(Date())")
}
var lateTime=1200
var lateTimehour=0
var lateTimeminute=0
#objc func lateTimeChanged(lateTimePicker: UIDatePicker){
let lateTimeFormatter = DateFormatter()
lateTimeFormatter.dateFormat = "h:mm a"
lateTimeFormatter.amSymbol = "AM"
lateTimeFormatter.pmSymbol = "PM"
LateTimePicker.text = lateTimeFormatter.string(from: lateTimePicker.date)
view.endEditing(true)
let lateTimedate = lateTimePicker.date
let lateTimecomponents = Calendar.current.dateComponents([.hour, .minute], from: lateTimedate)
lateTimehour = lateTimecomponents.hour!
lateTimeminute = lateTimecomponents.minute!
lateTime = lateTimecomponents.hour! * 60 + lateTimecomponents.minute!
let testMinute = lateTime % 60
let testHour = lateTime / 60
print("lateTimehour: \(lateTimecomponents.hour!)")
print("lateTimeminute: \(lateTimecomponents)")
print("lateTime: \(lateTime)")
print("testHour: \(testHour)")
print("testMinute: \(testMinute)")
myLabel_TestResetTime.text = "Time Set \(Date())"
myLabel_CurrentEarlyTime.text = "Current Early Time: \(earlyTime) / OnOff: \(OnOff)"
}
let PickedString = ["One","Two","Three","Four", "Five","Six","Seven","Eight"]
// #IBAction func TestCallFunction(_ sender: UIButton) {
// scheduleLocal()
// }
//NEED TO REPEAT THIS FUNCTION AT EARLY TIME - 10
//need to stop repeating with a cancel button (while bool true, do it, while false, stop. Default is false)
var RunDaily: Timer?
var OnOff = false
var QuestionNum = 1
#IBAction func Launch(_ sender: UIButton) {
OnOff = true
let center = UNUserNotificationCenter.current()
center.removeAllPendingNotificationRequests()
guard let QuestionNumA = Int(NumQuestions.text!) else { //This is how to get the UserInterface VALUE as a number
print("not a number!: \(String(describing: NumQuestions.text))")
return
}
print("Number of Questions: \(QuestionNumA)")
// var QuestionNum = 1
if QuestionNumA > 10 {QuestionNum=10} else {QuestionNum=QuestionNumA}
print("QuestionNumA:\(QuestionNumA) vs QuestionNum: \(QuestionNum)")
printStuff()
showMessage()
}
#IBAction func Stop(_ sender: UIButton) {
OnOff = false
printStuff()
}
func printStuff() {
if OnOff == true {
print("Bool is On : \(OnOff)")
RunDaily = Timer.scheduledTimer(timeInterval: 86400, target: self, selector: #selector(showMessage), userInfo: nil, repeats: true)//86400
}
if OnOff == false {
print("Bool is Off : \(OnOff)")
RunDaily?.invalidate()
let center = UNUserNotificationCenter.current()
center.removeAllPendingNotificationRequests()
}
}
func SaveDefaultData(){ // THis is the structure to SAVE input data for when the app relaunches (causes error when run.
let defaults = UserDefaults.standard
defaults.set("Date()", forKey:"key1")
//defaults.set(earlyTimePicker, forKey:"earlyTimePickerSet") cannot set earlyTimePicker. causes crash
// defaults.set(lateTimePicker, forKey:"lateTimePickerSet")
defaults.set(earlyTime, forKey:"earlyTimeSet")
defaults.set(lateTime, forKey:"lateTimeSet")
defaults.set(QuestionNum, forKey:"QuestionNumSet")
}
func SetDefaultData(){// THis is the structure to Set input for when the app relaunches
let defaults = UserDefaults.standard
if let savedValue = defaults.string(forKey: "key1"){
print("Here you will get saved value \(savedValue)")
} else {
print("No value in Userdefault,Either you can save value here or perform other operation")
defaults.set("Here you can save value", forKey: "key1")
}
if let earlyTimeValue = defaults.string(forKey: "earlyTimeSet"){
print("Here you will get saved value \(earlyTimeValue)")
earlyTime = UserDefaults.standard.value(forKey: "earlyTimeSet") as? Int ?? 485
} else {
print("No value in Userdefault,Either you can save value here or perform other operation")
defaults.set("Here you can save value", forKey: "earlyTimeSet")
earlyTime = 500
}
if let lateTimeValue = defaults.string(forKey: "lateTimeSet"){
print("Here you will get saved value \(lateTimeValue)")
lateTime = UserDefaults.standard.value(forKey: "lateTimeSet") as? Int ?? 1265
} else {
print("No value in Userdefault,Either you can save value here or perform other operation")
defaults.set("Here you can save value", forKey: "lateTimeSet")
lateTime = 1230
}
if let QuestionNumValue = defaults.string(forKey: "QuestionNumSet"){
print("Here you will get saved value \(QuestionNumValue)")
QuestionNum = UserDefaults.standard.value(forKey: "QuestionNumSet") as? Int ?? 4
} else {
print("No value in Userdefault,Either you can save value here or perform other operation")
defaults.set("Here you can save value", forKey: "QuestionNumSet")
QuestionNum = 2
}
}
#objc func showMessage() {
let center = UNUserNotificationCenter.current()
if lateTime <= earlyTime {
lateTime = earlyTime+1
if earlyTimehour <= 12 {
LateTimePicker.text = "\(earlyTimehour):\(earlyTimeminute) AM"
}
if earlyTimehour > 12 {
let EarlyTimeAfternoon = earlyTimehour - 12
LateTimePicker.text = "\(EarlyTimeAfternoon):\(earlyTimeminute) PM"
}
}
// center.removeAllPendingNotificationRequests()
// THIS IS WHERE ALL THE USER INPUT GETS INTO THE PROGRAM //
// guard let QuestionNumA = Int(NumQuestions.text!) else { //This is how to get the UserInterface VALUE as a number
// print("not a number!: \(String(describing: NumQuestions.text))")
// return
// }
//print("Number of Questions: \(QuestionNumA)")
// THIS IS WHERE ALL THE USER INPUT GETS INTO THE PROGRAM //
var RandHourArray:[Int] = [0]
var RandMinArray:[Int] = [0]
var RandQuestionArray:[Int] = [0]
var Counter = 1
// var QuestionNum = 1
//if QuestionNumA > 2 {QuestionNum=10} else {QuestionNum=QuestionNumA}
// print("QuestionNumA:\(QuestionNumA) vs QuestionNum: \(QuestionNum)")
for _ in 0 ... QuestionNum-1{
// Pick random times for badges
//let RandHour = Int.random(in: earlyTimehour ... lateTimehour)
let RandTimeMinFromMidnight = Int.random(in: self.earlyTime ... self.lateTime)
let ConvertRandTimeHours = RandTimeMinFromMidnight / 60
let ConvertRandTimeMinutes = RandTimeMinFromMidnight % 60
RandHourArray.append(ConvertRandTimeHours)
//let RandMin = Int.random(in: earlyTimeminute ... lateTimeminute)
RandMinArray.append(ConvertRandTimeMinutes)
let RandQuestion = Int.random(in: 0 ... self.PickedString.count-1)
RandQuestionArray.append(RandQuestion)
//print("RandTimeMinFromMidnight: \(RandTimeMinFromMidnight)")
// print("RandHourArray: \(RandHourArray)")
// print("ConvertRandTimeHours: \(ConvertRandTimeHours)")
// print("RandMinArray: \(RandMinArray)")
// print("ConvertRandTimeMinutes: \(ConvertRandTimeMinutes)")
}
myLabel_Questions.text = "# of questions: \(QuestionNum)"//\(QuestionNumA)"
myLabel_StartEndTime.text = "Start Time \(earlyTime) / End Time \(lateTime)"
let content_A = UNMutableNotificationContent()
content_A.title = "Prompt"
content_A.body = self.PickedString[RandQuestionArray[Counter]] //
content_A.categoryIdentifier = "alarm"
content_A.userInfo = ["customData": "fizzbuzz"]
content_A.sound = UNNotificationSound.default
var dateComponents_A = DateComponents()
dateComponents_A.hour = RandHourArray[Counter]
dateComponents_A.minute = RandMinArray[Counter]
let trigger_A = UNCalendarNotificationTrigger(dateMatching: dateComponents_A, repeats: false)
let request_A = UNNotificationRequest(identifier: UUID().uuidString, content: content_A, trigger: trigger_A)
center.add(request_A)
print("Request A time: \(RandHourArray[Counter]) : \(RandMinArray[Counter])")
print("Question String picked A: \(self.PickedString[RandQuestionArray[Counter]])")
Counter=2
if Counter<=QuestionNum {
let content_B = UNMutableNotificationContent()
content_B.title = "Prompt"
content_B.body = self.PickedString[RandQuestionArray[Counter]]
content_B.categoryIdentifier = "alarm"
content_B.userInfo = ["customData": "fizzbuzz"]
content_B.sound = UNNotificationSound.default
var dateComponents_B = DateComponents()
dateComponents_B.hour = RandHourArray[Counter]
dateComponents_B.minute = RandMinArray[Counter]
let trigger_B = UNCalendarNotificationTrigger(dateMatching: dateComponents_B, repeats: false)
let request_B = UNNotificationRequest(identifier: UUID().uuidString, content: content_B, trigger: trigger_B)
center.add(request_B)
print("Request B time: \(RandHourArray[Counter]) : \(RandMinArray[Counter])")
print("Question String picked B: \(self.PickedString[RandQuestionArray[Counter]])")
}
}
}
You should store your data inside UserDefaults, Keychain and Core Data or other stuff. if you dont store your data every time you close the application all the data will deallocate from the memory because they were stored in the heap.
Unsaved data:
let myLabel: UILabel = UILabel()
myLabel.text = "Some text"
Should save like:
UserDefaults.standard.setValue(myLabel.text, forKey: "it.is.custom")
And load like:
myLabel.text = UserDefaults.standard.value(forKey: "it.is.custom") as? String
refrence to study: https://fluffy.es/persist-data/

What's the correct way to pass changed value of variable?

So this is my code as you can see I'm trying to change the value of activitylevel if the image of a button is the same it all works fine and it changes the value, but when I try to use it down in the CaloriesCalculator function at let tde = activity * bmr activity still equals 0.0. I know that I can save it with UserDefaults, but that doesn't seem the correct way to me. Any help will be much appreciated.
class MenuController: UIViewController {
var calGoal: Double = 0.0
var activitylevel: Double = 0.0
#IBOutlet weak var Weight: UITextField!
#IBOutlet weak var Height: UITextField!
#IBOutlet weak var Age: UITextField!
#IBAction func ActivityLevelButton(_ sender: UIButton) {
if let ButtonImage = LightlyActive.image(for: .normal),
let Image = UIImage(named: "LightlyActiveGreen"),
ButtonImage.pngData() == Image.pngData()
{
activitylevel = 1.375
print(activitylevel)
}; if let ButtonImage = Active.image(for: .normal),
let Image = UIImage(named: "ActiveGreen"),
ButtonImage.pngData() == Image.pngData() {
activitylevel = 1.55
print(activitylevel)
}; if let ButtonImage = VeryActive.image(for: .normal),
let Image = UIImage(named: "VeryActiveGreen"),
ButtonImage.pngData() == Image.pngData() {
activitylevel = 1.755
print(activitylevel)
}
}
#IBAction func CaloriesCalculator(_ sender: UIButton) {
let w = Double(Weight.text!) ?? 0
let h = Double(Height.text!)! * 0.393701
let a = Double(Age.text!) ?? 0
let bmr = 66 + (6.23 * w) + (12.7 * h) - (6.8 * a)
let activity = activitylevel
let tde = activity * bmr
calGoal = tde
print(activitylevel)
}

How do I pass data between functions in this Firebase situation? Swift + Xcode

I am very new to Swift. How would I retrieve my annotation from the addPin function and be able to use it in my addLocation action (buttonPressed). I am trying to add a pin on to a map using a force touch, type in a name and information in two separate text fields, and add these four pieces of information to my Firebase Database where they can be retrieved and plotted on another map. Similar to how the app Flush works.
class AddLocationViewController: UIViewController {
#IBOutlet weak var nameTF : UITextField!
#IBOutlet weak var descriptionTF : UITextField!
#IBOutlet weak var longitudeTF : UITextField!
#IBOutlet weak var latitudeTF : UITextField!
#IBOutlet weak var addButton : UIButton!
#IBOutlet weak var readySwitch: UISwitch!
#IBAction func addLocation ( _ sender : Any? ) {
if let name = nameTF.text,
let info = descriptionTF.text,
let latitude = Optional(annotation.coordinate.latitude) ,
let longitude = Optional(annotation.coordinate.longitude),
name.isEmpty == false {
let dict : [String:Any] = ["name":name, "info":info, "latitude": latitude, "longitude":longitude]
let ref = Database.database().reference()
let newPointRef = ref.child("annotations").childByAutoId()
ref.child("annotations").child(newPointRef.key).setValue(dict)
}
}
#IBAction func textChanged ( _ sender : Any? ) {
validateUserInterface()
}
func validateUserInterface () {
addButton.isEnabled = false
guard let name = nameTF.text, name.isEmpty == false else { return
if let _ = CLLocationDegrees( latitudeTF.text ?? "" ),
let _ = CLLocationDegrees( longitudeTF.text ?? "" )
/*let location = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)*/ {
addButton.isEnabled = true
}
}
override func viewDidLoad() {
super.viewDidLoad()
validateUserInterface()
}
#IBOutlet weak var addCourtMapView: MKMapView!
#IBAction func addPin(_ sender: UILongPressGestureRecognizer) {
let location = sender.location(in: self.addCourtMapView)
let locCoord = self.addCourtMapView.convert(location, toCoordinateFrom: self.addCourtMapView)
let annotation = MKPointAnnotation()
annotation.coordinate = locCoord
annotation.title = "New Court"
annotation.subtitle = "The court is located here"
self.addCourtMapView.removeAnnotations(addCourtMapView.annotations)
self.addCourtMapView.addAnnotation(annotation)
}
}
You need to make a shared func and call it like this
func sharedStore(name:String,info:String,longitude:Double,latitude:Double) {
if name.isEmpty == false {
let dict : [String:Any] = ["name":name, "info":info, "latitude": latitude, "longitude":longitude]
let ref = Database.database().reference()
let newPointRef = ref.child("annotations").childByAutoId()
ref.child("annotations").child(newPointRef.key).setValue(dict)
}
}
//
#IBAction func addLocation ( _ sender : Any? ) {
if let name = nameTF.text,
let info = descriptionTF.text,
let latitude = Optional(annotation.coordinate.latitude) ,
let longitude = Optional(annotation.coordinate.longitude),
name.isEmpty == false {
sharedStore(name:name, info:info, longitude: longitude, latitude: latitude)
}
}
//
#IBAction func addPin(_ sender: UILongPressGestureRecognizer) {
let location = sender.location(in: self.addCourtMapView)
let locCoord = self.addCourtMapView.convert(location, toCoordinateFrom: self.addCourtMapView)
let name = "New Court"
let info = "The court is located here"
let annotation = MKPointAnnotation()
annotation.coordinate = locCoord
annotation.title = name
annotation.subtitle = info
self.addCourtMapView.removeAnnotations(addCourtMapView.annotations)
self.addCourtMapView.addAnnotation(annotation)
sharedStore(name:name, info:info, longitude: locCoord.longitude, latitude :locCoord.latitude)
}
You can use addCourtMapView.annotations to get annotations on the MapView:
#IBAction func addLocation ( _ sender : Any? ) {
guard let annotation = addCourtMapView.annotations.first else {
return
}
if let name = nameTF.text,
let info = descriptionTF.text,
let latitude = Optional(annotation.coordinate.latitude) ,
let longitude = Optional(annotation.coordinate.longitude),
name.isEmpty == false {
...

App Only Crashes for Iphone 6 and IPad in IOS 11 using Vision & Machine Learning API

I made a live translation app that identifies an object and translates it using the user's camera. It works just fine on my iPhone 6s and doesn't crash in any of the simulators, but when I run it on an iPhone 6, it crashes as soon I try to segue to the camera feed. Apple also says it crashes on the iPad as well.
Do certain devices just not support Vision API or is something wrong with my code?
import UIKit
import AVKit
import Vision
var lang = ""
var lang2 = ""
class ViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate, AVCapturePhotoCaptureDelegate {
#IBAction func screenshotB(_ sender: Any) {
//screenshot camera screen view
}
#IBOutlet weak var screenshotBOutlet: UIButton!
#IBOutlet weak var swirlyGuy: UIActivityIndicatorView!
#IBOutlet weak var title1: UILabel!
#IBOutlet weak var settingsButtonOutlet: UIButton!
#IBOutlet weak var launchScreen: UIViewX!
#IBOutlet weak var launchScreenLogo: UIImageView!
func stopSwirlyGuy(){
swirlyGuy.stopAnimating()
}
let identifierLabel: UILabel = {
let label = UILabel()
label.backgroundColor = UIColor(red: 0, green: 0, blue:0, alpha: 0.4)
label.textColor = .white
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
#IBAction func prepareForUnwind (segue:UIStoryboardSegue) {
}
override func viewDidLoad() {
super.viewDidLoad()
launchScreen.alpha = 1
launchScreenLogo.alpha = 1
swirlyGuy.startAnimating()
// start up the camera
let captureSession = AVCaptureSession()
captureSession.sessionPreset = .hd4K3840x2160
guard let captureDevice = AVCaptureDevice.default(for: .video) else { return }
guard let input = try? AVCaptureDeviceInput(device: captureDevice) else { return }
captureSession.addInput(input)
captureSession.startRunning()
let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
view.layer.addSublayer(previewLayer)
previewLayer.frame = view.frame
let dataOutput = AVCaptureVideoDataOutput()
dataOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoQueue"))
captureSession.addOutput(dataOutput)
setupIdentifierConfidenceLabel()
setupSettingsButton()
setupTitle()
setupSwirlyGuy()
setupScreenshot()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
UIView.animate(withDuration: 1.5) {
self.launchScreen.alpha = 0
self.launchScreenLogo.alpha = 0
}
}
fileprivate func setupSettingsButton() {
view.addSubview(settingsButtonOutlet)
}
fileprivate func setupScreenshot() {
view.addSubview(screenshotBOutlet)
}
fileprivate func setupSwirlyGuy() {
view.addSubview(swirlyGuy)
}
fileprivate func setupTitle() {
view.addSubview(title1)
}
fileprivate func setupIdentifierConfidenceLabel() {
view.addSubview(identifierLabel)
identifierLabel.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
identifierLabel.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
identifierLabel.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
identifierLabel.heightAnchor.constraint(equalToConstant: 100).isActive = true
identifierLabel.numberOfLines = 0
}
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
// print("Camera was able to capture a frame:", Date())
guard let pixelBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
// model
guard let model = try? VNCoreMLModel(for: Resnet50().model) else { return }
let request = VNCoreMLRequest(model: model) { (finishedReq, err) in
//perhaps check the err
// print(finishedReq.results)
guard let results = finishedReq.results as? [VNClassificationObservation] else { return }
guard let firstObservation = results.first else { return }
print(firstObservation.identifier, firstObservation.confidence)
let x = (firstObservation.confidence)
let y = (x * 10000).rounded() / 10000
let z = (firstObservation.identifier)
let s = (self.translateSpanish(object1: firstObservation.identifier))
let f = (self.translateFrench(object1: firstObservation.identifier))
// var lang = ""
// var lang2 = ""
if language == "English" {
lang = z
}
else if language == "Spanish" {
lang = s
}
else {
lang = f
}
if language2 == "Spanish" {
lang2 = s
}
else if language2 == "English" {
lang2 = z
}
else {
lang2 = f
}
DispatchQueue.main.async {
self.identifierLabel.text = "\(lang)" + " = " + "\(lang2) \n \(y * 100)% accuracy"
self.stopSwirlyGuy()
}
}
try? VNImageRequestHandler(cvPixelBuffer: pixelBuffer, options: [:]).perform([request])
}
//Translation fucntions omitted for brevity
This is the code for the view controller that segues into the main screen where the camera feed and Vision processing take place.
import UIKit
class FirstLaunchViewController: UIViewController {
#IBOutlet weak var title1: UILabelX!
#IBOutlet weak var logo1: UIImageView!
#IBOutlet weak var description1: UILabel!
#IBOutlet weak var buttonOutlet: UIButtonX!
#IBOutlet weak var initialBackground: UIViewX!
#IBOutlet weak var initialLogo: UIImageView!
#IBAction func toVC(_ sender: Any) {
UserDefaults.standard.set(false, forKey: "name")
performSegue(withIdentifier: "toMain", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
initialLogo.alpha = 1
initialBackground.alpha = 1
title1.alpha = 0
logo1.alpha = 0
description1.alpha = 0
buttonOutlet.alpha = 0
// Do any additional setup after loading the view.
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
UIView.animate(withDuration: 1.5, animations: {
self.initialLogo.alpha = 0
self.initialBackground.alpha = 0
}) { (true) in
self.initialBackgroundGone()
}
}
func initialBackgroundGone() {
UIView.animate(withDuration: 1.5, animations: {
self.title1.alpha = 1
}) { (true) in
self.showBackgroundAgain()
}
}
func showBackgroundAgain() {
UIView.animate(withDuration: 1.3, animations: {
self.logo1.alpha = 1
}) { (true) in
self.showTitle()
}
}
func showTitle() {
UIView.animate(withDuration: 1.5, animations: {
self.description1.alpha = 1
}) { (true) in
self.showEverythingElse()
}
}
func showEverythingElse() {
UIView.animate(withDuration: 3.5) {
self.buttonOutlet.alpha = 1
}
}
}
This is a lot of code but I think your issue comes from the video preset your are using as iPhone 6 doesn't have support for 4K video recording.
When setting the session preset you should test that it is supported by all the targeted devices:
if captureSession.canSetSessionPreset(.hd4K3840x2160) {
captureSession.sessionPreset = .hd4K3840x2160
} else {
captureSession.sessionPreset = .high // or any other preset that suits your needs
}