実現したいこと&疑問点
TableViewにてtextFieldにtodoを入れ値を保存して遷移した後遷移した後のclassにtextViewを設けて一言書きてそちらも保存したいのですが、classが変わった場合、同じkey値は使えずに保存内容もtextArray(cellを入れている配列)とtextViewは別で保存しないといけないと思うのですが、可能ですか?
発生しているエラー
cellをtap時に発生します。
Swift
1Thread 1: Exception: "Attempt to insert non-property list object <UITextView: 0x7fe59a84da00; frame = (27 476; 361 255); text = ''; clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x60000045cb10>; layer = <CALayer: 0x600000a7ffc0>; contentOffset: {0, 0}; contentSize: {361, 247}; adjustedContentInset: {0, 0, 0, 0}> for key Key"
該当コード
ViewController
1 2var textArray = [String]() 3 4override func viewWillAppear(_ animated: Bool) { 5 super.viewWillAppear(animated) 6 7 navigationController?.isNavigationBarHidden = true 8 9 //値の読み込み 10 if (UserDefaults.standard.stringArray(forKey: "todo") != nil){ 11 textArray = UserDefaults.standard.stringArray(forKey: "todo")! 12 13 } 14 15 tableView.reloadData() 16 17 } 18 19func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 20 21 let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) 22 23 cell.selectionStyle = .none 24 cell.textLabel?.text = textArray[indexPath.row] 25 cell.imageView?.image = UIImage(named: "profile") 26 cell.textLabel?.textColor = .white 27 28 //値の保存 29 UserDefaults.standard.set(textArray, forKey: "todo") 30 31 return cell 32 33 } 34
NextViewController
1class NextViewController: UIViewController { 2 3 var todoString = String() 4 let userDefaults = UserDefaults.standard 5 6 @IBOutlet weak var textView: UITextView! 7 @IBOutlet weak var Todolabel: UILabel! 8 9 override func viewDidLoad() { 10 super.viewDidLoad() 11 12 // Do any additional setup after loading the view. 13 14 Todolabel.text = todoString 15 UserDefaults.standard.set(textView, forKey: "Key") 16 17 } 18 19 override func viewWillAppear(_ animated: Bool) { 20 super.viewWillAppear(animated) 21 22 navigationController?.isNavigationBarHidden = false 23 let val1 = UserDefaults.standard.object(forKey: "Key") 24 25 } 26
先日のご質問に、クラスを作ってそこでToDoのラベルの内容、およびToDoに対するコメントを記録し、違うビューに遷移しても利用できるためのヒントを書いていますが、それはご理解いただけたでしょうか。
また、UserDefautlsはどんなデータ型でも保存できるわけではなく、いわゆるプロパティリストと呼ばれている型以外は一工夫しないと保存できないこと、またその対策法も書いていますが、そちらもご理解いただけていますか。
https://teratail.com/questions/251610#reply-363530
今回起きている実行時エラーは、UITextView をUserDefaultsで保存しようとした際に出たエラーだと思います。エラーが出た場所は明記されていませんが、コードをみた限り
UserDefaults.standard.set(textView, forKey: "Key")
のところで発生した可能性が高いです。
このtextViewはプロパティリストとして挙げられているデータ型ではないため、保存するためには先日ご提示した回答の末尾にあるヒント(別回答で挙げたサンプルコード)を使って、保存するためのクラスを実装する必要があります。
また、UserDefaults に保存しなければいけないのは、textView (UITextViewのインスタンス)全てではなく、textView のプロパティである text だけで十分です。
いずれにしても、どの程度ご理解されているのか次第でコメントも変わりますので、私が先日つけたコメントを再度ご確認いただいて、どの程度理解されているのか教えていただければとおもいます(必要に応じて質問内容を修正するようにお願いします)。
クラスを作ってのLabelのtitleの保存は仕組みはわかるのですが、classを元々設けることによりそれが保存先として機能するということですか?
また別記事のUserDefautlsはNSObject, NSCodingが自分的にはよく分からないのでメソッドやインスタンスの理解が少し難しいのですが、classの中と外でプロパティとインスタンスを分けることによって保存内容を分けることができるということですか?
ちなみにエラーはAppDelegateの
class AppDelegate: UIResponder, UIApplicationDelegateで起こります。
> クラスを作ってのLabelのtitleの保存は仕組みはわかるのですが、classを元々設けることによりそれが保存先として機能するということですか?
クラス先がそのまま保存されるわけではありません。データの扱い方として「Todo名、詳細事項」の2つをセットにしたクラスを作った方が便利ですよ、という程度の話です。
Todo名の String型の配列、詳細事項のString型の配列それぞれを別のキー名でUserDefaultsに保存しても作れますが、今後他の要素もまとめて扱いたいとなると処理も煩雑になるので、この時点でクラスを一つつくり、ひとまとめにして保存しておいた方が見通しの良いプログラムになりますよ、という話です。
> また別記事のUserDefautlsはNSObject, NSCodingが自分的にはよく分からないのでメソッドやインスタンスの理解が少し難しいのですが、classの中と外でプロパティとインスタンスを分けることによって保存内容を分けることができるということですか?
プロパティリストと呼ばれているもの以外の任意のクラスを保存するためには、そのクラスがNSObjectを継承し、NSCodingに準拠する必要があります。それは、たとえば元の質問でやっているようなtextViewを保存する場合でも同じです。
https://developer.apple.com/documentation/foundation/userdefaults
> A default object must be a property list—that is, an instance of (or for collections, a combination > of instances of) NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. If you want to > store any other type of object, you should typically archive it to create an instance of NSData.
カスタムクラスで定義したイニシャライザの一つは、クラスの初期値を設定するために必要となるイニシャライザです。他のイニシャライザとメソッド一つは、とりあえずそういうものが必要だ、という認識でいいとおもいます(当然、自分が扱うデータによって書き換えは必要ですが)。
しかし、カスタムクラスを作り、それを保存することについて、まだ理解が難しいということであれば、Todo名で一つ、Todoの詳細で一つと、別々のキーでString型の配列を保存する方法の方が良いのかもしれません(管理は厄介になりますが、新しく覚えることはほぼないはずです)。
繰り返しになりますが、textView 全体をUserDefaultsに保存するとなるとひと工夫必要ですし、そもそもその必要はありません。保存する必要があるのは、textView で入力された文字列だけです。なので、素直にその値だけを保存するように考えてみてはいかがでしょうか。
> ちなみにエラーはAppDelegateの
class AppDelegate: UIResponder, UIApplicationDelegateで起こります。
遷移先の画面で textView を保存するようなサンプルを作ってみました。たしかに実行時エラーで落ちるのはAppDelegateの部分です。しかし、吐かれているエラーメッセージと追加した処理から考えると、ほぼ間違いなく textView をUserDefaults に保存している部分です。
ご返信ありがとうございます。ベストアンサーにしたいのですが回答に何か一言入れてもらえないでしょうか?
では、上記のコメントを回答として適切な形に修正して回答にします。
丁寧にご連絡いただきありがとうございます。
回答2件
あなたの回答
tips
プレビュー