-2

I have solved the issue now, thanks for your help. I shouldn't have tried to save arrays with UITextViews, but I should have saved their text as strings instead. Here was the original question:

I have tried a lot, and googled a lot, but I can't solve this problem on my own. Whenever I try to save an array in userdefaults, it just is not working. I get the following error:

Thread 1: "Attempt to insert non-property list object (\n "<UITextView: 0x14001f800; frame = (0 0; 355 180); text = 'D'; clipsToBounds = YES; gestureRecognizers = <NSArray: 0x600003f01d10>; layer = <CALayer: 0x6000031c83e0>; contentOffset: {0, 0}; contentSize: {355, 30}; adjustedContentInset: {0, 0, 0, 0}>"\n) for key content"

I don't know what a non-property list object is. And I do not know how to solve the problem. Below is the lines of code that do not work.

        var contentList: [Any] = []
        let cl = defaults.array(forKey: "content")!
        if cl.count != 0{
            contentList += cl
        }
        contentList.append(label)
        defaults.setValue(contentList, forKey: "content")

If I take out the last line of code by turning it into a comment everything runs just fine. How should I replace that line of code? I essentially want to save an array of UITextViews and make it larger every time I call a fucntion (this code is part of a larger function). The reason why I have created another two lists (cl and contentList) is that it helps me with a problem down the line. What I cannot understand however, is why the last line of code doesn't work. If anyone has any ideas, please help me, it would be much appreciated.

Gabriel
  • 37
  • 4
  • You should not store a TextView array at all, you should store the content (String) of your text views. – Joakim Danielson Sep 12 '21 at 11:48
  • 1
    _"I don't know what a non-property list object is"_, UserDefaults support strings, numbers, Date and Data objects out of the box so UITextView is not supported – Joakim Danielson Sep 12 '21 at 11:54
  • I did just that earlier (stored the text only). The problem with that is the following: I want to be able to make a bunch of textviews, that look like a feed. This means that the textviews would have to get their position updated every time a new textview enters the feed. They would have to move one step down. The reason why I wanted to create the array of textviews was to iterate over the array and change the position of each element. Do you have any idea on how to create a feed without doing what I am doing? – Gabriel Sep 12 '21 at 12:04
  • You can still iterate the array if it contains strings. As general advice, you should never store UI components but only the content (the data source) and also make sure you separate your business/app logic from your UI code – Joakim Danielson Sep 12 '21 at 12:15
  • Okay, so how would you create a feed, where the textviews move one step down each time a new one is added? – Gabriel Sep 12 '21 at 12:20
  • I have no idea and it's not relevant to this particular question – Joakim Danielson Sep 12 '21 at 12:21
  • 1
    Tack för tipsen – Gabriel Sep 12 '21 at 12:53

2 Answers2

1

Use only String as stated in comments :

    var contentList: [String] = []
    let cl = defaults.array(forKey: "content")!
    if cl.count != 0{
        contentList += cl
    }
    If lbText = label.text {
        contentList.append(lbText)
    defaults.setValue(contentList, forKey: "content")
 }
Ptit Xav
  • 3,006
  • 2
  • 6
  • 15
0

You can only store a very limited list of data types into UserDefaults, commonly referred to as "property list objects" (Since property list (or plist) files will only store the same data types.

To quote the Xcode docs on UserDefaults, in the section titled "Storing Default Objects":

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 [or Data, String, NSNumber, Date, Array, or Dictionary types in Swift.] If you want to store any other type of object, you should typically archive it to create an instance of Data.

(I added the equivalent Swift types to the above quote in square brackets, since it looks like Apple hasn't updated it for Swift.)

That's worded a little awkwardly. The idea is that you can only store data of the types listed. Because the Array and Dictionary types are "container" types, you can store any combination of arrays and dictionaries that contain combinations of any of the above types. For example, you can store an array that contains a dictionary, 3 dates, 2 floats, a Double, some Data, and 2 arrays, and those dictionaries and arrays can contain other dictionaries and/or arrays.)

It is almost always wrong to archive UIView objects like UITextViews. You should save the text properties of your text views instead.

If you want to manage a vertical stack of UITextView objects, I suggest adding a vertical stack view to your user interface, and then writing code that adds or removes UITextView subviews to your stack view. You should be able to find plenty of examples of adding and removing objects from stack views online. (It's really easy.)

If you want to manage a scrolling list of feeds of arbitrary length, you might want to use a table view or collection view instead. Those require that you set up a data model and implement a "data source". That takes a little practice to get right, but is very powerful.

Duncan C
  • 128,072
  • 22
  • 173
  • 272