Post

Replies

Boosts

Views

Activity

Reply to Collection Reusable View Added Via Storyboard Not Registering with the Collection View
Thanks @BabyJ. I have updated my code to address the discrepancy which you've noted. My code now looks like this: ` let section = NSCollectionLayoutSection(group: group) let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(37.0)) let header = NSCollectionLayoutBoundarySupplementaryItem( layoutSize: headerSize, elementKind: ElementKind.sectionHeader.rawValue, alignment: .topLeading) section.boundarySupplementaryItems = [header] emotionFiltersDataSource.supplementaryViewProvider = { collectionView, kind, indexPath in guard let headerView = collectionView.dequeueReusableSupplementaryView( ofKind: ElementKind.sectionHeader.rawValue, withReuseIdentifier: "emotionFiltersHeaderReusableView", for: indexPath ) as? EmotionFiltersHeaderView else { fatalError("Could not dequeue header view as EmotionFiltersHeaderView") } let sectionTitle = Section.allCases[indexPath.section].rawValue headerView.sectionTitleLabel.text = sectionTitle return headerView } But I am still seeing the error. I had also selected the Section header accessory in the storyboard, but I've now deselected it when I tried using your suggestion and have gotten the same crash as before.
Topic: UI Frameworks SubTopic: UIKit
Jul ’25
Reply to Collection Reusable View Added Via Storyboard Not Registering with the Collection View
Apologies @BabyJ , I implemented the collectionView.register method which resulted in the cell dequeuing correctly, but my label in my header view was appearing nil which caused the application to crash. So I went back to your original answer and I updated the kind to UICollectionView.elementKindSectionHeader, and this worked, dequeuing the header successfully and supplying the label I added in storyboard in the reusable view. I believe that when implementing a collection reusable view in storyboard, I need to use UICollectionView.elementKindSectionHeader because this returns the object with the views in the storyboard.
Topic: UI Frameworks SubTopic: UIKit
Jul ’25
Reply to Cell Delegate Method Not Being Called
Thanks @Claude31 , per your comments, I have a function which is called repromtLLMForIconName which is in my EmotionExplorerCellDelegate protocol. When I call the method which is repromtLLMForIconName from my cell, this method is not called in my delegate which is my EmotionExplorerViewController. I have not checked that the delegate is not nil.
Topic: UI Frameworks SubTopic: UIKit
Jul ’25
Reply to Cell Delegate Method Not Being Called
Upon checking if the delegate is nil, the delegate is not nil. However, when I reattempted to run the app I ran into this issue: I am registering the cell using UICollectionView.CellRegistration in my view controller class and assigning cell.delegate = self inside this registration completion handler. My cell has a var delegate: EmotionExplorerCellDelegate? property, and inside the configure(iconName: String, title: String, red: CGFloat, green: CGFloat, blue: CGFloat) method in the cell is where I am calling delegate?.repromptLLMforIconName. Now it appears that my cell is nil inside my cell registration.
Topic: UI Frameworks SubTopic: UIKit
Jul ’25
Reply to Cell Delegate Method Not Being Called
This is my code: // UI View Controller Class class EmotionExplorerViewController: UIViewController, UINavigationControllerDelegate { func configureDataSource() { // Cell registration for main section let mainCellRegistration = UICollectionView.CellRegistration<EmotionExplorerCell, Item> { cell, indexPath, item in switch item { case .main(emotion: let emotion, icon: let iconName, red: let red, green: let green, blue: let blue): cell.delegate = self cell.index = indexPath.row print("collection view cell,", cell) cell.configure(iconName: iconName, title: emotion, red: red, green: green, blue: blue) case .title(title: _, buttonTitle: _): break case .filter(name: _): break case .skeleton: break } } } // Delegate method implementation extension EmotionExplorerViewController: EmotionExplorerCellDelegate { func repromptLLMForIconName(_ iconName: String, index: Int, emotion: String, red: CGFloat, green: CGFloat, blue: CGFloat) { guard let numberOfTries = geminiResponse?.numberOfTries, numberOfTries < 3 else { return } geminiResponse?.rempromptForIconName(iconName) { [self] emotions, error in if var item = dataSource.itemIdentifier(for: IndexPath(row: index, section: 3)) { var snapshot = dataSource.snapshot(for: .main) if let newEmotion = emotions?.first { var insertItem = Item.main(emotion: emotion, icon: newEmotion.sfSymbolName, red: red, green: green, blue: blue) snapshot.insert([insertItem], after: item) snapshot.delete([item]) dataSource.apply(snapshot, to: .main, animatingDifferences: true) } } } } } // UI Collection View Cell Class protocol EmotionExplorerCellDelegate { func repromptLLMForIconName(_ iconName: String, index: Int, emotion: String, red: CGFloat, green: CGFloat, blue: CGFloat) } class EmotionExplorerCell: UICollectionViewCell { var delegate: EmotionExplorerCellDelegate? var iconImageView: UIImageView! var titleLabel: UILabel! var index: Int! var emotion: String! var red: CGFloat! var green: CGFloat! var blue: CGFloat! override init(frame: CGRect) { super.init(frame: frame) configureCell() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func prepareForReuse() { super.prepareForReuse() iconImageView.image = nil titleLabel.text = nil contentView.backgroundColor = nil } private func configureCell() { iconImageView = UIImageView() iconImageView.contentMode = .scaleAspectFit iconImageView.tintColor = .black iconImageView.translatesAutoresizingMaskIntoConstraints = false titleLabel = UILabel() titleLabel.font = .systemFont(ofSize: 18, weight: .medium) titleLabel.textColor = .black titleLabel.translatesAutoresizingMaskIntoConstraints = false contentView.layer.cornerRadius = 7 contentView.layer.cornerCurve = .continuous contentView.clipsToBounds = true contentView.addSubview(iconImageView) contentView.addSubview(titleLabel) NSLayoutConstraint.activate([ iconImageView.centerXAnchor .constraint(equalTo: contentView.leadingAnchor, constant: 20), iconImageView.centerYAnchor .constraint(equalTo: contentView.centerYAnchor), titleLabel.leadingAnchor .constraint(equalTo: iconImageView.centerXAnchor, constant: 20), titleLabel.centerYAnchor .constraint(equalTo: contentView.centerYAnchor), titleLabel.trailingAnchor .constraint(lessThanOrEqualTo: contentView.trailingAnchor, constant: -16) ]) } func configure(iconName: String, title: String, red: CGFloat, green: CGFloat, blue: CGFloat) { if let image = UIImage(systemName: iconName) { iconImageView.image = image } else { print("delegate", delegate) delegate?.repromptLLMForIconName(iconName, index: index, emotion: emotion, red: red, green: green, blue: blue) } iconImageView.image = UIImage(systemName: iconName) titleLabel.text = title.capitalized let transformer = UIConfigurationColorTransformer.init { color in color.withProminence(.quaternary).withAlphaComponent(0.6) } let color = UIColor( red: red/255, green: green/255, blue: blue/255, alpha: 1 ) contentView.backgroundColor = transformer.callAsFunction(color) } }
Topic: UI Frameworks SubTopic: UIKit
Jul ’25
Reply to Cell Delegate Method Not Being Called
I have updated the cell registration to use UICollectionViewListCell and the accompanying configuration state API. // View Controller Class: class EmotionExplorerViewController: UIViewController, UINavigationControllerDelegate { override func viewDidLoad() { super.viewDidLoad() emotionExplorerCollectionView.collectionViewLayout = createLayout() configureDataSource() applyInitialSnapshot() emotionExplorerCollectionView.delegate = self geminiResponse = GeminiResponse() getGeminiResponse() } func configureDataSource() { let cellRegistration = UICollectionView.CellRegistration<EmotionExplorerCell, Item> { cell, indexPath, item in var contentConfiguration = cell.defaultContentConfiguration() var backgroundConfiguration = cell.defaultBackgroundConfiguration() switch item { case .main(emotion: let emotion, icon: let iconName, red: let red, green: let green, blue: let blue): print("emotion", emotion) contentConfiguration.text = emotion contentConfiguration.image = UIImage(systemName: iconName)?.withTintColor(.black) backgroundConfiguration.backgroundColorTransformer = UIConfigurationColorTransformer { color in return color.withAlphaComponent(0.10) } backgroundConfiguration.backgroundColor = backgroundConfiguration.backgroundColorTransformer?(UIColor(red: red/255, green: green/255, blue: blue/255, alpha: 1)) cell.contentConfiguration = contentConfiguration cell.backgroundConfiguration = backgroundConfiguration cell.delegate = self case .title, .filter: break case .skeleton: break } } } dataSource = UICollectionViewDiffableDataSource<Section, Item>( collectionView: emotionExplorerCollectionView ) { (collectionView, indexPath, item) -> UICollectionViewCell? in // Return the appropriate cell based on the item type switch item { case .title: return collectionView.dequeueConfiguredReusableCell( using: titleCellRegistration, for: indexPath, item: item ) case .main: return collectionView.dequeueConfiguredReusableCell( using: cellRegistration, for: indexPath, item: item ) case .filter: return collectionView.dequeueConfiguredReusableCell(using: filterCellRegistration, for: indexPath, item: item) case .skeleton: return collectionView.dequeueConfiguredReusableCell(using: skeletonCellRegistration, for: indexPath, item: item) } } } // UICollectionViewListCell protocol EmotionExplorerCellDelegate: AnyObject { func repromptLLMForIconName(_ iconName: String, index: Int, emotion: String, red: CGFloat, green: CGFloat, blue: CGFloat) } class EmotionExplorerCell: UICollectionViewListCell { weak var delegate: EmotionExplorerCellDelegate? var iconImageView: UIImageView! var titleLabel: UILabel! var rowIndex: Int! var emotion: String! var red: CGFloat! var green: CGFloat! var blue: CGFloat! override init(frame: CGRect) { super.init(frame: frame) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } }
Topic: UI Frameworks SubTopic: UIKit
Jul ’25
Reply to Cell Delegate Method Not Being Called
I ended up resolving this by setting cell.delegate = self in the dataSource handler where I connect the data source to my collection view in EmotionExplorerViewController. // Create diffable data source dataSource = UICollectionViewDiffableDataSource<Section, Item>( collectionView: emotionExplorerCollectionView ) { (collectionView, indexPath, item) -> UICollectionViewCell? in // Return the appropriate cell based on the item type switch item { case .title: return collectionView.dequeueConfiguredReusableCell( using: titleCellRegistration, for: indexPath, item: item ) case .main: let cell = collectionView.dequeueConfiguredReusableCell( using: mainCellRegistration, for: indexPath, item: item ) cell.delegate = self return cell case .filter: return collectionView.dequeueConfiguredReusableCell(using: filterCellRegistration, for: indexPath, item: item) case .skeleton: return collectionView.dequeueConfiguredReusableCell(using: skeletonCellRegistration, for: indexPath, item: item) } } I also reverted to using my old cell registration method since the content configuration API was a bit tricky to set up and customise.
Topic: UI Frameworks SubTopic: UIKit
Jul ’25
Reply to Trying to Connect an Outlet to a Gesture Recogniser in Storyboard
Hi @Claude31 , I have created the tap gesture in storyboard and added it to the view controller hierarchy by dragging the tap gesture onto the view controller. Here is the image of the attributes inspector in storyboard for the tap gesture: I did not control drag the tap gesture to the label in storyboard, rather I dragged the tap gesture and placed it directly on top of the label. How exactly do you try to connect ? Is it the label in storyboard or IBOutlet in code (you should not do it) ? Please clarify I control dragged from the tap gesture recogniser to the cell class where I dropped the label, and created the IBAction function called incrementNumberOfTaps when I did this: protocol TapLabelCollectionViewCellDelegate: AnyObject { func didTapLabel() } class TapLabelCollectionViewCell: UICollectionViewCell { @IBOutlet var taplabel: UILabel! var delegate: TapLabelCollectionViewCellDelegate? @IBAction func tapLabelAction(_ sender: Any) { } @IBAction func incrementNumberOfTaps(_ sender: UITapGestureRecognizer) { } } The circle next to the @IBAction now appears empty. What do you want to connect exactly in code ? You don't have to connect the tapGesture to the label IBOutlet in code. The connection is made in storybaord as explained before. I want to connect the gesture recogniser to the @IBAction func incrementNumberOfTaps function so I can call my delegate when I tap the label.
Topic: UI Frameworks SubTopic: UIKit Tags:
Jul ’25
Reply to Label I Added in Storyboard Appears nil when I try to Dequeue a Cell Using a Data Source Cell Provider
There is an extra part in my code: extension TapGridViewController: TapLabelCollectionViewCellDelegate { func incrementNumberOfTaps(index: Int) { cellItems[index].incrementLabelCount() var snapshot = NSDiffableDataSourceSnapshot<Section, CellItem>() snapshot.appendItems(cellItems) dataSource.apply(snapshot, animatingDifferences: true) } } I also moved the cell.delegate = self and the cell.index = indexPath.row to the Cell Registration handler, initially I thought I wasn't able to capture self in the cell registration handler, but upon checking again I can.
Topic: UI Frameworks SubTopic: UIKit Tags:
Jul ’25
Reply to Label I Added in Storyboard Appears nil when I try to Dequeue a Cell Using a Data Source Cell Provider
Hello, The steps I've gone through to add the label to the Interface Builder are as follows: I dragged the label to my UICollectionViewCell in storyboard. This is the outlet connection that is appearing in the identity inspector: I have added a breakpoint at line 53 setUpTapGestureRecognizer. This breakpoint gets called while the breakpoint at awakeFromNib() does not get called. I've also verified that the outlet in the code is connected to the label because the circle appears filled. Link to project: link.
Topic: UI Frameworks SubTopic: UIKit Tags:
Jul ’25
Reply to Label I Added in Storyboard Appears nil when I try to Dequeue a Cell Using a Data Source Cell Provider
I have implemented the incrementNumberOfTaps(index:) method in the extension of the TapGridViewController: extension TapGridViewController: TapLabelCollectionViewCellDelegate { func incrementNumberOfTaps(index: Int) { cellItems[index].incrementLabelCount() cellItems.append(CellItem(numberOfTaps: 0)) var snapshot = NSDiffableDataSourceSnapshot<Section, CellItem>() snapshot.appendSections([.main]) snapshot.appendItems(cellItems) dataSource.apply(snapshot, animatingDifferences: true) } } And the delegate is assigned in the TapGridViewController as well in the cell registration method: class TapGridViewController: UIViewController { func configureDataSource() { let cellRegistration = UICollectionView.CellRegistration<TapLabelCollectionViewCell, CellItem>(handler: { (cell: TapLabelCollectionViewCell, indexPath: IndexPath, item: CellItem) in cell.delegate = self //assigning the delegate of the cell here. cell.index = indexPath.row cell.numberOfTapsLabel.text = String(item.numberOfTaps) }) }
Topic: UI Frameworks SubTopic: UIKit Tags:
Jul ’25
Reply to Label I Added in Storyboard Appears nil when I try to Dequeue a Cell Using a Data Source Cell Provider
I have fixed this issue by removing the label from the storyboard and adding programmatically like so: protocol TapLabelCollectionViewCellDelegate: AnyObject { func incrementNumberOfTaps(index: Int) } class TapLabelCollectionViewCell: UICollectionViewCell { var numberOfTapsLabel: UILabel! var delegate: TapLabelCollectionViewCellDelegate? var index: Int! override init(frame: CGRect) { super.init(frame: frame) numberOfTapsLabel = UILabel() numberOfTapsLabel.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(numberOfTapsLabel) NSLayoutConstraint.activate([ numberOfTapsLabel.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), numberOfTapsLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor) ]) setUpTapGestureRecognizer() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func setUpTapGestureRecognizer() { let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(incrementNumberOfTaps)) print("numberOfTapsLabel", numberOfTapsLabel) numberOfTapsLabel.addGestureRecognizer(tapGestureRecognizer) numberOfTapsLabel.isUserInteractionEnabled = true } @objc func incrementNumberOfTaps() { delegate?.incrementNumberOfTaps(index: index) } }
Topic: UI Frameworks SubTopic: UIKit Tags:
Jul ’25