Swift - saveContext(), tableView, scrollView, and reloadRows



我有一个使用NSFetchedResultsController填充数据的tableView。单击单元格时,它会将您带到该对象的detailViewController。以下两个属性是用prepare(for:(推进的。

var coreDataStack: CoreDataStack!
var selectedGlaze: Glaze?

在detailView中,我有两个单元格。第一个是包含滚动视图和图像阵列的单元格:

import UIKit
protocol SwipedRecipeImageViewDelegate: class {
func recipeImageViewSwiped(_ cell: RecipePhotoTableViewCell, selectInt: Int)
}
class RecipePhotoTableViewCell: UITableViewCell, UIScrollViewDelegate {

@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var pageControl: UIPageControl!

// -

var imagesArray: [Data] = []
var selectedImageData: Int = 0

// -
weak var delegate: SwipedRecipeImageViewDelegate?
// -

override func awakeFromNib() {
super.awakeFromNib()
self.backgroundColor = .clear
self.selectionStyle = .none

scrollView.delegate = self

scrollView.isUserInteractionEnabled = false // Allows didSelectAtRow:
contentView.addGestureRecognizer(scrollView.panGestureRecognizer) // Allows Scrolling
}


override func layoutSubviews() {
super.layoutSubviews()
setImages()
setOffsetX(pageNumber: selectedImageData)
}


func configureCell(section: Int, row: Int, images: [RecipeImage], arrayInt: Int, delegate: SwipedRecipeImageViewDelegate) {
self.delegate = delegate

selectedImageData = arrayInt

for image in images {
guard let imageData = image.recipeImageData else { return }
imagesArray.append(imageData)
}
}


@IBAction func pageChanged(_ sender: UIPageControl) {
setOffsetX(pageNumber: sender.currentPage)
}

func setOffsetX(pageNumber: Int) {

pageControl.currentPage = pageNumber
let offsetX = contentView.bounds.width * CGFloat(pageNumber)
DispatchQueue.main.async {
UIView.animate(withDuration: 0.2, delay: 0, options: UIView.AnimationOptions.curveEaseOut, animations: {
self.scrollView.contentOffset.x = offsetX
}, completion: nil)
}

}


func setImages() {

// Set Page Count:
pageControl.numberOfPages = imagesArray.count
// Set Frame For ImageViews + Scroll View:
for index in 0..<imagesArray.count {
let imageView = UIImageView()
imageView.frame.size = contentView.bounds.size
imageView.frame.origin.x = contentView.bounds.width * CGFloat(index)
imageView.image = UIImage(data: imagesArray[index])
imageView.contentMode = .scaleAspectFill
imageView.layer.masksToBounds = true // Limits Frame Size

scrollView.addSubview(imageView)
}

// Set ScrollView Size:
scrollView.contentSize = CGSize(width: (contentView.bounds.width * CGFloat(imagesArray.count)), height: contentView.bounds.height)
scrollView.delegate = self
}

// Set Page Number:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageNumber = scrollView.contentOffset.x / scrollView.frame.size.width
self.pageControl.currentPage = Int(pageNumber)
delegate?.recipeImageViewSwiped(self, selectInt: pageControl.currentPage)
}

第二个单元格包含带有一些标签的stackView,用于显示图像显示的数据。它接受许多参数,然后设置textColor并更改一些标签。没有什么太令人兴奋的,所以我没有包括代码。

DetailViewController:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print("cellForRowAt: ", indexPath)
switch indexPath.section {
case sectionImage:  // Section 0:
guard
let images = selectedGlaze?.glazeImage,
let glazeImageSelected = selectedGlaze?.glazeImageSelected // This is a Double
else { return returnDefaultCell() }

let imageArray = images.allObjects as! [RecipeImage] // Takes NSSet of relational data and changes it into an Array to be passed into the image cell.
let imageSelected = Int(glazeImageSelected) // Double Converted to Int

switch indexPath.row {
case 0:
let cell = returnRecipeImageCell()
return configureRecipeImageCell(cell: cell, for: indexPath, imagesArray: imageArray, imageSelected: imageSelected)

case 1:
let cell = returnAtmosphereCell()
return configureAtmosphereCell(cell: cell, for: indexPath, imagesArray: imageArray, imageSelected: imageSelected)

default: return returnDefaultCell()
}
}
}

SwipedRecipeImageViewDelegate:

func recipeImageViewSwiped(_ cell: RecipePhotoTableViewCell, selectInt: Int) {
selectedGlaze?.glazeImageSelected = Double(selectInt)
coreDataStack.saveContext()
DispatchQueue.main.async { // 
self.tableView.beginUpdates() //
let row1: IndexPath = [0,1] //
self.tableView.reloadRows(at: [row1], with: .automatic) //
self.tableView.endUpdates() //
}
}

问题:我遇到的问题是在调用recipeImageViewSwiped()后,重新加载第二个要用正确信息更新的单元格。此处显示:https://i.stack.imgur.com/LpyXs.jpg

DispatchQueue.main.async块内的代码处于活动状态时,会发生这种情况。当区块被注释掉时,会发生以下情况:https://i.stack.imgur.com/be4e2.jpg-这正是我所期望的。(除[0,1]处的单元格外,其他单元格未更新(。

具体来说,当tableView重新加载第[0,1]行时,cellForRowAt((只在该行[0,1]上被调用。但我不知道为什么[0,0]处的单元格和图像会弹回到scrollView中显示的原始图像。

目标:我的目标是让滚动视图的单元格在滑动后不会闪烁。但也要保存上下文,以便对象可以保存数组中选择的图像。然后用所选图像的新信息更新/重新加载第二个单元格,这样它就可以正确地更新标签。

编辑:

在layoutSubviews((中删除以下内容会产生以下影响:https://i.stack.imgur.com/8Vrdl.jpg-这看起来基本上是有效的。但仍然有一个奇怪的动画。

override func layoutSubviews() {
super.layoutSubviews()
setImages()
//        setOffsetX(pageNumber: selectedImageData)
}

编辑2:这看起来完全是设置单元格视图的问题。连同布局子视图。

编辑3:

我在layoutSubviews()内部添加了一个Bool: hasSetLayout和一个开关,它看起来像我想要的那样工作。-然而,如果任何人仍然有任何信息可以帮助我理解这个问题,我将不胜感激

var hasSetLayout = false
override func layoutSubviews() {
super.layoutSubviews()
switch hasSetLayout {
case false: setImages(selectedPhoto: selectedImageData)
default: break
}
}

尝试在没有动画的情况下重新加载行:

UIView.performWithoutAnimation {
tableView.reloadRows(at: [indexPath], with: .none)
}

最新更新