0

I am trying to storing struct values into array and same array I want to store it into User-default and retrieve to show tableview.

struct item:Codable {
    var title : String!
    var size : String!

    init(title: String, size: String) {
        self.title = title
        self.size = size
    }
}

I am using below method for storing

UserDefaults.standard.set(try? PropertyListEncoder().encode(items), forKey:"items")

And get it back

if let data = UserDefaults.standard.value(forKey:"items") as? Data {
   let items_user = try? PropertyListDecoder().decode(Array<item>.self, from: data)
   print("*************\(String(describing: items_user))")
}

But output getting

Optional([ZLib.item(title: Swift.ImplicitlyUnwrappedOptional<Swift.String>.some("con-smash.gsheet"), size: Swift.ImplicitlyUnwrappedOptional<Swift.String>.some("120 KB"))])

How to remove above optional and ZLib.item(, Swift.ImplicitlyUnwrappedOptional<Swift.String>.some( unnecessary info.

  • Related: [Swift 3 incorrect string interpolation with implicitly unwrapped Optionals](https://stackoverflow.com/questions/39537177/swift-3-incorrect-string-interpolation-with-implicitly-unwrapped-optionals). – Martin R Aug 15 '18 at 07:16

2 Answers2

3

First of all struct names are supposed to start with a capital letter

Just remove the exclamation marks in the struct.

Never declare members / properties as IUO if there is an initializer with non-optional values.

struct Item : Codable {
    var title : String
    var size : String

    init(title: String, size: String) {
        self.title = title
        self.size = size
    }
}

Second of all

Never use value(forKey with UserDefaults.

In this case there is a dedicated method data(forKey otherwise use object(forKey or other dedicated methods for scalars (integer(forKey, bool(forKey etc.). However this is not related to the issue.

if let data = UserDefaults.standard.data(forKey:"items") {

Finally catch always errors when using Codable and don't misuse the String(describing initializer

  do {
      let itemsUser = try PropertyListDecoder().decode(Array<Item>.self, from: data)
      print("*************", itemsUser)
  } catch { print(error) }
}

To get rid of the app name in a print statement adopt CustomStringConvertible and add your own description

struct Item : Codable, CustomStringConvertible {
    var title : String
    var size : String

    init(title: String, size: String) {
        self.title = title
        self.size = size
    }

    var description : String {
        return "title : \(title), size : \(size)"
    }
}
vadian
  • 274,689
  • 30
  • 353
  • 361
  • Brilliant answer! – gotnull Aug 15 '18 at 06:36
  • Wow Awesome. great explanation and answer. I learned from you. Thank you so much I will mark it and one more doubt I am getting [ZLib.Item(title: "con-smash.gsheet", size: "120 KB")] is it possible to remove ZLib? i think its app name @vadian –  Aug 15 '18 at 06:46
  • Great,Sorry to asking you again I am appending into table data array var items = [Item]() items.append(Item(title: filename, size: string)) is it possible to give items.append(itemsUser)? if i give I am getting Cannot convert value of type '[Item]' to expected argument type 'Item' @vadian –  Aug 15 '18 at 06:56
  • You can assign the array directly `items = itemsUser` or if you don't want to overwrite existing data `items.append(contentsOf:itemsUser)` – vadian Aug 15 '18 at 06:59
  • I am getting empty array by items.append(contentsOf:itemsUser) after append I am doing like let item = items[indexPath.row] ,cell.name_label_util.text = item.title in cell for index @vadian –  Aug 15 '18 at 07:03
  • Do you call `tableView.reloadData()` after the `append` line? You have to. And please no *snake_cased* variable names. According to the naming convention it should be `nameLabelUtil` – vadian Aug 15 '18 at 07:04
  • tableView.reloadData() yes I am doing but nothing cell showing in my tableview @vadian –  Aug 15 '18 at 07:06
  • If `print`ing `itemsUser` shows the data then the cause of the issue is somewhere else and beyond the scope of this question. – vadian Aug 15 '18 at 07:08
0

You can use "String" instead of "String!" to avoid "Swift.ImplicitlyUnwrappedOptional.some(" being printed.

try? means you will get an optional object so you get "Optional([ZLib.item(......"

you can try this:

do {
    let items_user = try PropertyListDecoder().decode(Array<item>.self, from: data)
} catch {
//error
}

or:

let items_user = try! PropertyListDecoder().decode(Array<item>.self, from: data)
Kang
  • 63
  • 6