I have a problem. When i tapping add item before editing/deleting for the first time i have following problem:Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value ||| In that part of my code:
override func finalLayoutAttributesForDisappearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
guard let attributes = super.finalLayoutAttributesForDisappearingItem(at: itemIndexPath),
deletedItems!.contains(itemIndexPath) else {
return nil
}
attributes.alpha = 0.5
attributes.transform = CGAffineTransform(scaleX: 0.15, y: 0.15)
attributes.zIndex = 5
return attributes
}
deletedItems!.contains(itemIndexPath) else
I just cant comprehend why this method called. Any suggestion?
My MainViewController:
import UIKit
class MainViewController: UICollectionViewController {
@IBOutlet private weak var addButton:UIBarButtonItem!
@IBOutlet private weak var deleteButton:UIBarButtonItem!
private let dataSource = DataSource()
override func viewDidLoad() {
super.viewDidLoad()
// Set up a 3-column Collection View
let width = view.frame.size.width / 3
let layout = collectionView?.collectionViewLayout as! UICollectionViewFlowLayout
layout.itemSize = CGSize(width:width, height:width)
layout.sectionHeadersPinToVisibleBounds = true
// Refresh control
let refresh = UIRefreshControl()
refresh.addTarget(self, action: #selector(self.refresh), for: UIControlEvents.valueChanged)
collectionView?.refreshControl = refresh
// Toolbar
navigationController?.isToolbarHidden = true
// Edit
navigationItem.leftBarButtonItem = editButtonItem
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "DetailSegue" {
if let dest = segue.destination as? DetailViewController {
dest.park = sender as? Park
}
}
}
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
addButton.isEnabled = !editing
collectionView?.allowsMultipleSelection = editing
if !editing {
navigationController?.isToolbarHidden = true
}
guard let indexes = collectionView?.indexPathsForVisibleItems else {
return
}
for index in indexes {
let cell = collectionView?.cellForItem(at: index) as! CollectionViewCell
cell.isEditing = editing
}
}
@IBAction func addItem() {
let index = dataSource.indexPathForNewRandomPark()
let layout = collectionView?.collectionViewLayout as! FlowLayout
layout.addedItem = index
collectionView?.insertItems(at: [index])
}
@objc func refresh() {
addItem()
collectionView?.refreshControl?.endRefreshing()
}
@IBAction func deleteSelected() {
if let selected = collectionView?.indexPathsForSelectedItems {
print(selected)
dataSource.deleteItemsAtIndexPaths(selected)
let layout = self.collectionView?.collectionViewLayout as! FlowLayout
layout.deletedItems = selected
selected.forEach({self.collectionView?.cellForItem(at: $0)?.isSelected = false})
collectionView?.deleteItems(at: selected)
navigationController?.isToolbarHidden = true
}
}
}
extension MainViewController {
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind:String, at indexPath: IndexPath) -> UICollectionReusableView {
let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "SectionHeader", for: indexPath) as! SectionHeader
let mySection = Section()
mySection.title = dataSource.titleForSectionAtIndexPath(indexPath)
mySection.count = dataSource.numberOfParksInSection(indexPath.section)
view.section = mySection
return view
}
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return dataSource.numberOfSections
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataSource.numberOfParksInSection(section)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell
cell.park = dataSource.parkForItemAtIndexPath(indexPath)
cell.isEditing = isEditing
cell.isSelected = false
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if !isEditing {
let park = dataSource.parkForItemAtIndexPath(indexPath)
performSegue(withIdentifier: "DetailSegue", sender: park)
} else {
let cell = self.collectionView?.cellForItem(at: indexPath) as! CollectionViewCell
cell.isSelected = !cell.isSelected
navigationController?.isToolbarHidden = false
}
}
override func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
if isEditing {
if let selected = collectionView.indexPathsForSelectedItems, selected.count == 0 {
navigationController?.isToolbarHidden = true
}
}
}
}
My flowLayout:
import UIKit
class FlowLayout: UICollectionViewFlowLayout {
var addedItem: IndexPath?
var deletedItems: [IndexPath]?
//add border to layout
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var result = [UICollectionViewLayoutAttributes]()
if let attributes = super.layoutAttributesForElements(in: rect){
for item in attributes {
let cellAttributes = item.copy() as! UICollectionViewLayoutAttributes
if item.representedElementKind == nil {
let frame = cellAttributes.frame
cellAttributes.frame = frame.insetBy(dx: 2.0, dy: 2.0)
}
result.append(cellAttributes)
}
}
return result
}
override func initialLayoutAttributesForAppearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
guard let attributes = super.initialLayoutAttributesForAppearingItem(at: itemIndexPath),
let added = addedItem,
added == itemIndexPath else {
return nil
}
//set new attributes
attributes.center = CGPoint(x: collectionView!.frame.width - 23.5, y: -24.5)
attributes.alpha = 1.0
attributes.transform = CGAffineTransform(scaleX: 0.15, y: 0.15)
attributes.zIndex = 5
return attributes
}
override func finalLayoutAttributesForDisappearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
guard let attributes = super.finalLayoutAttributesForDisappearingItem(at: itemIndexPath),
deletedItems!.contains(itemIndexPath) else {
return nil
}
attributes.alpha = 0.5
attributes.transform = CGAffineTransform(scaleX: 0.15, y: 0.15)
attributes.zIndex = 5
return attributes
}
}