質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

2回答

2891閲覧

userDefaultsで保存した後に呼び出したが表示されない

AppDvl

総合スコア58

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2019/05/06 12:10

編集2019/05/09 14:23

前提・実現したいこと

永続化できていると思う(不安)のですが、
userDefaultsを呼び出してdateText.text!に代入しても表示されません。
何が悪いのかわからないので、解決策を教えていただければと思います。
10日前にプログラムを始めた初心者です。
丸一日いじくった挙げ句に降参ですがアプリ開発を諦めたくありません。
周りに質問できる者も居ないので、どなたかご教授お願いします。

発生している問題・エラーメッセージ

シミュレーターでアプリを立ち上げ直してもdateText.text!に表示されない。
エラーメッセージ
エラーメッセージは表示されていません。

試したこと

型が合わないのかもしれないのでオプショナル型を調べて試しました。
userDefaults.set(nil, forKey: "userText") //で永続データを一旦初期化してみましたが、解決しません。
「for文の中でdate.textに代入するとメモリをたくさん使う」外側に出しました。

補足情報(FW/ツールのバージョンなど)

xcode10.2.1
macはmacBookPro2012 retina

・・・・・・・・
追記

かなり長文になり、申し訳ありませんが下記の通りです。

追加して試したこと
detailsViewControllerのviewDidLoad()で
下記の通り記録する直前にprintを入れて見ました,デバックエリアに表示されています。

print("呼び出しuserTextは" + userDefaults.string(forKey: "userText")!) // テスト
dateText.text! = userDefaults.string(forKey: "userText")! //永続化呼び出し

アプリの目的
タイマーでスタートボタンを押した時間を記録して、スタートボタンを押した時間と回数を記録すること

おおまかな処理の流れは
1,class ViewControllerタイマーのスタートボタンを押した時間を記録して、
AppDelegateのstartDates配列に渡す。
2,AppDelegat
startDates配列の設置
3,detailsViewControllerでstartDates配列で一覧表を作成し表示する。
!!ここで躓いています!!
4,アプリを閉じても消えず、再起動したら続きから記録する。

デバックエリアの表示(これが”printの出力”のことでしょうか?言葉の意味もわからず、お恥ずかしいです。)

print出力を更新しました。\\\\\\\\

xcodeのシミュレーターを確認しながら
・・・まずViewControllerで2回スタートボタンを押しました。

呼び出しuserTextは1.19/05/09 23:12:19 Thu,
2.19/05/09 23:12:25 Thu,

ftTextは1.19/05/09 23:13:30 Thu,
2.19/05/09 23:13:33 Thu,

userTextは1.19/05/09 23:13:30 Thu,
2.19/05/09 23:13:33 Thu,

・・・次にdetailsViewControllerで時間が表示されていことを確認し、ViewControllerで1回スタートボタンを押しました。

呼び出しuserTextは1.19/05/09 23:13:30 Thu,
2.19/05/09 23:13:33 Thu,

ftTextは1.19/05/09 23:13:30 Thu,
2.19/05/09 23:13:33 Thu,
3.19/05/09 23:15:50 Thu,

userTextは1.19/05/09 23:13:30 Thu,
2.19/05/09 23:13:33 Thu,
3.19/05/09 23:15:50 Thu,

・・・ここでアプリを上書き&起動してdetailsViewControllerを表示。

呼び出しuserTextは1.19/05/09 23:13:30 Thu,
2.19/05/09 23:13:33 Thu,
3.19/05/09 23:15:50 Thu,

ftTextは
userTextは
・・・となっています。
しかし、シミュレーターの「@IBOutlet weak var dateText: UITextView!」は空白のままです。

swift

