初回起動の処理でアラートに文字を入力して"OK"を押したらUserDefaultsに入力した文字を保存する処理にしたいのですが (= Thread 1: signal SIGABRT) と致命的なエラーになります。ブレーキングポイントなどでエラーになる場所を突き止めたのですが、なぜそのコードがエラーになるのかその原因がわかりません。どういったコードに変更したら良いでしょうか。
↓すると、スレッド1:シグナルSIGABRT //Thread 1: signal SIGABRT
コード
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var characterImage: UIImageView!
@IBOutlet weak var timerlabel: UILabel!
@IBOutlet weak var startButton: UIButton!
let fastTitleKey = UserDefaultsController.shard.fastTitleKey
override func viewDidLoad() {
super.viewDidLoad()
SkillModal.shared.relode()
SkillModal.shared.load()
if let myTitle = SkillModal.shared.fastSkill(){
self.title = myTitle.title
} else {
let alert = UIAlertController(title: "Title Name", message: "Please enter new name", preferredStyle: .alert)
alert.addTextField(configurationHandler: nil)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in
if let text = alert.textFields?[0].text {
self.title = text
SkillModal.shared.add(Skill(title: text, goalCount: 60 * 60 * 20))
SkillModal.shared.save() //ここで致命的なエラーになる
}
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
present(alert, animated: true, completion: nil)
}
startButton.layer.cornerRadius = 25.0
}
override func viewWillAppear(_ animated: Bool) {
guard let skill = SkillModal.shared.currentSkill else {
return
}
self.title = skill.title
timerlabel.text = secondsToGoalTimerLabel(skill.goalCount)
}
}
import Foundation
//「1つのセル」に捉われず、「1つのスキル」を表すデータがあればここに追加していく
struct Skill {
var title: String
var goalCount: Int
}
class SkillModal{
//アプリ全体で1インスタンスしかいらないならひたすらシングルトン!!
static let shared = SkillModal()
//このクラスはシングルトンとしてしかアクセスさせない
private init() { }
//配列としての`skills`を公開しておくと辻褄の合わない更新をしてしまう可能性があるのでprivateにする
private var skills: [Skill] = []
//`ViewController`側ではcurrentな要素を扱う
private var currentIndex: Int? = nil
//currentとなるindexを設定する
func setCurrentIndex(_ newIndex: Int) {
currentIndex = newIndex
}
//currentの要素を返す
var currentSkill: Skill? { //ここ分からない
if let index = currentIndex,skills.indices.contains(index) { //indicesて何?containsは指定された範囲内に含まれているか。ではindicesはコレクションを購読するのに有効なインデックス(昇順)とは?
return skills[index]
} else {
return nil
}
}
//一軒追加して、それをcurrentにする
func addAndSetCurrent(_ newSkill: Skill) {
currentIndex = skills.count
skills.append(newSkill) //もしかしてこれと上はコードの順番が逆??
}
func relode(){
if let skillArray = UserDefaults.standard.array(forKey: "skillArray") as? [Skill] {
skills = skillArray
}
}
//一件追加
func add(_ newSkill: Skill) {
skills.append(newSkill)
}
//一件削除
func remove(at index: Int) {
currentIndex = nil //current -= 1じゃ無いの??
skills.remove(at: index)
}
//`index`けんめんを取り出す
//`Skill`は値型なので、このメソッドの戻り値のプロパティを変更しても`skills`に反映されない
func skill(at index: Int) -> Skill {
return skills[index]
}
// ViewController の初回起動処理に使うメソッド
func fastSkill() -> Skill? {
if skills.indices.contains(0) {
return skills[0]
} else {
return nil
}
}
//プロパティを変更したい場合には、専用のメソッドを用意してそれを呼ぶ
//`index`件目の`goalCount`を変更する
func setGoalCount(_ newGoalCount: Int, at index: Int) {
skills[index].goalCount = newGoalCount
}
//要素を返す
var count: Int {
return skills.count
}
/********問題のコード↓**********/
func save() { //問題のコード
UserDefaults.standard.set(skill, forKey: "skillArray")
}
/*********問題のコード↑********/
func load() -> [Skill]? {
let userDefaultsSkill = UserDefaults.standard.array(forKey: "skillArray")
return userDefaultsSkill as? [Skill]
}
}