无法在Collection View中显示App Delegate存储的数组数据
我正在开发一款Meme(表情包)生成器应用,该生成器以模态方式呈现,集成在Tab Bar View Controller中。第一个标签页通过Table View展示所有已保存的Meme,第二个标签页计划通过Collection View展示已保存的Meme。
Meme生成器功能正常,会将生成的Meme保存到App Delegate文件中的数组内(我知道这种做法有争议,但这是练习要求)。我尝试配置Collection View,但无法获取App Delegate中的Meme对象引用,且不清楚原因。
我的CollectionViewController代码如下:
import UIKit class CollectionViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource { @IBOutlet weak var collectionView: UICollectionView! var memes: [Meme]! { didSet { collectionView.reloadData() } } override func viewDidLoad() { super.viewDidLoad() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) let appDelegate = UIApplication.shared.delegate as! AppDelegate memes = appDelegate.memes } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return memes.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) cell.imageView.image = memes[indexPath].memedImage return cell } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { } }
该代码是基于可正常运行的Table View代码编写的,Table View代码如下:
import UIKit class TableViewMemesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { @IBOutlet weak var tableView: UITableView! var memes: [Meme]! { didSet { tableView.reloadData() } } override func viewDidLoad() { super.viewDidLoad() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) let appDelegate = UIApplication.shared.delegate as! AppDelegate memes = appDelegate.memes } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return memes.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") let meme = memes[indexPath.row] cell?.imageView?.image = meme.memedImage cell?.textLabel?.text = meme.topText return cell! } }
请问如何获取该数组数据,并在用户保存新Meme时在Collection View中显示?
让我们一步步解决你的问题:
1. 修复Collection View Cell的核心访问问题
首先看你cellForItemAt方法里的代码,这里有两个关键错误:
UICollectionViewCell默认没有imageView属性(这和UITableViewCell的默认配置不一样),你需要创建自定义Collection View Cell类来绑定图片控件。- 访问数组元素时用了
memes[indexPath],Collection View应该用indexPath.item(Table View才用row)。
先创建自定义Cell类:
import UIKit class MemeCollectionViewCell: UICollectionViewCell { @IBOutlet weak var memeImageView: UIImageView! }
然后在Storyboard中:
- 选中Collection View Cell,在Identity Inspector里设置Class为
MemeCollectionViewCell - 给Cell添加UIImageView,将其与
memeImageView的IBOutlet绑定
修改后的cellForItemAt方法:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! MemeCollectionViewCell let meme = memes[indexPath.item] cell.memeImageView.image = meme.memedImage return cell }
2. 确保安全获取AppDelegate的数组
你的viewWillAppear逻辑是对的,但可以加安全判断避免空数组或nil导致的崩溃:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) let appDelegate = UIApplication.shared.delegate as! AppDelegate memes = appDelegate.memes ?? [] }
同时修改numberOfItemsInSection方法,增加空值保护:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return memes?.count ?? 0 }
3. 实现保存新Meme时的实时更新
目前你的代码只有在标签页切换时才会刷新数据,想要在用户保存新Meme后立刻更新Collection View,有两种简单方案:
方案一:用NotificationCenter监听更新
在AppDelegate中,当新Meme被添加到数组时发送通知:
// 假设这是你保存Meme的方法 func saveMeme(_ newMeme: Meme) { memes.append(newMeme) NotificationCenter.default.post(name: NSNotification.Name("MemeAdded"), object: nil) }
然后在CollectionViewController中监听这个通知:
override func viewDidLoad() { super.viewDidLoad() // 注册通知监听 NotificationCenter.default.addObserver(self, selector: #selector(refreshMemes), name: NSNotification.Name("MemeAdded"), object: nil) } @objc private func refreshMemes() { let appDelegate = UIApplication.shared.delegate as! AppDelegate memes = appDelegate.memes ?? [] } // 记得在页面销毁时移除监听 deinit { NotificationCenter.default.removeObserver(self) }
方案二:在模态返回时刷新
如果Meme生成器是通过present弹出的,可将刷新逻辑移到viewDidAppear(模态返回时viewWillAppear可能不会触发):
override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) let appDelegate = UIApplication.shared.delegate as! AppDelegate memes = appDelegate.memes ?? [] }
总结
先解决自定义Cell的问题,这是当前代码无法正常显示的核心原因;再添加空值保护避免崩溃;最后选择合适的方式实现实时更新。这样你的Collection View就能正确获取AppDelegate中的Meme数组,并在保存新Meme时及时展示了。
内容的提问来源于stack exchange,提问作者Andrew Tuzson