1AppDelegate.swift 2 3import UIKit 4 5var startDates = [Date]() //広域変数 6 7@UIApplicationMain 8class AppDelegate: UIResponder, UIApplicationDelegate { 9 10 var window: UIWindow? 11 12 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 13 // Override point for customization after application launch. 14 return true 15 } 16 17import UIKit 18ViewControllerファイル 19 20class ViewController: UIViewController { 21 22 var userTimer:Int = 0 23 var userSecTimer:Int = 0 24 var count = 0.0 25 var elapsedTime = 0.0 26 var timer = Timer() 27 var stopDate = Date() 28 var startDate = Date() 29 30 @IBOutlet weak var minButton: UIButton! 31 @IBOutlet weak var secButton: UIButton! 32 @IBOutlet weak var reset: UIButton! 33 @IBOutlet weak var startButton: UIButton! 34 @IBOutlet weak var stopButton: UIButton! 35 @IBOutlet weak var timerLabel: UILabel! 36 37 var secLabel:UILabel! 38 var msecLabel:UILabel! 39 40 41 override func viewDidLoad() { 42 super.viewDidLoad() 43 44 } 45 46 47 48 override func viewDidAppear(_ animated: Bool) { 49 super.viewDidAppear(animated) 50 if count == 0.0 { 51 setButtonEnabled(true, true, false, false, false) 52 }else if timer.isValid == false { //タイマーが止まっていたら 53 setButtonEnabled(false, false, true, false, true) 54 }else{ 55 setButtonEnabled(false, false, false, true, true) 56 } 57 } 58 59 60 //タイマーの処理 61 @objc func timerAction(sender:Timer){ 62 63 let minCount = Int(count)/60 64 let secCount = Int(count) % 60 65 let msecCount = Int((count - Double(minCount * 60) - Double(secCount)) * 100.0) 66 timerLabel.text = String(format:"%02d:%02d:%02d",minCount,secCount,msecCount)//%02dで整数を表示 67 68 count -= 0.1 69 70 if count <= 0.0{ 71 72 sender.invalidate() //止める 73 timerLabel.text = String(format:"%02d:%02d:%02d",0,0) 74 setButtonEnabled(true, true, false, false, false) 75 userTimer = 0 76 userSecTimer = 0 77 elapsedTime = 0 78 count = 0 79 } 80 } 81 func setButtonEnabled(_ minButton:Bool,_ secButton:Bool,_ startButton:Bool,_ stopButton:Bool,_ reset:Bool){ //bool型の変数をisEnabledに代入 82 self.minButton.isEnabled = minButton 83 self.secButton.isEnabled = secButton 84 self.startButton.isEnabled = startButton 85 self.stopButton.isEnabled = stopButton 86 self.reset.isEnabled = reset 87 } 88 89 } 90 91 @IBAction func minButton(_ sender: Any) { 92 setButtonEnabled(true, true, true, false, true) 93 userTimer += 1 94 timerLabel.text = String(format:"%02d:%02d:%02d",userTimer,userSecTimer) 95 96 } 97 98 @IBAction func secButton(_ sender: Any) { 99 setButtonEnabled(true, true, true, false, true) 100 101 userSecTimer += 10 102 timerLabel.text = String(format:"%02d:%02d:%02d",userTimer,userSecTimer) 103 } 104 105 @IBAction func startButton(_ sender: Any) { 106 setButtonEnabled(false,false,false,true,false) 107 108 109 stopDate=Date() 110 // 時間の差を計算する 111 let dateComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second, .nanosecond], from: startDate, to: stopDate) 112 113 if Int(dateComponents.second!) <= 2 { //2秒以内は配列に送らずにセットにカウントしない 114 115 }else{ 116 //広域配列startDatesに追加していく 117 startDates.append(Date()) 118 119 } 120 121 //タイマーの作成 122 func createTimer(){ 123 count = (Double(userTimer) * 60 + Double(userSecTimer) + elapsedTime) 124 125 self.timer = Timer.scheduledTimer(timeInterval: 0.1, 126 target: self, 127 selector: #selector(self.timerAction(sender:)), 128 userInfo: nil, 129 repeats: true) 130 } 131 createTimer() 132 } 133 134 @IBAction func stopButton(_ sender: Any) { 135 setButtonEnabled(false, false, true, false, true) 136 // setAdjustsImageWhenDisabled() 137 stopDate = Date() 138 139 userTimer = 0 140 userSecTimer = 0 141 elapsedTime = count 142 self.timer.invalidate()//止める 143 } 144 145 @IBAction func reset(_ sender: Any) { 146 setButtonEnabled(true, true, false, false, false) 147 // setAdjustsImageWhenDisabled() 148 userTimer = 0 149 userSecTimer = 0 150 elapsedTime = 0 151 count = 0 152 timerLabel.text = String(format:"%02d:%02d:%02d",userTimer,userSecTimer) 153 self.timer.invalidate()//止める 154 } 155 156 @IBAction func transitionButton(_ sender: Any) { 157 setButtonEnabled(false, false, false, true, true) 158 userTimer = 0 159 userSecTimer = 0 160 elapsedTime = count 161 162 } 163} 164 165・・・・ 166 167import UIKit 168detailsViewControllerファイル 169 170class detailsViewController: UIViewController { 171 let userDefaults = UserDefaults.standard//永続化のインスタンス 172 var btText:String = "" 173 var ftText:String = "" 174 var ttText:String = "" 175 @IBOutlet weak var dateText: UITextView! 176 @IBAction func backButton(_ sender: Any) { 177 self.dismiss(animated: true, completion: nil)//閉じる 178 } 179 180 var no = 1 181 var non = 0 182 var counts :Int = 0 183 var cnt :Int = 0 184 185 186 override func viewDidLoad() { 187 super.viewDidLoad() 188 189// userDefaults.set(nil, forKey: "userText") //永久データを一旦 初期化 190 191 if userDefaults.object(forKey: "userText") != nil{ 192// "userText"がnilでないときの処理hh 193 print("呼び出しuserTextは" + userDefaults.string(forKey: "userText")!) // テスト 194 dateText.text = userDefaults.string(forKey: "userText")! //永続化呼び出し 195 196 for _ in startDates { 197 let dateformatter = DateFormatter() 198 dateformatter.dateFormat = "yy/MM/dd HH:mm:ss E" 199 200 let startTime = dateformatter.string(from: startDates[counts]) 201 202 ftText = ftText + String( non + 1 ) + "." + startTime + String(",\n") 203 //順番大事dateText.text!に挿入されていくことに注意 204 205 counts += 1 206 non += 1 207 208 } 209 210 print("ftTextは" + "(ftText)") 211 userDefaults.set(ftText, forKey: "userText")//永続化で保存 212 213 dateText.text! = ftText 214 print("userTextは" + UserDefaults.standard.string(forKey: "userText")!) 215 216 217 }else{ 218// "userText"がnilのときの処理 219 220 for _ in startDates { 221 // staetDatesにデータ入っていれば処理する 222 223 if startDates.count > 0{ 224 let dateformatter = DateFormatter() 225 dateformatter.dateFormat = "yy/MM/dd HH:mm:ss E" 226 let startTime = dateformatter.string(from: startDates[counts]) 227 btText = btText + String( non + 1 ) + "." + startTime + String(",\n") //順番大事dateText.text!に挿入されていくことに注意 228 counts += 1 229 non += 1 230 } 231 } 232 userDefaults.set(btText, forKey: "userText")//永続化で保存 233 dateText.text! = btText 234 print("nilでbtTextは" + "(btText)") 235 } 236 237 } 238} 239

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fuzzball

