致命错误:尝试访问collectionView函数内的模型数组内容时,索引超出范围



我正在尝试加载用户信息并在ProfileViewController上显示。我从数据库中检索信息,并将它们附加到一组用户模型中。当我在loadUserInfo函数中打印数组的内容时,它会显示正确的信息,但当我试图在viewForSupplementaryElementOfKind函数中显示它们时,我会得到Index超出范围的错误。当我尝试打印内容时,它显示模型数组中没有任何内容。为了显示用户信息,我使用我制作的ProfileInfoHeaderCollectionReusableView。它使用了一个配置函数,我在其中传递用户对象,并显示用户的名字和姓氏以及他们的个人资料照片。信息应显示在ProfileInfoHeaderCollectionReusableView类中定义的标签和ImageView中。

final class ProfileViewController: UIViewController {

private var collectionView: UICollectionView?

private var database = Database.database().reference()

var models = [Userr]()

override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Profile"
view.backgroundColor = .white
configureNavigationBar()
loadUserInfo()
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.minimumLineSpacing = 1
layout.minimumInteritemSpacing = 1
layout.sectionInset = UIEdgeInsets(top: 0, left: 1, bottom: 0, right: 1)
let size = (view.width-4)/3
layout.itemSize = CGSize(width: size, height: size)
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)

//Cell
collectionView?.register(PhotoCollectionViewCell.self, forCellWithReuseIdentifier: PhotoCollectionViewCell.identifier)

// headers
collectionView?.register(ProfileInfoHeaderCollectionReusableView.self,
forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
withReuseIdentifier: ProfileInfoHeaderCollectionReusableView.identifier)
collectionView?.register(ProfileTabsCollectionReusableView.self,
forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
withReuseIdentifier: ProfileTabsCollectionReusableView.identifier)

collectionView?.delegate = self
collectionView?.dataSource = self
guard let collectionView = collectionView else {
return
}

view.addSubview(collectionView)

}

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
collectionView?.frame = view.bounds
}

private func loadUserInfo(){
let uid = Auth.auth().currentUser?.uid
print("UID for ProfileVc: ",uid!)
database.child("users").child(uid!).observeSingleEvent(of: .value, with: { (snapshot) in
// Get user value
if let value = snapshot.value as? [String: AnyObject] {
let username = value["username"] as? String ?? ""
let firstName = value["firstName"] as? String ?? ""
let lastName = value["lastName"] as? String ?? ""
let profilePic = value["profileImageUrl"] as! String
let user = Userr(username: username, firstName: firstName, lastName: lastName, profilePhoto: profilePic)
self.models.append(user)
}
print("models: ",self.models[0])
}) { (error) in
print(error.localizedDescription)
}
}

}
extension ProfileViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{

func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0 {
return 0
}
//  return userposts.count
return 30
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// let model = userPosts[indexPath.row]
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PhotoCollectionViewCell.identifier,
for: indexPath) as! PhotoCollectionViewCell
//cell.configure(with: model)
cell.configure(debug: "test")
return cell
}


func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {

guard kind == UICollectionView.elementKindSectionHeader else {
return UICollectionReusableView()
}

if indexPath.section == 1 {
// tabs header
let tabControlHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: ProfileTabsCollectionReusableView.identifier, for: indexPath) as! ProfileTabsCollectionReusableView
tabControlHeader.delegate = self
return tabControlHeader
}

let profileHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: ProfileInfoHeaderCollectionReusableView.identifier, for: indexPath) as! ProfileInfoHeaderCollectionReusableView
profileHeader.delegate = self
//let user = models[indexPath.row]
print("models content: ",self.models[0]) //here is the line that get fatal error
//profileHeader.configure(user: models[indexPath.row])// this is the configure function that is used to display the user information in a label and imageView
return profileHeader
}



}

首先,设置集合视图的框架一次,最好是在loadView中,因为看起来您正在以编程方式构建视图——不要在viewDidLayoutSubviews中执行此操作(此方法调用得太晚,可能会调用多次(。

其次,您应该在viewWillAppear而不是viewDidLoad中尝试数据库调用,因为如果有同步返回(例如当数据库脱机操作时(,则集合视图可能不会显示数据。

第三,在解析数据库获取之后,您永远不会在这段代码中重新加载集合视图。集合视图如何知道如何显示数据?填充数组后,调用collectionView.reloadData()

第四,记住在每个方法中都要考虑集合视图委托中的部分,而不仅仅是返回单元格的地方。

final class ProfileViewController: UIViewController  {
private var collectionView: UICollectionView?
private let database = Database.database().reference()
private var models = [Userr]()

/* You're doing this programmatically; therefore,
add subviews here. And don't call super on this
method. */
override func loadView() {
addCollectionView()
}

/* After you've loaded the view in loadView,
do any post work here (i.e. adding notification
observers, post-view configuration, etc. */
override func viewDidLoad() {
super.viewDidLoad() // do call super

}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
loadUserInfo()
}

private func addCollectionView() {
// configure collection view and then add to view here
}

private func loadUserInfo() {
guard let uid = Auth.auth().currentUser?.uid else {
return
}
database.child("users").child(uid).observeSingleEvent(of: .value, with: { (snapshot) in
if let value = snapshot.value as? [String: AnyObject] {
let username = value["username"] as? String ?? ""
let firstName = value["firstName"] as? String ?? ""
let lastName = value["lastName"] as? String ?? ""
let profilePic = value["profileImageUrl"] as! String
let user = Userr(username: username, firstName: firstName, lastName: lastName, profilePhoto: profilePic)

self.models.append(user)
self.collectionView?.reloadData()
}
}) { (error) in
print(error.localizedDescription)
}
}
}
extension ProfileViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
switch section {
case 0:
return 0

case 1:
return userposts.count
default:
return 0
}
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
switch indexPath.section {
case 1:
let model = userPosts[indexPath.row]
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PhotoCollectionViewCell.identifier, for: indexPath) as! PhotoCollectionViewCell

cell.configure(with: model)
return cell
default:
return UICollectionViewCell()
}
}

func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
guard kind == UICollectionView.elementKindSectionHeader else {
return UICollectionReusableView()
}
switch indexPath.section {
case 0:
let user = models[indexPath.row]
let profileHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: ProfileInfoHeaderCollectionReusableView.identifier, for: indexPath) as! ProfileInfoHeaderCollectionReusableView

profileHeader.delegate = self
profileHeader.configure(user: models[indexPath.row])
return profileHeader

case 1:
let tabControlHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: ProfileTabsCollectionReusableView.identifier, for: indexPath) as! ProfileTabsCollectionReusableView
tabControlHeader.delegate = self
return tabControlHeader
default:
return UICollectionReusableView()
}
}
}

最新更新