在我的应用程序中有一个集合视图,当我到达最后一个项目时必须更新(在底部加载新帖子)。 我正在使用Alamofire获取新帖子。 此外,我的集合视图具有自定义布局。 奇怪的是:当应用程序第一次加载时,集合视图正确更新,我可以看到帖子的第一部分,但是当我滚动并调用方法来加载更多时,它会加载帖子,将其附加到数据源,但是集合视图即使我尝试在主队列上更新它,也无法获得更新。
我的代码:
FeedViewController.swift:
private let reuseIdentifier = "Cell"
class FeedViewController: UICollectionViewController {
var posts : [GPost] = []
var offsetForPosts = 0
let limitForPosts = 50
override func viewDidLoad() {
super.viewDidLoad()
if let layout = collectionView?.collectionViewLayout as? FeedLayout {
layout.delegate = self
}
self.collectionView?.registerNib(UINib(nibName: "GCell", bundle: nil), forCellWithReuseIdentifier: reuseIdentifier)
let initialPath : URLStringConvertible = "\(DEFAULT_PATH)api_key=\(API_KEY)&offset=\(offsetForPosts)&limit=\(self.limitForPosts)"
self.loadPostsForPath(initialPath) { (_posts) in
self.posts.appendContentsOf(_posts)
print(self.posts.count)
dispatch_async(dispatch_get_main_queue(), {
self.collectionView?.reloadData()
})
}
}
func loadPostsForPath(path: URLStringConvertible, completion: (posts: [GPost]) -> ()) {
Alamofire.request(.GET, path, parameters: nil, encoding: .JSON, headers: nil).responseJSON { (response) in
switch response.result {
case .Success(let data):
let JSONData = JSON(data)
var result = [GPost]()
for (_, value) in JSONData["data"] {
let post = GPost(id: value["id"].stringValue,
url: NSURL(string: value["images"]["fixed_width_downsampled"]["url"].stringValue)!,
slug: value["slug"].stringValue,
imageWidth: CGFloat(value["images"]["original"]["width"].floatValue),
imageHeight: CGFloat(value["images"]["original"]["height"].floatValue))
result.append(post)
}
completion(posts: result)
break
case .Failure(let error):
print("Error loading posts: \(error)")
break
}
}
}
override func collectionView(collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) {
if indexPath.item == posts.count - 10 {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), {
self.offsetForPosts += 50
let path : URLStringConvertible = "\(DEFAULT_PATH)api_key=\(API_KEY)&offset=\(self.offsetForPosts)&limit=\(self.limitForPosts)"
self.loadPostsForPath(path, completion: { (_posts) in
self.posts.appendContentsOf(_posts)
print(self.posts.count)
dispatch_async(dispatch_get_main_queue(), {
self.collectionView?.reloadData()
self.collectionView?.collectionViewLayout.invalidateLayout()
})
})
})
}
}
}
extension FeedViewController : FeedLayoutDelegate {
func collectionView(collectionView: UICollectionView, heightForPostAtIndexPath indexPath: NSIndexPath, withWidth width: CGFloat) -> CGFloat {
let post = posts[indexPath.item]
return width * post.getProportion() + 30
}
}
FeedLayout.swift:
protocol FeedLayoutDelegate {
func collectionView(collectionView: UICollectionView, heightForPostAtIndexPath indexPath: NSIndexPath, withWidth width: CGFloat) -> CGFloat
}
class FeedLayout: UICollectionViewLayout {
var delegate : FeedLayoutDelegate!
var numberOfColumns = 2
var cellPadding : CGFloat = 0.0
private var cache = [UICollectionViewLayoutAttributes]()
private var contentHeight : CGFloat = 0.0
private var contentWidth : CGFloat {
let insets = collectionView!.contentInset
return CGRectGetWidth(collectionView!.bounds) - (insets.left + insets.right)
}
override func prepareLayout() {
if cache.isEmpty {
let columnWidth = contentWidth / CGFloat(numberOfColumns)
var xOffset = [CGFloat]()
for column in 0..<numberOfColumns {
xOffset.append(CGFloat(column) * columnWidth)
}
var column = 0
var yOffset = [CGFloat](count: numberOfColumns, repeatedValue: 0)
for item in 0..<collectionView!.numberOfItemsInSection(0) {
let indexPath = NSIndexPath(forItem: item, inSection: 0)
let width = columnWidth - cellPadding * 2
let height = cellPadding + delegate.collectionView(collectionView!, heightForPostAtIndexPath: indexPath, withWidth: width) + cellPadding
let frame = CGRectMake(xOffset[column], yOffset[column], columnWidth, height)
let insetFrame = CGRectInset(frame, cellPadding, cellPadding)
let attributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath)
attributes.frame = insetFrame
cache.append(attributes)
contentHeight = max(contentHeight, CGRectGetMaxY(frame))
yOffset[column] = yOffset[column] + height
column = column >= (numberOfColumns - 1) ? 0 : column + 1
}
}
}
override func collectionViewContentSize() -> CGSize {
return CGSizeMake(contentWidth, contentHeight)
}
override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var layoutAttributes = [UICollectionViewLayoutAttributes]()
for attributes in cache {
if CGRectIntersectsRect(attributes.frame, rect) {
layoutAttributes.append(attributes)
}
}
return layoutAttributes
}
}