调用 `reloadItems(at:)` 会导致程序崩溃
Posted
技术标签:
【中文标题】调用 `reloadItems(at:)` 会导致程序崩溃【英文标题】:Calling `reloadItems(at:)` causes program to crash 【发布时间】:2018-07-18 21:37:16 【问题描述】:我正在尝试创建一个程序,当用户在UITextField
中输入文本时,它会动态更新 collectoinView。下面是我为实现此目的而创建的扩展
我已根据您的建议更新了代码以包含插入和删除语句,我仍在重构和添加委托,但是虽然代码不会导致错误,但它不允许用户继续输入并关闭键盘我是否正确实现了所有内容
更新 #2(感谢您的所有帮助)
import UIKit
class ViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource, UICollectionViewDelegate, UISearchBarDelegate
lazy var collectionView : UICollectionView =
let layout = UICollectionViewFlowLayout()
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .white
cv.delegate = self
cv.dataSource = self
return cv
()
var genericTagsArray:[String] = ["tag1","tag2","tag3","tag4","tag5","tag6","tag7","tag8","tag9","tag10","tag11","tag12","A","B","C","D","E","F","G","Ab","Abc","za","tag1","tag2","tag3","tag4","tag5","tag6","tag7","tag8","tag9","tag10","tag11","tag12","A","B","C","D","E","F","G","Ab","Abc","za"]
var currentTagsArray:[String] = [String]()
didSet
collectionView.reloadData()
override func viewDidLoad()
super.viewDidLoad()
self.view.addSubview(collectionView)
collectionView.register(Cell.self, forCellWithReuseIdentifier: "cell")
collectionView.register(Header.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "header")
collectionView.anchor(top: view.safeAreaLayoutGuide.topAnchor, leading: self.view.leadingAnchor, bottom: self.view.bottomAnchor, trailing: self.view.trailingAnchor, padding: .init(top: 30, left: 0, bottom: 30, right: 0))
collectionView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
return currentTagsArray.count
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! Cell
cell.label.text = currentTagsArray[indexPath.item]
return cell
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView
let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "header", for: indexPath) as! Header
header.searchBar.delegate = self
return header
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize
return CGSize(width: collectionView.contentSize.width, height: 75)
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
return CGSize(width: self.view.frame.size.width, height: 50)
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat
return 5
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat
return 5
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
self.currentTagsArray = self.genericTagsArray.filter (text) -> Bool in
return text.contains(searchText.lowercased())
class Cell : UICollectionViewCell
let label = UILabel()
override init(frame: CGRect)
super.init(frame: frame)
setupViews()
required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
func setupViews()
self.backgroundColor = .gray
self.addSubview(label)
label.anchor(top: self.topAnchor, leading: self.leadingAnchor, bottom: self.bottomAnchor, trailing: self.trailingAnchor)
class Header: UICollectionReusableView
var searchBar = UISearchBar(frame: .zero)
override init(frame: CGRect)
super.init(frame: frame)
setupViews()
required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
func setupViews()
self.backgroundColor = .gray
self.addSubview(searchBar)
searchBar.anchor(top: self.topAnchor, leading: self.leadingAnchor, bottom: nil, trailing: self.trailingAnchor, padding: .init(top: 0, left: 5, bottom: 0, right: 5), size: .init(width: 0, height: 50))
extension UIView
func anchor(top: NSLayoutYAxisAnchor?, leading: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, trailing: NSLayoutXAxisAnchor?, padding: UIEdgeInsets = .zero, size: CGSize = .zero)
translatesAutoresizingMaskIntoConstraints = false
if let top = top
topAnchor.constraint(equalTo: top, constant: padding.top).isActive = true
if let leading = leading
leadingAnchor.constraint(equalTo: leading, constant: padding.left).isActive = true
if let bottom = bottom
bottomAnchor.constraint(equalTo: bottom, constant: -padding.bottom).isActive = true
if let trailing = trailing
trailingAnchor.constraint(equalTo: trailing, constant: -padding.right).isActive = true
if size.width != 0
widthAnchor.constraint(equalToConstant: size.width).isActive = true
if size.height != 0
heightAnchor.constraint(equalToConstant: size.height).isActive = true
通过编辑更新函数
@objc func textFieldDidChange()
guard(!(feedSearchBar.text?.isEmpty)!) else
VC.currentTagsArray = VC.genericTagsArray
VC.feedScreenCollectionView.reloadData()
return
VC.currentTagsArray = VC.genericTagsArray.filter(letter -> Bool in
if feedSearchBar.text!.count > letter.count
return false
let stringRange = letter.index(letter.startIndex, offsetBy: feedSearchBar.text!.count)
let subword = letter[..<stringRange]
return subword.lowercased().contains(feedSearchBar.text!.lowercased())
)
if VC.currentTagsArray.isEmpty
VC.feedScreenCollectionView.deleteItems()
VC.currentTagsArray.insert(feedSearchBar.text!, at: 0)
VC.feedScreenCollectionView.insertItems(at: [IndexPath(item: 0, section: 0)])
//VC.feedScreenCollectionView.reloadItems(inSection: 0)
// VC.feedScreenCollectionView.reloadItems(at: [IndexPath(item: 0, section: 0)])
//VC.feedScreenCollectionView.reloadData()
VC.feedScreenCollectionView.reloadItems(inSection: 0)
extension UICollectionView
func reloadItems(inSection section:Int = 0)
var indicies:[IndexPath] = [IndexPath]()
print("current number of items to reload \(self.numberOfItems(inSection: section))")
for i in 0..<self.numberOfItems(inSection: section)
indicies.append(IndexPath(item: i, section: section))
print("current item number: \(i)")
self.reloadItems(at: indicies)
// self.insertItems(at: indicies)
func deleteItems(inSection section:Int = 0)
var indicies:[IndexPath] = [IndexPath]()
for i in 0..<self.numberOfItems(inSection: section)
indicies.append(IndexPath(item: i, section: section))
self.deleteItems(at: indicies)
原始功能:
extension UICollectionView
func reloadItems(inSection section:Int = 0)
var indicies:[IndexPath] = [IndexPath]()
for i in 0..<self.numberOfItems(inSection: section)
indicies.append(IndexPath(item: i, section: section))
self.reloadItems(at: indicies)
但是,当我在编辑 textField 后调用此函数时,程序会因错误而崩溃
* -[UICollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:animator:] 中的断言失败,/BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3698.54.4/UICollectionView.m:5867 2018-07-18 16:28:02.226606-0400 FeedScreenReuseableView[87752:9704142] * 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“尝试将第 6 项插入第 0 部分,但只有 6 个更新后第0节中的项目'
我不确定如何解决这个问题。有没有更好的方法来重新加载不影响标题的单元格。提前感谢您的所有帮助。以下是该项目的完整代码。
import UIKit
class ViewController: UIViewController,UICollectionViewDelegateFlowLayout,UICollectionViewDelegate,UICollectionViewDataSource,printDelegateWorkedDelegate,updateCollectionView
func updateCollectionView()
self.feedScreenCollectionView.reloadData()
func printDelegateWorkedDelegate()
print("The delegate worked")
var genericTagsArray:[String] = ["tag1","tag2","tag3","tag4","tag5","tag6","tag7","tag8","tag9","tag10","tag11","tag12","A","B","C","D","E","F","G","Ab","Abc","za","tag1","tag2","tag3","tag4","tag5","tag6","tag7","tag8","tag9","tag10","tag11","tag12","A","B","C","D","E","F","G","Ab","Abc","za"]
var currentTagsArray:[String] = [String]()
var tagsSelected:[String] = [String]()
let keyboardSlider = KeyboardSlider()
var header:feedViewHeader = feedViewHeader()
@IBOutlet weak var feedScreenCollectionView: UICollectionView!
override func viewDidLoad()
super.viewDidLoad()
keyboardSlider.subscribeToKeyboardNotifications(view: view)
currentTagsArray = genericTagsArray
let viewTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(feedViewHeader.viewTapped(gestureRecognizer:)))
viewTapGestureRecognizer.cancelsTouchesInView = false
self.feedScreenCollectionView.addGestureRecognizer(viewTapGestureRecognizer)
feedScreenCollectionView.delegate = self
//
feedScreenCollectionView.dataSource = self
//
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 5, left: 1, bottom: 0, right: 1)
layout.minimumLineSpacing = 0
layout.headerReferenceSize = CGSize(width: 50, height: 75)
layout.sectionHeadersPinToVisibleBounds = true
feedScreenCollectionView.collectionViewLayout = layout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize
return CGSize(width: 50, height: 75)
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView
header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "feedViewHeader", for: indexPath) as! feedViewHeader
header.VC = self
return header
//
//Data Source
func numberOfSections(in collectionView: UICollectionView) -> Int
return 1
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
return currentTagsArray.count
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "feedViewCell", for: indexPath) as! feedViewCell
cell.feedImageView.backgroundColor = .blue
cell.feedImageView.clipsToBounds = true
cell.feedImageView.layer.cornerRadius = CGFloat((cell.feedImageView.frame.width)/5)
cell.feedLabel.text = currentTagsArray[indexPath.item]
return cell
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat
return 0
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat
return 0
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
let collectionViewWidth = collectionView.bounds.width/4.0
let collectionViewHeight = collectionViewWidth
return CGSize(width: collectionViewWidth-4, height: collectionViewHeight+25)
var lastContentOffset:CGFloat = 0
func scrollViewDidScroll(_ scrollView: UIScrollView)
if self.lastContentOffset > self.feedScreenCollectionView.contentOffset.y && self.feedScreenCollectionView.contentOffset.y > 0 && self.feedScreenCollectionView.contentOffset.y < self.feedScreenCollectionView.frame.maxY
self.lastContentOffset = scrollView.contentOffset.y
header.isHidden = false
else if (self.lastContentOffset < self.feedScreenCollectionView.contentOffset.y) && (self.feedScreenCollectionView.contentOffset.y < self.feedScreenCollectionView.frame.maxY) && (self.feedScreenCollectionView.contentOffset.y > 0)
print("you scrolled down,content offSet: \(scrollView.contentOffset.y)->\(self.feedScreenCollectionView.contentOffset.y)")
header.isHidden = true
else
self.lastContentOffset = scrollView.contentOffset.y
print("content offSet: \(scrollView.contentOffset.y)")
print("Nothing happened")
// self.headerDelegate?.hideHeaderView(hide: true)
override func viewWillAppear(_ animated: Bool)
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardFrameChangeNotification(notification:)), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
var offsetY:CGFloat = 0
@objc func keyboardFrameChangeNotification(notification: Notification)
class feedViewCell:UICollectionViewCell
@IBOutlet weak var feedImageView: UIImageView!
@IBOutlet weak var feedLabel: UILabel!
let keyboardSlider = KeyboardSlider()
override func awakeFromNib()
super.awakeFromNib()
feedLabel.translatesAutoresizingMaskIntoConstraints = false
feedImageView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
feedImageView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
feedImageView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
feedImageView.bottomAnchor.constraint(equalTo: self.feedLabel.topAnchor).isActive = true
feedImageView.translatesAutoresizingMaskIntoConstraints = false
feedLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
feedLabel.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
feedLabel.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
feedLabel.topAnchor.constraint(equalTo: self.feedImageView.bottomAnchor).isActive = true
feedLabel.textAlignment = .center
class feedViewHeader:UICollectionReusableView,UITextFieldDelegate,UICollectionViewDelegate
@IBOutlet weak var feedSearchBar: UITextField!
var delegateWorked:printDelegateWorkedDelegate?
var updateCV:updateCollectionView?
var VC:ViewController!
var collectionView:UICollectionView?
var stringToBeSet = "String to be set"
override func awakeFromNib()
super.awakeFromNib()
feedSearchBar.delegate = self
feedSearchBar.autocorrectionType = .no
feedSearchBar.keyboardType = .default
feedSearchBar.addTarget(self, action: #selector(feedViewHeader.textFieldDidChange), for: .editingChanged)
self.feedSearchBar.borderStyle = .roundedRect
self.feedSearchBar.layer.borderColor = UIColor.black.cgColor
self.feedSearchBar.layer.borderWidth = 4
var searchBarHeight = self.feedSearchBar.bounds.height
self.feedSearchBar.placeholder = "Tap To Search"
self.feedSearchBar.returnKeyType = .search
self.feedSearchBar.rightViewMode = .always
@objc func viewTapped(gestureRecognizer:UIGestureRecognizer)
if feedSearchBar.isFirstResponder
feedSearchBar.resignFirstResponder()
func textFieldShouldReturn(_ textField: UITextField) -> Bool
textField.resignFirstResponder()
VC.feedScreenCollectionView.reloadData()
//VC.feedScreenCollectionView.reloadSections([0])
return true
/// Helper to dismiss keyboard
@objc func didStopEditing()
func textFieldDidEndEditing(_ textField: UITextField)
UIView.setAnimationCurve(UIViewAnimationCurve.easeInOut)
UIView.animate(withDuration: 0.2)
self.VC.view.frame.origin.y = 0
@objc func textFieldDidChange()
guard(!(feedSearchBar.text?.isEmpty)!) else
VC.currentTagsArray = VC.genericTagsArray
VC.feedScreenCollectionView.reloadData()
return
VC.currentTagsArray = VC.genericTagsArray.filter(letter -> Bool in
if feedSearchBar.text!.count > letter.count
return false
let stringRange = letter.index(letter.startIndex, offsetBy: feedSearchBar.text!.count)
let subword = letter[..<stringRange]
return subword.lowercased().contains(feedSearchBar.text!.lowercased())
)
if VC.currentTagsArray.isEmpty
VC.currentTagsArray.insert(feedSearchBar.text!, at: 0)
VC.feedScreenCollectionView.reloadItems(inSection: 0)
extension Notification.Name
static let showKeyboard = Notification.Name("showKeyboard")
class KeyboardSlider: NSObject
// variables to hold and process information from the view using this class
weak var view: UIView?
@objc func keyboardWillShow(notification: NSNotification)
// method to move keyboard up
// view?.frame.origin.y = 0 - getKeyboardHeight(notification as Notification)
print("made it to keyboard will show")
func getKeyboardHeight(_ notification:Notification) -> CGFloat
// get exact height of keyboard on all devices and convert to float value to return for use
let userInfo = notification.userInfo
let keyboardSize = userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue
return keyboardSize.cgRectValue.height
func subscribeToKeyboardNotifications(view: UIView)
// assigning view to class' counterpart
self.view = view
// when UIKeyboardWillShow do keyboardWillShow function
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: .UIKeyboardWillShow, object: nil)
func unsubscribeFromKeyboardNotifications()
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
class blankView:UICollectionReusableView
extension UICollectionView
func reloadItems(inSection section:Int = 0)
print("made it to reload")
for i in 0..<self.numberOfItems(inSection: section)
self.reloadItems(at: [IndexPath(item: i, section: section)])
【问题讨论】:
您基本上有 一个 部分,其中包含多个项目,为什么不直接通过IBOutlet
调用 reloadData()
到您的收藏视图?我认为应该是self.feedScreenCollectionView.reloadData()
@AlejandroIván 感谢您的回复。我最初尝试过,但后来它与单元格一起重新加载标题。这会导致 textField 的键盘在用户仍在键入时关闭,因为在 @objc func textFieldDidChange() function
内部调用了 reloadData
。
如果你的UITextField
应该一直可见,我不会将它添加到集合的标题视图中,而是在它的同一级别(视图控制器上的另一个视图) .我不确定,但我认为您可以使用 let indexSet = IndexSet(integer: 0); self.feedScreenCollectionView.reloadSections(indexSet)
之类的东西来实现您想要做的事情。
【参考方案1】:
您正在向VC.currentTagsArray
添加一个新字符串,但您没有在集合视图上调用insertItems(at:)
,因此当numberOfItemsInSection
突然开始返回比以前更多的项目时,您会得到一致性异常。
关于风格的其他一些观察:
我会使用委托将事件传递回视图控制器,而不是让标题视图和单元格持有对 VC 的引用并紧密耦合对象。 变量VC
应该是vc
。大写首字母是一个类
就叫它currentTags
而不是currentTagsArray
【讨论】:
非常感谢您的回答,感谢您对样式和功能的反馈。作为一个新手,在功能和可读性方面改进代码风格一直是我在进行更大项目时一直在努力改进的事情。我经常发现 swift 有很多方法可以做某事我不确定哪种方法是正确的。 您添加 insertItems(at:) 的解决方案是有道理的,但是当我在currentTags.insert(at:)
正下方添加 insertItems(at: [IndexPath(item: 0, section: 0)])
时,我仍然遇到同样的错误。但是如果我在错误的地方实现这个功能,我仍然会遇到同样的错误。再次非常感谢您的所有帮助。
我收到的错误是这样的“'NSInternalInconsistencyException',原因:'无效更新:第0节中的项目数无效。更新后(1)必须包含在现有节中的项目数等于更新前该节中包含的项目数 (44),加上或减去从该节插入或删除的项目数(插入 1,删除 0),加上或减去移入或移出的项目数该部分(0 移入,0 移出)。'"
你需要看看为什么有 44 个项目,而现在只有 1 个。请记住,数组是 Swift 中的值类型,并且在修改时被复制,所以你可能正在做类似的事情。通过重构代码,让 onkynthe 视图控制器关注标签,您将能够简化代码并避免问题。
调用reloadItems
似乎也刷新了headerView 有没有办法让reloadItems
重新加载collectionView
的项目【参考方案2】:
您的问题是因为您只调用insertItemsAt
,它正是这样做的,插入了一个项目。您忘记了deleteItemsAt
,这应该会删除您不想再显示的所有项目。
顺便说一句,您真的应该考虑重构您的代码。它不容易阅读,而且事情没有在正确的地方完成。例如,您的标题永远不应该是负责更新您的收藏视图的人。您应该将其留给控制器本身并使用委托将文本从标题获取到视图控制器。
更新
这是为您进行搜索的完整代码。这只是一个示例,因此您可以了解它是如何完成的。
import UIKit
class ViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource, UICollectionViewDelegate, UISearchBarDelegate
lazy var collectionView : UICollectionView =
let layout = UICollectionViewFlowLayout()
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .white
cv.delegate = self
cv.dataSource = self
return cv
()
var genericTagsArray:[String] = ["tag1","tag2","tag3","tag4","tag5","tag6","tag7","tag8","tag9","tag10","tag11","tag12","A","B","C","D","E","F","G","Ab","Abc","za","tag1","tag2","tag3","tag4","tag5","tag6","tag7","tag8","tag9","tag10","tag11","tag12","A","B","C","D","E","F","G","Ab","Abc","za"]
var currentTagsArray:[String] = [String]()
didSet
collectionView.reloadSections(IndexSet.init(integer: 1))
override func viewDidLoad()
super.viewDidLoad()
self.view.addSubview(collectionView)
collectionView.register(Cell.self, forCellWithReuseIdentifier: "cell")
collectionView.register(Header.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "header")
collectionView.anchor(top: view.safeAreaLayoutGuide.topAnchor, leading: self.view.leadingAnchor, bottom: self.view.bottomAnchor, trailing: self.view.trailingAnchor, padding: .init(top: 0, left: 0, bottom: 0, right: 0))
collectionView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
if section == 0 return 0
return currentTagsArray.count
func numberOfSections(in collectionView: UICollectionView) -> Int
return 2
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView
let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "header", for: indexPath) as! Header
header.searchBar.delegate = self
return header
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize
if section == 0
return CGSize(width: self.view.frame.width, height: 50)
return CGSize()
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! Cell
cell.label.text = currentTagsArray[indexPath.item]
return cell
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
return CGSize(width: self.view.frame.size.width, height: 50)
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat
return 5
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat
return 5
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
self.currentTagsArray = self.genericTagsArray.filter (text) -> Bool in
return text.contains(searchText.lowercased())
class Cell : UICollectionViewCell
let label = UILabel()
override init(frame: CGRect)
super.init(frame: frame)
setupViews()
required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
func setupViews()
self.backgroundColor = .gray
self.addSubview(label)
label.anchor(top: self.topAnchor, leading: self.leadingAnchor, bottom: self.bottomAnchor, trailing: self.trailingAnchor)
class Header : UICollectionViewCell
let searchBar = UISearchBar()
override init(frame: CGRect)
super.init(frame: frame)
setupViews()
required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
func setupViews()
self.backgroundColor = .gray
self.addSubview(searchBar)
searchBar.anchor(top: self.topAnchor, leading: self.leadingAnchor, bottom: self.bottomAnchor, trailing: self.trailingAnchor)
extension UIView
func anchor(top: NSLayoutYAxisAnchor?, leading: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, trailing: NSLayoutXAxisAnchor?, padding: UIEdgeInsets = .zero, size: CGSize = .zero)
translatesAutoresizingMaskIntoConstraints = false
if let top = top
topAnchor.constraint(equalTo: top, constant: padding.top).isActive = true
if let leading = leading
leadingAnchor.constraint(equalTo: leading, constant: padding.left).isActive = true
if let bottom = bottom
bottomAnchor.constraint(equalTo: bottom, constant: -padding.bottom).isActive = true
if let trailing = trailing
trailingAnchor.constraint(equalTo: trailing, constant: -padding.right).isActive = true
if size.width != 0
widthAnchor.constraint(equalToConstant: size.width).isActive = true
if size.height != 0
heightAnchor.constraint(equalToConstant: size.height).isActive = true
【讨论】:
感谢您的帮助,很抱歉代码有点乱。我不太确定如何将 textField 中的文本和 collectionView 的数据源结合起来。谢谢你通读这一切。我尝试在数组插入后立即进行插入,我不确定这是否是正确的放置位置,我应该在插入数组和插入之前删除所有单元格吗? 似乎当我在执行删除和插入项目后调用reloadItems(at: )
时,标题会重新加载,同时会从 textField 折叠键盘并强制用户点击 textField 以继续输入。有没有办法使用reloadItems(at: )
重新加载项目而不重新加载标题?
你能用你的新代码更新你的问题吗?所以我们可以看到你在哪里以及如何做。
感谢您的所有帮助我已经添加了包含deleteItems()
、insertItems(at:)
的修改函数和修改后的 UICollectionView 扩展
问题是我真的不明白你为什么要尝试做这么复杂的事情。您可以使用其他几个选项来创建搜索。查看我的编辑。以上是关于调用 `reloadItems(at:)` 会导致程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章
与 collectionView.reloadItems[at: [indexPath]] 重叠标签值
Swift -collectionView 单元格内的属性在 collectionView.performBatchUpdates > reloadItems(at:) 运行后没有更新
iOS解决UICollectionView中使用reloadItemsAtIndexPaths进行局部cell更新导致视图重叠问题
Swift - UICollectionView reloadItems 需要太长时间