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

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

ただいまの
回答率

87.79%

Userdefaultsを違うclassで使う方法

解決済

回答 2

投稿

  • 評価
  • クリップ 1
  • VIEW 644

score 39

実現したいこと&疑問点

TableViewにてtextFieldにtodoを入れ値を保存して遷移した後遷移した後のclassにtextViewを設けて一言書きてそちらも保存したいのですが、classが変わった場合、同じkey値は使えずに保存内容もtextArray(cellを入れている配列)とtextViewは別で保存しないといけないと思うのですが、可能ですか?

発生しているエラー

cellをtap時に発生します。

Thread 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"

該当コード

var textArray = [String]()

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        navigationController?.isNavigationBarHidden = true

        //値の読み込み   
        if (UserDefaults.standard.stringArray(forKey: "todo") != nil){
            textArray = UserDefaults.standard.stringArray(forKey: "todo")!

        }

        tableView.reloadData()

    }

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)

        cell.selectionStyle = .none
        cell.textLabel?.text = textArray[indexPath.row]
        cell.imageView?.image = UIImage(named: "profile")
        cell.textLabel?.textColor = .white

        //値の保存
        UserDefaults.standard.set(textArray, forKey: "todo")

        return cell

    }
class NextViewController: UIViewController {

    var todoString = String()
    let userDefaults = UserDefaults.standard

    @IBOutlet weak var textView: UITextView!
    @IBOutlet weak var Todolabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.

        Todolabel.text = todoString
        UserDefaults.standard.set(textView, forKey: "Key")

    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        navigationController?.isNavigationBarHidden = false
        let val1 = UserDefaults.standard.object(forKey: "Key")

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • TsukubaDepot

    2020/04/08 11:43

    > クラスを作っての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 に保存している部分です。

    キャンセル

  • Ytan

    2020/04/10 15:59

    ご返信ありがとうございます。ベストアンサーにしたいのですが回答に何か一言入れてもらえないでしょうか?

    キャンセル

  • TsukubaDepot

    2020/04/10 16:13

    では、上記のコメントを回答として適切な形に修正して回答にします。
    丁寧にご連絡いただきありがとうございます。

    キャンセル

回答 2

checkベストアンサー

0

クラス先がそのまま保存されるわけではありません。今後アプリを発展させることを考えると、データの扱い方として「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.

ちなみに、カスタムクラス(正確にはプロパティリスト)以外のクラスをUserDefaultsに保存するためには、さらにひと工夫必要です。

具体的な例は過去の回答の後半に例がありますので、そちらも参考にしてみてください。

カスタムクラスで定義したイニシャライザの一つは、クラスの初期値を設定するために必要となるイニシャライザです。他のイニシャライザとメソッド一つは、とりあえずそういうものが必要だ、という認識でいいとおもいます(当然、自分が扱うデータによって書き換えは必要ですが)。

しかし、カスタムクラスを作り、それを保存することについて、まだ理解が難しいということであれば、Todo名で一つ、Todoの詳細で一つと、別々のキーでString型の配列を保存する方法の方が良いのかもしれません(管理は厄介になりますが、新しく覚えることはほぼないはずです)。

繰り返しになりますが、textView 全体をUserDefaultsに保存するとなるとひと工夫必要ですし、そもそもその必要はありません。保存する必要があるのは、textView で入力された文字列だけです。なので、素直にその値だけを保存するように考えてみてはいかがでしょうか。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 87.79%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る