Сохранение нескольких объектов с массивом userDefaults в TableViewCell - Swift 5 - PullRequest
0 голосов
/ 16 апреля 2020

Я реализую функцию Favorite внутри ячейки collectionview. Пользователь должен нажать любимую кнопку в ячейке, чтобы сохранить элемент. Однако при нажатии кнопки для сохранения данных из пользовательского объекта, который заполняет ячейку, сохраняется только один объект. Если я коснусь, чтобы добавить другой элемент в избранное, он заменяет предыдущий, а не добавляется в список избранных. Интересно, что мне здесь не хватает ..

Вот код:

Пользовательский объект (Entity.swift)

struct MediaObject: Codable {
  let name: String
  var results: [Entity]
}

struct Entity: Codable {

var id: Int? 
var name: String? 
var kind: String?
var artwork: String? 
var genre: String? 
var artist: String? 

  private enum CodingKeys: String, CodingKey {

           case id = "trackId"
           case name = "trackName"
           case kind = "kind"
           case artwork = "artworkUrl100"
           case genre = "primaryGenreName"
           case artist = "artistName"
       }


  init(from decoder: Decoder) throws {
    let values = try decoder.container(keyedBy: CodingKeys.self)
    id = try values.decodeIfPresent(Int.self, forKey: .id)
    name = try values.decodeIfPresent(String.self, forKey: .name)
    kind = try values.decodeIfPresent(String.self, forKey: .kind)
    artwork = try values.decodeIfPresent(String.self, forKey: .artwork)
    genre = try values.decodeIfPresent(String.self, forKey: .genre)
    artist = try values.decodeIfPresent(String.self, forKey: .artist)

  }

}

View Controller.swift

class MediaViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {


 var obj:MediaObject? = nil {
     didSet {
         collectionView.reloadData()
     }
 }


  @IBOutlet weak var collectionView: UICollectionView!
  @IBOutlet weak var sectionLabel: UILabel!

  override func awakeFromNib() {
    super.awakeFromNib()
    // Initialization code

      if let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
      flowLayout.estimatedItemSize = CGSize(width: 100, height: 90)
    }
}


  func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

    return obj!.results.count   
  }

  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MediaCollectionViewCell

    if let obj = obj {
      cell.entity = obj.results[indexPath.row]
      cell.artistLabel.text = obj.results[indexPath.row].artist
      cell.trackLabel.text = obj.results[indexPath.row].name
    }

    return cell
  }



  func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

    return CGSize(width: 250, height: 205)
  }

}

А вот мой класс MediaCollectionViewCell.swift:

MediaCollectionViewCell: UICollectionViewCell {


  @IBOutlet weak var artistLabel: UILabel!
  @IBOutlet weak var trackLabel: UILabel!
  @IBOutlet weak var imageView: UIImageView!
  @IBOutlet weak var favButton: UIButton!

  var favoritesArray = [Entity]()

  var entity:Entity? = nil {
    didSet {
      if let entity = entity,
        let artworkUrl = NSURL(string: entity.artwork!) {
        self.imageView.sd_setImage(with: artworkUrl as URL)
      }
    }
  }


  @IBAction func favButtonPressed(_ sender: Any) {

    print("isFavorited")
  let encoder = JSONEncoder()
         if let encoded = try? encoder.encode([entity]) {
                  let defaults = UserDefaults.standard
                  defaults.set(encoded, forKey: "entity")
              }

let defaultsData = UserDefaults.standard.data(forKey: "entity")

    let decoder = JSONDecoder()
    let loadedPerson = try? decoder.decode(Entity.self, from: defaultsData!) 

favoritesArray.append(loadedPerson)
print(loadedPerson)

print(loadedPerson?.count)


}

Ответы [ 2 ]

0 голосов
/ 16 апреля 2020

Проблема:

Вы создали favoritesArray внутри MediaCollectionViewCell. Каждый раз, когда cell используется повторно, favoritesArray будет повторно инициализирован, т.е. добавленный ранее entity будет потерян.

Вот почему вы всегда находите внутри него один entity и тот же самый cell.

Решение:

Вместо создания дополнительного favoritesArray внутри ячейки, попробуйте использовать closure, чтобы сохранить избранные объекты. Вот подход, которому вы можете следовать.

1. Прежде всего используйте class вместо struct и добавьте свойство isFavourite внутри * Модель 1033 *, т.е.

class MediaObject: Codable {
    let name: String
    var results: [Entity]
}

class Entity: Codable {
    var id: Int?
    var name: String?
    var kind: String?
    var artwork: String?
    var genre: String?
    var artist: String?
    var isFavourite = false 

    enum CodingKeys: String, CodingKey {
        case id = "trackId"
        case name = "trackName"
        case kind = "kind"
        case artwork = "artworkUrl100"
        case genre = "primaryGenreName"
        case artist = "artistName"
    }
}

Примечание: Существует необходимость создания init(from:) внутри модели Entity. Используйте его, когда есть какая-то особая обработка.

2. Теперь внутри MediaCollectionViewCell создайте closure favouriteHandler и вызывайте его внутри favButtonPressed(_:) то есть

class MediaCollectionViewCell: UICollectionViewCell {
    //rest of the code...

    var favouriteHandler: (()->())?

    @IBAction func favButtonPressed(_ sender: Any) {
        print("isFavorited")
        self.favouriteHandler?()
    }
}

3. Далее, в collectionView(_:cellForItemAt:) установите favouriteHandler, чтобы обновить isFavourite статус entity, а затем сохраните все объекты с isFavourite = true в UserDefaults.

Используйте filter(_:), чтобы получить все избранные объекты.

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MediaCollectionViewCell
    if let entity = obj?.results[indexPath.row] {
        cell.entity = entity
        cell.artistLabel.text = entity.artist
        cell.trackLabel.text = entity.name

        cell.favouriteHandler = {[weak self] in //here...
            entity.isFavourite = !entity.isFavourite
            let favourites = self?.obj?.results.filter{ $0.isFavourite }
            let data = try? JSONEncoder().encode(favourites)
            UserDefaults.standard.set(data, forKey: "entity")
        }

    }
    return cell
}
0 голосов
/ 16 апреля 2020

Попробуйте:

  1. Создайте функцию, которая извлекает сохраненные сущности
  2. Если нет сохраненных сущностей, сохраните Массив сущностей , т. Е. [ Entity]
  3. Остальное Добавление нового объекта к уже сохраненному Entities
...