#swift #nsuserdefaults
#swift #nsuserdefaults
Вопрос:
Я успешно использую пользовательские значения по умолчанию на других страницах моего приложения, оно работает так, как вы ожидаете. В этом конкретном контроллере я вызвал метод из структуры с параметрами и назначил его как константу. Насколько я могу судить, по какой-то причине эта конфигурация не будет сохранять или извлекать данные из пользовательских значений по умолчанию. Я уверен, что есть способ, но я не знаю правильного способа. Здесь очень помогли бы некоторые рекомендации.
Итак, я пытаюсь сохранить текстовые поля в пользовательских значениях по умолчанию и вызвать данные текстового поля, а также метод после перезагрузки приложения, чтобы у пользователя были все старые данные в такте. Прямо сейчас ничего не происходит, я даже не могу распечатать, чтобы устранить неполадки, если что-то будет сохранено, потому что я действительно не знаю, как распечатать сохраненное состояние. Новичок здесь.
До сих пор я пытался переместить точку сохранения в разные места, перед вызовом метода при нажатии кнопки, после вызова также пытался вставить пользовательские значения по умолчанию в метод struct, все безуспешно! Я также пробовал различные методы поиска в представлении, загружал, но пока не заходил.
Вот где в настоящее время находится мой код, сохранение по умолчанию для нерабочего пользователя:
override func viewDidLoad() {
area.delegate = self
volume.delegate = self
height.delegate = self
// Check to see if there is a saved state, if there is then use those numbers and run method for even gauge
let savedArea = StateManager.retrieveClearCalcValue(key: StateManager.areaKey) as? Double
let savedVolume = StateManager.retrieveClearCalcValue(key: StateManager.volumeKey) as? Double
let savedHeight = StateManager.retrieveClearCalcValue(key: StateManager.lengthKey) as? Double
// If there is data in saved states, set text fields to saved data and call calculate
if (savedArea != nil) amp;amp; (savedVolume != nil) amp;amp; (savedHeight != nil) {
area.text = String(savedArea!)
volume.text = String(savedVolume!)
height.text = String(savedHeight!)
let result = zoneCalc.clearCalc(area: Double(area.text!), volume: Double(volume.text!), height: Double(height!))
areaBorder.text = String("(result.0) mm")
areaBorderLabel.text = "Cut result:"
}
}
Кнопка:
@IBAction func calcButtonPress(_ sender: Any) {
// Resigns keyboard once button pressed
self.view.endEditing(true)
// State save attempt
StateManager.saveClearZone(area: Double(area.text!), volume: Double(volume.text!), height: Double(height!))
let result = clearCalc.clearZoneCalc(area: Double(area.text!) ?? 1.0, volume: Double(volume.text!) ?? 1.0, height: Double(height!))
areaBorder.text = String("(result.0) mm")
areaBorderLabel.text = "Cut result:"
}
РЕДАКТИРОВАТЬ (добавление структуры сохранения):
struct StateManager {
static var unitAreaKey = "UnitArea"
static var unitVolumeKey = "UnitVolume"
static var unitHeightKey = "UnitHeight"
// Saving user data
static func saveClearCalcState(area: Any, volume: Any, height: Any) {
// Call reference to user defaults
let defaults = UserDefaults.standard
// Save state data
defaults.set(area, forKey: unitAreaKey)
defaults.set(volume, forKey: unitVolumeKey)
defaults.set(height, forKey: unitHeightKey)
}
// Retrieve user data
static func retrieveClearCalcValue(key: String) -> Any? {
//Call reference to user defaults
let defaults = UserDefaults.standard
return defaults.value(forKey: key)
}
}
Комментарии:
1. Код вообще не связан с
UserDefaults
. Как мы можем знать, что это такоеzoneCalc
иStateManager
прочее?2. исправлено, что … zoneCalc — это просто калькулятор, который вычисляет некоторые числа, взятые из текстовых полей…
3. Внутри вызывается
calcButtonPress
методStateManager.saveClearZone
, но в предоставленном вами коде такого метода нет, не могли бы вы добавить его, пожалуйста?4. исправлено, проблема была не в этом. Это была моя опечатка при публикации этим утром после долгой ночной смены. Я должен изменить свой код на post, потому что он содержит конфиденциальную интеллектуальную собственность… проще говоря: приведенный выше код работает хорошо, сохраняя состояние пользователя внутри вызова функции в контроллере представления, однако в этой конфигурации я пытаюсь сохранить после и до вызова метода struct, у меня возникают проблемы… Должен ли я сохранять весь вызов метода struct? Можно ли это сделать? … прошу прощения за головоломки, все еще привыкаю к тому, как публиковать здесь.
5. Получил его для печати сохраненных значений в viewDidLoad, и похоже, что только одно из трех печатает значение, а другие печатают ноль… Я трижды проверил, что мой код исправен. Что происходит? помощь приветствуется
![]()
Ответ №1:
Мое лучшее предположение заключается в том, что преобразование из String в Double иногда завершается ошибкой в этой строке (при условии, что вместо saveClearZone
вы хотели написать saveClearCalcState
):
StateManager.saveClearZone(area: Double(area.text!), volume: Double(volume.text!), height: Double(height!))
Инициализатор Double из строки является отказоустойчивым, что означает, что он может вернуться nil
, если преобразование из строки в число завершается неудачей. Это может привести к сбою из-за широкого круга проблем, таких как конечный пробел или нестрогий формат.
Ниже приведены несколько рекомендаций, как это исправить.
Используйте строго типизированные аргументы функции и избегайте Any
В настоящее время ваш метод сохранения принимается Any
, но если вы знаете, что хотите сохранить свои данные только тогда, когда пользователь правильно ввел все значения, используйте Double
вместо этого:
static func saveClearCalcState(area: Double, volume: Double, height: Double)
Если вы измените типы аргументов на Double
, ваш код больше не будет компилироваться, потому что инициализаторам нравится Double(area.text!)
return Double?
, и вам придется сначала развернуть опции, чтобы проверить, что значения действительны, что является хорошей возможностью сообщить пользователю, если его ввод не может быть обработан.
Если вы намерены просто сохранить все, что ввел пользователь, чтобы сохранить состояние между запусками, вы можете выбрать String?
вместо Any
. Независимо от того, что вы выберете вместо Any
, использование метода будет намного понятнее.
Используется NumberFormatter
для преобразования строк в числа
NumberFormatter
Класс обеспечивает гораздо большую гибкость для этой задачи. Например, вы можете преобразовать числа, введенные пользователем, в их текущую локаль. Скажем, если ваш пользователь находится в стране, где в качестве десятичного разделителя используется запятая, NumberFormatter
это позволит им использовать предпочитаемый способ ввода чисел, в то время как Double
инициализатору всегда требуется символ полной остановки в качестве десятичного разделителя.
Используйте необязательную цепочку вместо принудительного развертывания
Ваш код содержит много принудительного развертывания (операторы восклицательного знака). Помните, что попытка принудительного развертывания nil
приведет к сбою вашего приложения. В некоторых случаях это может быть нормально, но было бы нехорошо завершать работу приложения только потому, что в текстовом поле нет текста.
Предпочитаю необязательную цепочку принудительному развертыванию.
Пример изящной обработки с нулевым значением
@IBAction func calcButtonPress(_ sender: Any) {
// Resigns keyboard once button pressed
self.view.endEditing(true)
guard let areaText = area.text, !areaText.isEmpty else {
// TODO: alert the user that area can't be empty
return
}
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.locale = Locale.current
guard let areaValue = numberFormatter.number(from: areaText)?.doubleValue else {
// TODO: alert the user that the text they entered can't be recognized as a numeric value
return
}
//...
//... do the same checks for volume and height
//...
// State save attempt
StateManager.saveClearZone(area: areaValue, volume: volumeValue, height: heightValue)
let result = clearCalc.clearZoneCalc(area: areaValue, volume: volumeValue, height: heightValue)
areaBorder.text = String("(result.0) mm")
areaBorderLabel.text = "Cut result:"
}
Комментарии:
1. спасибо за подробный пост, я определенно чему-то научился с помощью number formatter, я применил его. Я также обрабатываю опции путем объединения. У меня все еще возникают проблемы! Сверхпрочность сохранения ключей и значений каким-то образом нарушается. Итак, на данный момент я попробовал много новых вещей, таких как форматирование чисел в строки, это все, что сохраняется сейчас, сохранение двойных значений возвращает ноль для всех ключей. Также сохранение строк является дурацким, оно сохранит значение ключа 1 идеально, но 2 и 3 всегда разные, иногда вторые последние значения, которые я ввел … не имеют смысла. Я даже пытался использовать. syncronize() — нет.
2. @AppMonster, я отредактировал свой ответ, включив пример того, как я буду обрабатывать nils в такой ситуации. Если вы сделали что-то подобное и все еще испытываете проблемы, пожалуйста, приложите фактический код, который не работает, и я буду рад помочь.
3. изменил мой пост ниже со всем кодом. Все еще не работает, все еще ломаю голову над этим. Любая помощь действительно ценится!
Ответ №2:
@Vadim, во-первых, еще раз спасибо за подробный пост. Снова многому научился и применил вашу необязательную обработку, с этого момента я буду использовать эти методы. Очень лаконично!
Что касается проблем с пользовательскими значениями по умолчанию… ОНИ ВСЕ ЕЩЕ ЕСТЬ. Это сводит меня с ума. Я перепробовал так много разных вещей, что едва могу перечислить их все, но я попробую здесь:
У меня есть:
- Переписал структуру State manager 3 раза и изменил много разных вещей и предпринял попытку обработки всех типов данных
- Перемещал точку состояния сохранения в коде много раз и во многие разные точки
- Загруженный cocopod «Defaults», который в конечном итоге столкнулся с точно такой же проблемой, как UserDefaults
- Я изменил свой метод загрузки view did НЕ МЕНЕЕ 10 раз с множеством разных конфигураций
- На данный момент пробовал все виды необязательной обработки с нулевым значением
Что происходит не так:
- Независимо от того, какие конфигурации кода я получаю одно и то же странное извлечение данных, потому что я записываю значения в текстовые поля при перезагрузке, если не nil, я могу видеть значения (также их распечатывая). И последовательно 1-е текстовое поле является правильным, но второе и третье неверны. Иногда 2-й и 3-й отображают последние введенные данные, но не самые последние данные перезагрузки. Как будто это отстает от одной перезагрузки. Пример:
Попытка первая: Поле 1: 12345 Поле 2: 1234 Поле 3: 123 Перезагрузка—
Загрузка: Показать поле 1: 12345 Поле 2: Поле 3: Попытка ввода новых данных: Поле 1: 54321 Поле 2: 5432 Поле 3: 543 Перезагрузка—
Показать- Поле 1: 54321 Поле 2: 1234 Поле 3: 123
WTF?
Также я должен заявить, что это точное состояние отлично работает для 6 других контроллеров просмотра и использует те же самые методы struct для сохранения и извлечения. Единственное отличие в том, что в этом VC я создал класс для калькулятора, а в других калькулятор маленький, поэтому он в VC объявлен и вызывается как функция без параметров…
В любом случае, вот мой ПОЛНЫЙ код для VC, без изменений, если вы хотите помочь, я был бы вам очень признателен и буду продвигать услугу в будущем, когда я буду осведомлен:
// Copyright © 2020 Roberto B. All rights reserved.
//
import UIKit
class CutCalculatorViewController: UIViewController {
// Length cut user inputs
@IBOutlet weak var overallLength: UITextField!
@IBOutlet weak var unitLength: UITextField!
@IBOutlet weak var headJointSize: UITextField!
@IBOutlet weak var metricImperialLengthSelector: UISegmentedControl!
// Length cut labels
@IBOutlet weak var buttonSelectorLabel: UILabel!
@IBOutlet weak var courseOneCut: UILabel!
@IBOutlet weak var courseOneCutLabel: UILabel!
@IBOutlet weak var courseTwoCut: UILabel!
@IBOutlet weak var courseTwoCutLabel: UILabel!
// Height cut user inputs
@IBOutlet weak var overallHeight: UITextField!
@IBOutlet weak var unitHeight: UITextField!
@IBOutlet weak var bedJointSize: UITextField!
@IBOutlet weak var metricImperialHeightSelector: UISegmentedControl!
// Height cut label
@IBOutlet weak var heightCutResult: UILabel!
override func viewDidLoad() {
if StateManager.retrieveCutCalcValue(key: StateManager.overallLengthKey) != nil amp;amp; StateManager.retrieveCutCalcValue(key: StateManager.unitLengthKey) != nil amp;amp; StateManager.retrieveCutCalcValue(key: StateManager.headJointSizeKey) != nil amp;amp; StateManager.retrieveCutCalcValue(key: StateManager.unitLengthSelector) != nil amp;amp; StateManager.retrieveCutCalcValue(key: StateManager.unitLengthSelector) as? Int == 0 {
let savedOverallLength = StateManager.retrieveCutCalcValue(key: StateManager.overallLengthKey) as? Double
let savedUnitLength = StateManager.retrieveCutCalcValue(key: StateManager.unitLengthKey) as? Double
let savedHeadJoint = StateManager.retrieveCutCalcValue(key: StateManager.headJointSizeKey) as? Double
metricImperialLengthSelector.selectedSegmentIndex = 0
print(savedOverallLength!)
print(savedUnitLength!)
print(savedHeadJoint!)
print(metricImperialLengthSelector.selectedSegmentIndex)
overallLength.text = String(savedOverallLength!)
unitLength.text = String(savedUnitLength!)
headJointSize.text = String(savedHeadJoint!)
let result = cutCalc.metricRunningBondCalc(overallLength: savedOverallLength!, unitLength: savedUnitLength!, headJointSize: savedHeadJoint!)
courseOneCut.text = String("(result.0) mm")
courseTwoCut.text = "N/A"
courseTwoCut.textColor = UIColor.clear
courseTwoCutLabel.textColor = UIColor.clear
buttonSelectorLabel.text = "Stack bond cut result"
courseOneCutLabel.text = "Cut result:"
} else if StateManager.retrieveCutCalcValue(key: StateManager.overallLengthKey) != nil amp;amp; StateManager.retrieveCutCalcValue(key: StateManager.unitLengthKey) != nil amp;amp; StateManager.retrieveCutCalcValue(key: StateManager.headJointSizeKey) != nil amp;amp; StateManager.retrieveCutCalcValue(key: StateManager.unitLengthSelector) != nil amp;amp; StateManager.retrieveCutCalcValue(key: StateManager.unitLengthSelector) as? Int == 1 {
let savedOverallLength = StateManager.retrieveCutCalcValue(key: StateManager.overallLengthKey)
let savedUnitLength = StateManager.retrieveCutCalcValue(key: StateManager.unitLengthKey)
let savedHeadJoint = StateManager.retrieveCutCalcValue(key: StateManager.headJointSizeKey)
metricImperialLengthSelector.selectedSegmentIndex = 1
print(savedOverallLength!)
print(savedUnitLength!)
print(savedHeadJoint!)
print(metricImperialLengthSelector.selectedSegmentIndex)
overallLength.text = savedOverallLength as? String
unitLength.text = savedUnitLength as? String
headJointSize.text = savedHeadJoint as? String
let result = cutCalc.imperialRunningBondCalc(overallLength: savedOverallLength as! Double, unitLength: savedUnitLength as! Double, headJointSize: savedHeadJoint as! Double)
courseOneCut.text = String("(result.0) inches")
courseTwoCut.text = "N/A"
courseTwoCut.textColor = UIColor.clear
courseTwoCutLabel.textColor = UIColor.clear
buttonSelectorLabel.text = "Stack bond cut result"
courseOneCutLabel.text = "Cut result:"
}
super.viewDidLoad()
}
// Initialize cut calculator structure
let cutCalc = CutCalculator()
// Initialize metric imperial segments
var unitLengthMeasurement: Bool = true
var unitHeightMeasurement: Bool = true
// Length cut buttons
// Stack bond- DONE
@IBAction func stackBondLength(_ sender: Any) {
// Resigns keyboard once button pressed
self.view.endEditing(true)
// Activate methods for cut calculation metric/imperial amp; label changes
if unitLengthMeasurement == true {
guard let overallLength = overallLength.text, !overallLength.isEmpty else {
let alert = UIAlertController(title: "Empty field!", message: "All text fields must contain data.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Got it!", style: .cancel, handler: nil))
self.present(alert, animated: true)
return
}
guard let unitLength = unitLength.text, !unitLength.isEmpty else {
let alert = UIAlertController(title: "Empty field!", message: "All text fields must contain data.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Got it!", style: .cancel, handler: nil))
self.present(alert, animated: true)
return
}
guard let headJoint = headJointSize.text, !headJoint.isEmpty else {
let alert = UIAlertController(title: "Empty field!", message: "All text fields must contain data.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Got it!", style: .cancel, handler: nil))
self.present(alert, animated: true)
return
}
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.locale = Locale.current
guard let overallLengthValue = numberFormatter.number(from: overallLength)?.doubleValue else {
// TODO: alert the user that the text they entered can't be recognized as a numeric value
return
}
guard let unitLengthValue = numberFormatter.number(from: unitLength)?.doubleValue else {
// TODO: alert the user that the text they entered can't be recognized as a numeric value
return
}
guard let headJointValue = numberFormatter.number(from: headJoint)?.doubleValue else {
// TODO: alert the user that the text they entered can't be recognized as a numeric value
return
}
let unitSelectorValue = metricImperialLengthSelector.selectedSegmentIndex
StateManager.saveLengthCutCalcState(overallLength: overallLengthValue, unitLength: unitLengthValue, headJointSize: headJointValue, measurementLengthSelector: unitSelectorValue)
let result = cutCalc.metricRunningBondCalc(overallLength: overallLengthValue, unitLength: unitLengthValue, headJointSize: headJointValue)
courseOneCut.text = "(result.0) mm"
courseTwoCut.text = "N/A"
courseTwoCut.textColor = UIColor.clear
courseTwoCutLabel.textColor = UIColor.clear
buttonSelectorLabel.text = "Stack bond cut result"
courseOneCutLabel.text = "Cut result:"
// Popup alert
if result.0 < 36.0 {
// First instantiate the UIAlertController
let alert = UIAlertController(title: "Small cut!", message: "Depending on conditions you may be able to open or squeeze head joints to eliminate this small cut.", preferredStyle: .alert)
// Add action buttons to it and attach handler functions if you want to
alert.addAction(UIAlertAction(title: "Got it!", style: .cancel, handler: nil))
// Show the alert by presenting it
self.present(alert, animated: true)
}
} else {
guard let overallLength = overallLength.text, !overallLength.isEmpty else {
let alert = UIAlertController(title: "Empty field!", message: "All text fields must contain data.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Got it!", style: .cancel, handler: nil))
self.present(alert, animated: true)
return
}
guard let unitLength = unitLength.text, !unitLength.isEmpty else {
let alert = UIAlertController(title: "Empty field!", message: "All text fields must contain data.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Got it!", style: .cancel, handler: nil))
self.present(alert, animated: true)
return
}
guard let headJoint = headJointSize.text, !headJoint.isEmpty else {
let alert = UIAlertController(title: "Empty field!", message: "All text fields must contain data.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Got it!", style: .cancel, handler: nil))
self.present(alert, animated: true)
return
}
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.locale = Locale.current
guard let overallLengthValue = numberFormatter.number(from: overallLength)?.doubleValue else {
// TODO: alert the user that the text they entered can't be recognized as a numeric value
return
}
guard let unitLengthValue = numberFormatter.number(from: unitLength)?.doubleValue else {
// TODO: alert the user that the text they entered can't be recognized as a numeric value
return
}
guard let headJointValue = numberFormatter.number(from: headJoint)?.doubleValue else {
// TODO: alert the user that the text they entered can't be recognized as a numeric value
return
}
let unitSelectorValue = metricImperialLengthSelector.selectedSegmentIndex
StateManager.saveLengthCutCalcState(overallLength: overallLengthValue, unitLength: unitLengthValue, headJointSize: headJointValue, measurementLengthSelector: unitSelectorValue)
let result = cutCalc.imperialRunningBondCalc(overallLength: overallLengthValue, unitLength: unitLengthValue, headJointSize: headJointValue)
courseOneCut.text = "(result.0) inches"
courseTwoCut.text = "N/A"
courseTwoCut.textColor = UIColor.clear
courseTwoCutLabel.textColor = UIColor.clear
buttonSelectorLabel.text = "Stack bond cut result"
courseOneCutLabel.text = "Cut result:"
// Popup alert
if result.2 < 2.5 {
// First instantiate the UIAlertController
let alert = UIAlertController(title: "Small cut!", message: "Depending on conditions you may be able to open or squeeze head joints to eliminate this small cut.", preferredStyle: .alert)
// Add action buttons to it and attach handler functions if you want to
alert.addAction(UIAlertAction(title: "Got it!", style: .cancel, handler: nil))
// Show the alert by presenting it
self.present(alert, animated: true)
}
}
}
// Running bond- DONE
@IBAction func runningBondLength(_ sender: Any) {
// Resigns keyboard once button pressed
self.view.endEditing(true)
// Activate methods for cut calculation metric/imperial amp; label changes
if unitLengthMeasurement == true {
let result = cutCalc.metricRunningBondCalc(overallLength: Double(overallLength.text!) ?? 1.0, unitLength: Double(unitLength.text!) ?? 1.0, headJointSize: Double(headJointSize.text!) ?? 1.0)
courseOneCut.text = String("(result.0) mm")
courseTwoCut.text = String("(result.1) mm")
buttonSelectorLabel.text = "Running bond cut results"
courseTwoCut.textColor = #colorLiteral(red: 0.7333333333, green: 0.8823529412, blue: 0.9803921569, alpha: 1)
courseTwoCutLabel.textColor = #colorLiteral(red: 0.7333333333, green: 0.8823529412, blue: 0.9803921569, alpha: 1)
courseOneCutLabel.text = "Course 1 cut:"
courseTwoCutLabel.text = "Course 2 cut:"
// Popup alert
if result.0 < 36 || result.1 < 36 {
// First instantiate the UIAlertController
let alert = UIAlertController(title: "Small cut!", message: "Depending on conditions you may be able to open or squeeze head joints to eliminate this small cut.", preferredStyle: .alert)
// Add action buttons to it and attach handler functions if you want to
alert.addAction(UIAlertAction(title: "Got it!", style: .cancel, handler: nil))
// Show the alert by presenting it
self.present(alert, animated: true)
}
} else {
let result = cutCalc.imperialRunningBondCalc(overallLength: Double(overallLength.text!) ?? 1.0, unitLength: Double(unitLength.text!) ?? 1.0, headJointSize: Double(headJointSize.text!) ?? 1.0)
courseOneCut.text = String("(result.0) inches")
courseTwoCut.text = String("(result.1) inches")
buttonSelectorLabel.text = "Running bond cut results"
courseTwoCut.textColor = #colorLiteral(red: 0.7333333333, green: 0.8823529412, blue: 0.9803921569, alpha: 1)
courseTwoCutLabel.textColor = #colorLiteral(red: 0.7333333333, green: 0.8823529412, blue: 0.9803921569, alpha: 1)
courseOneCutLabel.text = "Course 1 cut:"
courseTwoCutLabel.text = "Course 2 cut:"
// Popup alert
if result.2 < 2.5 || result.3 < 2.5 {
// First instantiate the UIAlertController
let alert = UIAlertController(title: "Small cut!", message: "Depending on conditions you may be able to open or squeeze head joints to eliminate this small cut.", preferredStyle: .alert)
// Add action buttons to it and attach handler functions if you want to
alert.addAction(UIAlertAction(title: "Got it!", style: .cancel, handler: nil))
// Show the alert by presenting it
self.present(alert, animated: true)
}
}
}
// Height cut button- DONE
@IBAction func heightCut(_ sender: Any) {
// Resigns keyboard once button pressed
self.view.endEditing(true)
// Activate methods for cut calculation metric/imperial amp; label changes
if unitHeightMeasurement == true {
let result = cutCalc.metricHeightCutCalc(overallHeight: Double(overallHeight.text!) ?? 1.0, unitHeight: Double(unitHeight.text!) ?? 1.0, beadJointSize: Double(bedJointSize.text!) ?? 1.0)
heightCutResult.text = String("(result) mm")
// Popup alert
if result < 30.5 {
// First instantiate the UIAlertController
let alert = UIAlertController(title: "Small cut!", message: "Depending on conditions you may be able to gain or squeeze to eliminate this small cut.", preferredStyle: .alert)
// Add action buttons to it and attach handler functions if you want to
alert.addAction(UIAlertAction(title: "Got it!", style: .cancel, handler: nil))
// Show the alert by presenting it
self.present(alert, animated: true)
}
} else {
let result = cutCalc.imperialHeightCutCalc(overallHeight: Double(overallHeight.text!) ?? 1.0, unitHeight: Double(unitHeight.text!) ?? 1.0, beadJointSize: Double(bedJointSize.text!) ?? 1.0)
heightCutResult.text = String("(result) inches")
// Popup alert
if result.1 < 2.5 {
// First instantiate the UIAlertController
let alert = UIAlertController(title: "Small cut!", message: "Depending on conditions you may be able to gain or squeeze to eliminate this small cut.", preferredStyle: .alert)
// Add action buttons to it and attach handler functions if you want to
alert.addAction(UIAlertAction(title: "Got it!", style: .cancel, handler: nil))
// Show the alert by presenting it
self.present(alert, animated: true)
}
}
}
// Length cut calculator metric imperial selector- DONE
@IBAction func lengthUnitSelector(_ sender: UISegmentedControl) {
if (metricImperialLengthSelector.selectedSegmentIndex == 0) {
unitLengthMeasurement = true
} else {
unitLengthMeasurement = false
}
}
// Height cut calculator metric imperial selector- DONE
@IBAction func heightUnitSelector(_ sender: UISegmentedControl) {
if (metricImperialHeightSelector.selectedSegmentIndex == 0) {
unitHeightMeasurement = true
} else {
unitHeightMeasurement = false
}
}
// Acts to dismiss number keyboard when user taps outside
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
overallLength.resignFirstResponder()
unitLength.resignFirstResponder()
headJointSize.resignFirstResponder()
overallHeight.resignFirstResponder()
unitHeight.resignFirstResponder()
bedJointSize.resignFirstResponder()
}
}
Вот мой класс сохранения:
// Cut calculator saved states
static var overallLengthKey = "OverallLength"
static var unitLengthKey = "UnitLength"
static var headJointSizeKey = "HeadJointSize"
static var unitLengthSelector = "LengthUnitSelector"
static var overallHeightKey = "OverallHeight"
static var unitHeightKey = "UnitHeight"
static var bedJointSizeKey = "BedJointSize"
static var unitHeightSelector = "HeightUnitSelector"
// Saving user data
static func saveLengthCutCalcState(overallLength: Double, unitLength: Double, headJointSize: Double, measurementLengthSelector: Int) {
let defaults = UserDefaults.standard
defaults.set(overallLength, forKey: overallLengthKey)
defaults.set(unitLength, forKey: unitLengthKey)
defaults.set(headJointSize, forKey: headJointSizeKey)
defaults.set(measurementLengthSelector, forKey: unitLengthSelector)
defaults.synchronize()
}
// Saving user data
static func saveHeightCutCalcState(overallHeight: Double, unitHeight: Double, bedJointSize: Double, measurementHeightSelector: Int) {
let defaults = UserDefaults.standard
defaults.set(overallHeight, forKey: overallHeightKey)
defaults.set(unitHeight, forKey: unitHeightKey)
defaults.set(bedJointSize, forKey: bedJointSizeKey)
defaults.set(measurementHeightSelector, forKey: unitHeightSelector)
}
// Retrieve user data
static func retrieveCutCalcValue(key: String) -> Any? {
let defaults = UserDefaults.standard
defaults.synchronize()
return defaults.value(forKey: key)
}
// Clear state
static func clearLengthCutCalcState() {
let defaults = UserDefaults.standard
// Clear the saved state data in user defaults
defaults.removeObject(forKey: overallLengthKey)
defaults.removeObject(forKey: unitLengthKey)
defaults.removeObject(forKey: headJointSizeKey)
defaults.removeObject(forKey: unitLengthSelector)
}
static func clearHeightCutCalcState() {
let defaults = UserDefaults.standard
// Clear the saved state data in user defaults
defaults.removeObject(forKey: overallHeightKey)
defaults.removeObject(forKey: unitHeightKey)
defaults.removeObject(forKey: bedJointSizeKey)
defaults.removeObject(forKey: unitHeightSelector)
}
// DONE- Even gauge calcualtor saved states -DONE