我的快速iOS应用程序出现问题:“由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'试图为无视图创建视图动画'”
有人可以在这里找到主要问题吗?谢谢!
背景:我正在使用Firebase,并试图将数据(从Firebase数据库)加载到UICollection视图。该问题正在解决从数据库检索数据的问题。
[问题在代码中的特定区域附近突出显示]
import Foundation
import UIKit
import Firebase
import ProgressHUD
class CollectionViewController : UICollectionViewController {
private var hiddenCells: [ExpandableCell] = []
private var expandedCell: ExpandableCell?
private var isStatusBarHidden = false
var posts = [Post]()
var fetchingMore = false
var endReached = false
let leadingScreensForBatching:CGFloat = 3.0
var refreshControl:UIRefreshControl!
var lastUploadedPostID:String?
var postsRef:DatabaseReference {
return Database.database().reference().child("posts")
}
var oldPostsQuery:DatabaseQuery {
var queryRef:DatabaseQuery
let lastPost = posts.last
if lastPost != nil {
let lastTimestamp = lastPost!.createdAt.timeIntervalSince1970 * 1000
queryRef = postsRef.queryOrdered(byChild: "timestamp").queryEnding(atValue: lastTimestamp)
} else {
queryRef = postsRef.queryOrdered(byChild: "timestamp")
}
return queryRef
}
var newPostsQuery:DatabaseQuery {
var queryRef:DatabaseQuery
let firstPost = posts.first
if firstPost != nil {
let firstTimestamp = firstPost!.createdAt.timeIntervalSince1970 * 1000
queryRef = postsRef.queryOrdered(byChild: "timestamp").queryStarting(atValue: firstTimestamp)
} else {
queryRef = postsRef.queryOrdered(byChild: "timestamp")
}
return queryRef
}
override var shouldAutorotate: Bool {
return false
}
override var prefersStatusBarHidden: Bool {
return isStatusBarHidden
}
override func viewDidLoad() {
super.viewDidLoad()
self.hideKeyboardWhenTappedAround()
collectionView.delegate = self
collectionView.dataSource = self
collectionView.reloadData()
refreshControl = UIRefreshControl()
if #available(iOS 12.0, *) {
collectionView.refreshControl = refreshControl
} else {
// Fallback on earlier versions
collectionView.addSubview(refreshControl)
}
beginBatchFetch()
}
// **** ISSUE AROUND HERE VVV **** //
func beginBatchFetch() {
fetchingMore = true
self.collectionView.reloadSections(IndexSet(integer: 0))
fetchPosts { newPosts in
self.posts.append(contentsOf: newPosts)
self.fetchingMore = false
self.endReached = newPosts.count == 0
UIView.performWithoutAnimation {
self.collectionView.reloadData()
self.listenForNewPosts()
}
}
}
var postListenerHandle:UInt?
func listenForNewPosts() {
guard !fetchingMore else { return }
// Avoiding duplicate listeners
stopListeningForNewPosts()
postListenerHandle = newPostsQuery.observe(.childAdded, with: { snapshot in
if snapshot.key != self.posts.first?.id,
let data = snapshot.value as? [String:Any],
let post = Post.parse(snapshot.key, data) {
self.stopListeningForNewPosts()
if snapshot.key == self.lastUploadedPostID {
self.handleRefresh()
self.lastUploadedPostID = nil
} else {
}
}
})
}
@objc func handleRefresh() {
print("Refresh!")
newPostsQuery.queryLimited(toFirst: 10).observeSingleEvent(of: .value, with: { snapshot in
var tempPosts = [Post]()
let firstPost = self.posts.first
for child in snapshot.children {
if let childSnapshot = child as? DataSnapshot,
let data = childSnapshot.value as? [String:Any],
let post = Post.parse(childSnapshot.key, data),
childSnapshot.key != firstPost?.id {
tempPosts.insert(post, at: 0)
}
}
self.posts.insert(contentsOf: tempPosts, at: 0)
let newIndexPaths = (0..<tempPosts.count).map { i in
return IndexPath(row: i, section: 0)
}
self.refreshControl?.endRefreshing()
self.collectionView.scrollToItem(at: IndexPath(row: 0, section: 0), at: [], animated: true)
self.collectionView.insertItems(at: newIndexPaths)
self.listenForNewPosts()
})
}
func stopListeningForNewPosts() {
if let handle = postListenerHandle {
newPostsQuery.removeObserver(withHandle: handle)
postListenerHandle = nil
}
}
func fetchPosts(completion:@escaping (_ posts:[Post])->()) {
oldPostsQuery.queryLimited(toLast: 20).observeSingleEvent(of: .value, with: { snapshot in
var tempPosts = [Post]()
let lastPost = self.posts.last
for child in snapshot.children {
if let childSnapshot = child as? DataSnapshot,
let data = childSnapshot.value as? [String:Any],
let post = Post.parse(childSnapshot.key, data),
childSnapshot.key != lastPost?.id {
tempPosts.insert(post, at: 0)
}
}
return completion(tempPosts)
})
}
// **** ISSUE ABOVE HERE ^^^ **** //
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0:
return posts.count
case 1:
return fetchingMore ? 1 : 0
default:
return 0
}
}
// MARK: - UICollectionViewDelegates
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return posts.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ExpandableCell", for: indexPath) as! ExpandableCell
cell.set(post: posts[indexPath.row])
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView.contentOffset.y < 0 ||
collectionView.contentOffset.y > collectionView.contentSize.height - collectionView.frame.height {
return
}
let dampingRatio: CGFloat = 0.8
let initialVelocity: CGVector = CGVector.zero
let springParameters: UISpringTimingParameters = UISpringTimingParameters(dampingRatio: dampingRatio, initialVelocity: initialVelocity)
let animator = UIViewPropertyAnimator(duration: 0.5, timingParameters: springParameters)
self.view.isUserInteractionEnabled = false
if let selectedCell = expandedCell {
isStatusBarHidden = false
animator.addAnimations {
selectedCell.collapse()
for cell in self.hiddenCells {
cell.show()
}
}
animator.addCompletion { _ in
collectionView.isScrollEnabled = true
self.expandedCell = nil
self.hiddenCells.removeAll()
}
} else {
isStatusBarHidden = true
collectionView.isScrollEnabled = false
let selectedCell = collectionView.cellForItem(at: indexPath)! as! ExpandableCell
let frameOfSelectedCell = selectedCell.frame
expandedCell = selectedCell
hiddenCells = collectionView.visibleCells.map { $0 as! ExpandableCell }.filter { $0 != selectedCell }
animator.addAnimations {
selectedCell.expand(in: collectionView)
for cell in self.hiddenCells {
cell.hide(in: collectionView, frameOfSelectedCell: frameOfSelectedCell)
}
}
}
animator.addAnimations {
self.setNeedsStatusBarAppearanceUpdate()
}
animator.addCompletion { _ in
self.view.isUserInteractionEnabled = true
}
animator.startAnimation()
}
}