我正在collectionview单元格中实现Favorite功能。用户应该点击单元格中的收藏夹按钮来保存项目。但是,当点击按钮保存填充单元格的自定义对象中的数据时,只保存一个对象。如果我点击收藏另一个项目,该项目将替换前一个,而不是添加到收藏数组中。想知道我在这里错过了什么。。
这是代码:
自定义对象(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)
}
}
查看控制器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)
}
试试这个:
- 创建一个检索已保存实体的函数
- 如果没有保存的实体,请保存实体数组,即[实体]
- 否则将新实体附加到已保存的实体
问题:
您已经在MediaCollectionViewCell
中创建了favoritesArray
。每次重复使用cell
时,favoritesArray
都会被重新初始化,即之前添加的entity
将丢失。
这就是为什么你总是在里面找到一个entity
,以及那个特定的cell
。
解决方案:
不要在单元格内创建额外的favoritesArray
,而是尝试使用closure
来保存喜爱的实体。以下是您可以遵循的方法。
1。首先使用class
而不是struct
,并在Entity
模型中添加isFavourite
属性,即
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"
}
}
注意:需要在Entity
模型中创建init(from:)
。在有任何特殊处理时使用。
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
以更新entity
的isFavourite
状态,然后将所有具有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
}