2019/05/07 02:08

printの出力を書いて下さい。 現在の処理の流れがどうなっているのか、こちらは全く分かりません。
dsuzuki

2019/05/07 03:12

userDefaults.set(...)が実行されていることは確認していますか。 startDatesの定義がないので、for _ in startDates {...}内の処理が実行されているかもわからず。
AppDvl

2019/05/07 14:23 編集

質問の内容を更新しました。 detailsViewControllerのviewDidLoad()で 記録する直前にprintを入れて見ましたがデバックエリアに表示されています。 文字数制限があり、ViewControllerの内容は記載できませんでしたが、ViewControllerは想定した内容とおりに動いてと思われます。 下記にViewControllerのスタートボタンを押したときの内容を記載しました。 @IBAction func startButton(_ sender: Any) { stopDate=Date() // 第1引数は差分を表現する形式を指定します 時間の差を計算する let dateComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second, .nanosecond], from: startDate, to: stopDate) if Int(dateComponents.second!) <= 2 { //2秒以内は配列に送らずにセットにカウントしない }else{ //広域配列startDatesに追加していく startDates.append(Date()) }
fuzzball

2019/05/08 00:17

printの出力は書いてもらえないのでしょうか?
dsuzuki

2019/05/08 01:23

startDatesに対してDateを追加している処理がなく、配列のサイズが常にゼロの様に見えます。 従って、for _ in startDates {...}内の処理が実行されてない = userDefaults.set(...)が実行されていないように見えます。(追記に示されたコードは、"記録する直前"ではなく、"参照する直前"のコードです。) 「ViewControllerは想定した内容とおりに動いてと思われます。」の想定とはどのような動きでしょうか。 記載できていないソースコードがあるのでしたら、fuzzballさんが指摘しているように、実際にどの処理が実行されているかがわかるprintの出力結果を提示するのが早いと思います。
AppDvl

2019/05/08 10:51

printの出力とはxcodeのデバックエリアに表示される文字を指すのでしょうか? そうだと仮定して、デバックエリアの文字を質問の中に記入しました。 なんだか申し訳ないですが、よろしくお願いします。
fuzzball

2019/05/09 00:19

>>ここでアプリを再起動してdetailsViewControllerを表示しても空欄のままです このときのprintの出力を書いてもらえますか?
AppDvl

2019/05/09 11:01

再起動後のprint出力はxcodeとアプリの接続が切れているようで、デバックエリアに何も表示されませんでした。質問を重ねてしまいますが、再起動後のprint出力の方法があれば教えていただきたです。 他にできることがあればお申し付けください。
dsuzuki

2019/05/09 11:20

Mac OSのLaunchpad内に"コンソール"アプリがあります。これを利用すれば、USB接続しているiPhone/iPadで出力されるログが取得できます。 また、Xcodeから再度デバッグ実行(上書きインストール&実行)で事足りるかと。(アンインストールしない限り、UserDefautlsのデータは残ります。) もしかして、UserDefaultsの初期化処理が実装されてたりしますか?
AppDvl

2019/05/09 14:28

dsuzukiさんありがとうございます。 教えて頂いた方法で再起動ごのprinto出力ができました! こんな方法があったとは。 ネットで調べても出てこなかったので感心しました。
AppDvl

2019/05/09 21:30

UserDefaultsの初期化はテストで何度か行いましたが、最終的に実装していません。
guest

回答2

0

startDates[]を永続化して再び読み込むことで解決しました。
また、解決前のコードよりもスッキリして読み易くなりました。

投稿2019/05/11 04:49

AppDvl

総合スコア58

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

簡単に言うと、起動時にUserDefaultsから読み込んでいないことが原因です。

「dateTextの内容をstartDatesから生成」しているにも関わらず、起動時はstartDatesが空っぽなので、dateTextも空っぽです。

たぶん、

swift

1//detailsViewControllerのviewDidLoad() 2dateText.text = userDefaults.string(forKey: "userText")! //永続化呼び出し

ここで読み込んだ気になっているのだと思うのですが、その後で「dateTextの内容をstartDatesから生成」しているので、上記のコードは全く意味がありません。

投稿2019/05/10 00:44

fuzzball

総合スコア16731

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問