collectionviewcell pass data to relevant collectionview - ios

I am using collectionview. In this collectionview I have a button and I have 2 different cells in it which is 2 different collectionviewcell. When I press the button I need to get text from its second cells. the second cell is register cell which contains username, email and password fields.
Here is code snippets.
This is LoginController
class LoginController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDelegate, UICollectionViewDataSource {
******* I am taking of cell; If I do not do that then TextField returns nil *******
var registerController: RegisterControllerCell?
override func viewDidLoad() {
super.viewDidLoad()
UIApplication.shared.statusBarStyle = .lightContent
view.backgroundColor = UIColor.rgb(61, 91, 151)
******* and here is making cell is accessible *******
registerController = RegisterControllerCell()
setupComponents()
}
final func setupComponents() -> Void {
.... components set up here
}
******* this is the collectionview that should hold cells in it *******
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let view = UICollectionView(frame: .zero, collectionViewLayout: layout)
view.register(LoginControllerCell.self, forCellWithReuseIdentifier: loginCellId)
view.register(RegisterControllerCell.self, forCellWithReuseIdentifier: registerCellId)
view.translatesAutoresizingMaskIntoConstraints = false
view.bounces = false
view.showsHorizontalScrollIndicator = false
view.isPagingEnabled = true
view.layer.cornerRadius = 8
view.layer.masksToBounds = true
view.backgroundColor = .white
view.delegate = self
view.dataSource = self
return view
}()
#objc func hideKeyboard(){
self.view.endEditing(true)
}
********* HERE IS PROBLEM STARTS... this is the button that should return text of textfield when clicking occurs. *********
let rlButton: UIButton = {
let btn = UIButton()
btn.translatesAutoresizingMaskIntoConstraints = false
btn.setTitle("LOGIN", for: .normal)
btn.layer.cornerRadius = 5
btn.layer.masksToBounds = true
btn.backgroundColor = UIColor.brown
btn.addTarget(self, action: #selector(handleClick), for: .touchUpInside)
return btn
}()
#objc func handleClick(){
switch buttonState {
case .register?:
registerUser()
break
case .login?:
print("login")
break
case .none:
print("none of them")
break
}
}
********* here is should return the value *********
func registerUser() -> Void {
******** this should return a text but it is nil every time ********
let username = registerController?.username.text
print(username)
}
// collectionView stuff
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 2
}
// let colors: [UIColor] = [.black, .green]
let colors: [colorEnumerations] = [.white, .white]
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: loginCellId, for: indexPath) as? LoginControllerCell else {
fatalError("unresolved cell id")
}
if indexPath.item == 1 {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: registerCellId, for: indexPath) as? RegisterControllerCell else {
fatalError("unresolved cell id")
}
return cell
}
cell.backgroundColor = colors[indexPath.item].value
return cell
}
}
and this is the RegisterCell
class RegisterControllerCell: BaseCell {
override func setupComponents() {
registerComponents()
}
final func registerComponents() {
.... components set up
}
let holder: UIView = {
let vw = UIView()
vw.backgroundColor = .white
vw.translatesAutoresizingMaskIntoConstraints = false
return vw
}()
let seperator: UIView = {
let spr = UIView()
spr.translatesAutoresizingMaskIntoConstraints = false
spr.layer.borderWidth = 0.5
spr.layer.borderColor = UIColor.gray.cgColor
spr.backgroundColor = UIColor.gray
return spr
}()
let seperator2: UIView = {
let spr = UIView()
spr.translatesAutoresizingMaskIntoConstraints = false
spr.layer.borderWidth = 0.5
spr.layer.borderColor = UIColor.gray.cgColor
spr.backgroundColor = UIColor.gray
return spr
}()
let seperator3: UIView = {
let spr = UIView()
spr.translatesAutoresizingMaskIntoConstraints = false
spr.layer.borderWidth = 0.5
spr.layer.borderColor = UIColor.gray.cgColor
spr.backgroundColor = UIColor.gray
return spr
}()
******** I need to get its and others texts ********
let username: UITextField = {
let input = UITextField()
input.translatesAutoresizingMaskIntoConstraints = false
input.placeholder = "Username"
return input
}()
let email: UITextField = {
let input = UITextField()
input.translatesAutoresizingMaskIntoConstraints = false
input.placeholder = "Email"
return input
}()
let password: UITextField = {
let input = UITextField()
input.translatesAutoresizingMaskIntoConstraints = false
input.placeholder = "Password"
input.isSecureTextEntry = true
return input
}()
}
Thanks for your helps guys, I really need that.
A little not: Textfield is not nil by the way, the nil thing is its text, it is every time returns nil.

Related

CollectionView in TableView Cell Swift mix card type reuse issue

A collection view is contained in a table view cell.
Collection view cells are drawn for each card type.
In indexPath 0 and 1, the card is of a single type.
indexPath 2 is a mix type.
There are three card types, live reserved vod, and playLayer is added when it is a vod type.
When drawing collection view cells in mix type, playLayer is added to reserved type, and playLayer is added to all cells when scrolling up and down.
class TableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
lazy private var homeManager = HomeManager()
var sections: [Section]?
var liveData: [Item]?
var vodData: [Item]?
var mixData: [Item]?
var table: UITableView = {
let tableView = UITableView()
tableView.register(CardCollectionTableViewCell.self, forCellReuseIdentifier: CardCollectionTableViewCell.identifier)
return tableView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .black
view.addSubview(table)
homeManager.getdata{ [weak self] response in
self?.sections = response.sections ?? []
self?.liveData = self?.sections?[1].items ?? []
self?.vodData = self?.sections?[2].items ?? []
self?.mixData = self?.sections?[3].items ?? []
self?.table.reloadData()
}
table.delegate = self
table.dataSource = self
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
table.frame = view.bounds
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 && liveData != nil {
let cell = table.dequeueReusableCell(withIdentifier: CardCollectionTableViewCell.identifier, for: indexPath) as! CardCollectionTableViewCell
cell.configure(with: liveData)
cell.titleLabel.text = sections![1].title!
return cell
} else if indexPath.row == 1 && vodData != nil {
let cell = table.dequeueReusableCell(withIdentifier: CardCollectionTableViewCell.identifier, for: indexPath) as! CardCollectionTableViewCell
cell.configure(with: vodData)
cell.titleLabel.text = sections![2].title!
return cell
} else if indexPath.row == 2 && mixData != nil {
let cell = table.dequeueReusableCell(withIdentifier: CardCollectionTableViewCell.identifier, for: indexPath) as! CardCollectionTableViewCell
cell.configure(with: mixData)
cell.titleLabel.text = sections![3].title!
return cell
}
else {
return UITableViewCell()
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 400
}
CardCollection TableViewCell
static let identifier = "CardCollectionTableViewCell"
var titleLabel: UILabel = {
let label = UILabel()
label.font = Fonts.text16()
label.textColor = .white
return label
}()
var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
layout.scrollDirection = .horizontal
collectionView.register(MyCollectionViewCell.self, forCellWithReuseIdentifier: MyCollectionViewCell.identifier)
collectionView.backgroundColor = .black
return collectionView
}()
var models:[Item]?
func configure(with models: [Item]?) {
self.models = models
titleLabel.snp.makeConstraints { make in
make.top.equalToSuperview()
make.leading.equalToSuperview().offset(20)
make.width.equalTo(300)
make.height.equalTo(24)
}
collectionView.snp.makeConstraints { make in
make.top.equalToSuperview().offset(44)
make.leading.equalToSuperview().offset(20)
make.trailing.bottom.equalToSuperview()
}
collectionView.reloadData()
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(collectionView)
contentView.addSubview(titleLabel)
collectionView.delegate = self
collectionView.dataSource = self
contentView.backgroundColor = .black
//guard models != nil else { return }
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// Collectionview
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return models?.count ?? 5
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyCollectionViewCell.identifier, for: indexPath) as! MyCollectionViewCell
cell.setupViews(with: models![indexPath.item])
cell.setupConstraints(with: models![indexPath.item])
cell.configure(with: models![indexPath.item])
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 140, height: 350)
}
CollectionViewCell
class MyCollectionViewCell: UICollectionViewCell {
static let identifier = "MyCollectionViewCell"
var player: AVPlayer?
private lazy var imageView: UIImageView = {
let image = UIImageView()
image.contentMode = .scaleAspectFill
image.clipsToBounds = true
image.backgroundColor = .blue
image.layer.cornerRadius = 8
return image
}()
private lazy var typeLabelBackgroud: UIImageView = {
let image = UIImageView()
image.clipsToBounds = true
image.layer.cornerRadius = 8
return image
}()
private lazy var playerView: AVPlayerLayer? = {
let url = URL(string: "https://1303309272.vod2.myqcloud.com/7e895809vodkr1303309272/8155555e3701925920462082823/f0.mp4")
player = AVPlayer(url: url!)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = CGRect(x: 0, y: 0, width: 140, height: 210)
playerLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.player?.play()
}
return playerLayer
}()
private lazy var typeLabel: UILabel = {
let label = UILabel()
label.font = Fonts.text10()
label.textColor = .white
return label
}()
private lazy var timeLabel: UILabel? = {
let label = UILabel()
label.font = Fonts.text11()
label.textColor = .white
label.frame.size.width = 42
label.frame.size.height = 16
return label
}()
private lazy var titleLabel: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.font = Fonts.text14()
label.textColor = .white
return label
}()
private lazy var storeName: UILabel = {
let label = UILabel()
label.font = Fonts.text11()
label.textColor = .gray
return label
}()
private lazy var heartImage: UIImageView = {
let image = UIImageView()
image.image = UIImage(named: "Vector")
image.contentMode = .scaleAspectFit
return image
}()
private lazy var heartCountLabel: UILabel = {
let label = UILabel()
label.font = Fonts.text11()
label.textColor = .gray
label.frame.size.width = 27
label.frame.size.height = 16
label.textAlignment = .left
return label
}()
private lazy var eyeImage: UIImageView = {
let image = UIImageView()
image.image = UIImage(named: "Eye")
image.contentMode = .scaleAspectFit
return image
}()
private lazy var eyeCountLabel: UILabel = {
let label = UILabel()
label.font = Fonts.text11()
label.textColor = .gray
label.frame.size.width = 27
label.frame.size.height = 16
label.textAlignment = .left
return label
}()
private override init(frame: CGRect) {
super.init(frame: frame)
}
public convenience init() {
self.init(frame:. zero)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews(with model: Item?) {
guard model != nil else {return}
print("CollectionViewCell의 model! data: \(model)")
if model!.type == "LIVE" {
addSubview(imageView)
addSubview(typeLabelBackgroud)
addSubview(typeLabel)
addSubview(titleLabel)
addSubview(storeName)
addSubview(heartImage)
addSubview(heartCountLabel)
addSubview(eyeImage)
addSubview(eyeCountLabel)
} else if model!.type == "RESERVED"{
addSubview(imageView)
addSubview(typeLabelBackgroud)
addSubview(typeLabel)
addSubview(titleLabel)
addSubview(storeName)
addSubview(heartImage)
addSubview(heartCountLabel)
addSubview(eyeImage)
addSubview(eyeCountLabel)
} else if model!.type == "VOD" {
addSubview(imageView)
addSubview(typeLabelBackgroud)
addSubview(typeLabel)
addSubview(titleLabel)
addSubview(storeName)
addSubview(heartImage)
addSubview(heartCountLabel)
addSubview(eyeImage)
addSubview(eyeCountLabel)
addSubview(timeLabel!)
imageView.layer.addSublayer(playerView!)
}
}
func setupConstraints(with model: Item?) {
guard model != nil else {return}
if model!.type == "LIVE" {
imageView.snp.makeConstraints { make in
make.width.equalTo(140)
make.height.equalTo(210)
}
typeLabelBackgroud.snp.makeConstraints { make in
make.leading.equalTo(imageView).inset(8)
make.top.equalTo(imageView).inset(10)
make.width.equalTo(33)
make.height.equalTo(20)
}
typeLabel.snp.makeConstraints { make in
make.leading.equalTo(typeLabelBackgroud).inset(6)
make.top.equalTo(typeLabelBackgroud).inset(2)
make.width.equalTo(21)
make.height.equalTo(16)
}
titleLabel.snp.makeConstraints { make in
make.top.equalTo(imageView.snp.bottom).offset(8)
make.width.equalTo(140)
make.height.equalTo(42)
}
storeName.snp.makeConstraints { make in
make.top.equalTo(titleLabel.snp.bottom).offset(4)
make.width.equalTo(140)
make.height.equalTo(16)
}
heartImage.snp.makeConstraints { make in
make.top.equalTo(storeName.snp.bottom).offset(3)
make.width.height.equalTo(16)
}
heartCountLabel.snp.makeConstraints { make in
make.top.equalTo(storeName.snp.bottom).offset(3)
make.leading.equalTo(heartImage.snp.trailing).offset(5)
}
eyeImage.snp.makeConstraints { make in
make.leading.equalTo(heartCountLabel.snp.trailing).offset(13)
make.top.equalTo(storeName.snp.bottom).offset(3)
make.width.height.equalTo(16)
}
eyeCountLabel.snp.makeConstraints { make in
make.top.equalTo(storeName.snp.bottom).offset(3)
make.leading.equalTo(eyeImage.snp.trailing).offset(5)
}
} else if model!.type == "RESERVED" {
imageView.snp.makeConstraints { make in
make.width.equalTo(140)
make.height.equalTo(210)
}
typeLabelBackgroud.snp.makeConstraints { make in
make.leading.equalTo(imageView).inset(8)
make.top.equalTo(imageView).inset(10)
make.width.equalTo(33)
make.height.equalTo(20)
}
typeLabel.snp.makeConstraints { make in
make.leading.equalTo(typeLabelBackgroud).inset(6)
make.top.equalTo(typeLabelBackgroud).inset(2)
make.width.equalTo(21)
make.height.equalTo(16)
}
titleLabel.snp.makeConstraints { make in
make.top.equalTo(imageView.snp.bottom).offset(8)
make.width.equalTo(140)
make.height.equalTo(42)
}
storeName.snp.makeConstraints { make in
make.top.equalTo(titleLabel.snp.bottom).offset(4)
make.width.equalTo(140)
make.height.equalTo(16)
}
heartImage.snp.makeConstraints { make in
make.top.equalTo(storeName.snp.bottom).offset(3)
make.width.height.equalTo(16)
}
heartCountLabel.snp.makeConstraints { make in
make.top.equalTo(storeName.snp.bottom).offset(3)
make.leading.equalTo(heartImage.snp.trailing).offset(5)
}
eyeImage.snp.makeConstraints { make in
make.leading.equalTo(heartCountLabel.snp.trailing).offset(13)
make.top.equalTo(storeName.snp.bottom).offset(3)
make.width.height.equalTo(16)
}
eyeCountLabel.snp.makeConstraints { make in
make.top.equalTo(storeName.snp.bottom).offset(3)
make.leading.equalTo(eyeImage.snp.trailing).offset(5)
}
} else if model!.type == "VOD" {
imageView.snp.makeConstraints { make in
make.width.equalTo(140)
make.height.equalTo(210)
}
typeLabelBackgroud.snp.makeConstraints { make in
make.leading.equalTo(imageView).inset(8)
make.top.equalTo(imageView).inset(10)
make.width.equalTo(33)
make.height.equalTo(20)
}
typeLabel.snp.makeConstraints { make in
make.leading.equalTo(typeLabelBackgroud).inset(6)
make.top.equalTo(typeLabelBackgroud).inset(2)
make.width.equalTo(21)
make.height.equalTo(16)
}
timeLabel!.snp.makeConstraints { make in
make.top.equalTo(imageView).inset(8)
make.trailing.equalTo(imageView).inset(10)
}
titleLabel.snp.makeConstraints { make in
make.top.equalTo(imageView.snp.bottom).offset(8)
make.width.equalTo(140)
make.height.equalTo(42)
}
storeName.snp.makeConstraints { make in
make.top.equalTo(titleLabel.snp.bottom).offset(4)
make.width.equalTo(140)
make.height.equalTo(16)
}
heartImage.snp.makeConstraints { make in
make.top.equalTo(storeName.snp.bottom).offset(3)
make.width.height.equalTo(16)
}
heartCountLabel.snp.makeConstraints { make in
make.top.equalTo(storeName.snp.bottom).offset(3)
make.leading.equalTo(heartImage.snp.trailing).offset(5)
}
eyeImage.snp.makeConstraints { make in
make.leading.equalTo(heartCountLabel.snp.trailing).offset(13)
make.top.equalTo(storeName.snp.bottom).offset(3)
make.width.height.equalTo(16)
}
eyeCountLabel.snp.makeConstraints { make in
make.top.equalTo(storeName.snp.bottom).offset(3)
make.leading.equalTo(eyeImage.snp.trailing).offset(5)
}
}
}
public func configure(with model: Item?) {
//self.model! = model!
guard model != nil else {return}
if model!.type == "LIVE" {
imageView.kf.setImage(with: URL(string: model!.image!))
typeLabel.text = "LIVE"
typeLabelBackgroud.backgroundColor = .orange
titleLabel.text = String(model!.title!)
storeName.text = String(model!.store!)
heartCountLabel.text = String(model!.likeCount!)
eyeCountLabel.text = String(model!.playedCount!)
} else if model!.type == "RESERVED" {
imageView.kf.setImage(with: URL(string: model!.image!))
typeLabel.text = "예정"
typeLabelBackgroud.backgroundColor = Colors.primary()
titleLabel.text = String(model!.title!)
storeName.text = String(model!.store!)
heartCountLabel.text = String(model!.likeCount!)
eyeCountLabel.text = String(model!.playedCount!)
} else if model!.type == "VOD" {
imageView.kf.setImage(with: URL(string: model!.image!))
typeLabel.text = "VOD"
titleLabel.text = String(model!.title!)
typeLabelBackgroud.backgroundColor = Colors.vodBackgroud()
storeName.text = String(model!.store!)
heartCountLabel.text = String(model!.likeCount!)
eyeCountLabel.text = String(model!.playedCount!)
timeLabel?.text = "01:35:40"
}
}
}
The way I tried is let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) ->
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: collectionViewFlowLayout.init()) .
The reuse problem did not occur, but it cannot be used because the scroll direction is changed.
You could solve your problem in two ways:
1 - reset your cell in cellForItemAt
Currently you call cell.setupViews(with: models![indexPath.item]) for each cell, which adds subviews to the cells. Since collectionView reuses cells, when scrolling you are getting cells which where used as all types (live, reserved, vod), that is why you see that "playLayer is added to all cells when scrolling up and down".
With this code you also add subviews each time the cell is reused, which is also not the best practice.
You could add an additional function to reset the cell and remove all subviews before adding new ones:
cell.subviews.forEach { $0.removeFromSuperview() }
(it is also better to add views to the cell.contentView)
2 - Create separate classes for different cell types
In cellFroItemAtyou could check for the type of the cell and return the required on. Each type will have a different ReuseIdentifier and playLayer will be added only to the type you need

Inset a new section in UICollectionView with new type of Cell

I am working on a chat app. I am using UICollectionView to display text and different type of text. I have 3 type of cells. In the first section, I am loading the first type of cell. in second, second type and in third, third type of cell loading. I have a button text field. When i click send button in text field i want to create new section of type first cell. I don't know how to create. Please help :)
Here is my Code:
// ChatLogController.swift
// Blubyn
//
// Created by JOGENDRA on 02/02/18.
// Copyright © 2018 Jogendra Singh. All rights reserved.
//
import UIKit
fileprivate enum DefaultConstants {
static let sendButtonImageName: String = "send-icon"
static let voiceButtonImageName: String = "microphone"
}
enum Cells {
case chatCell
case oneWayFlight
case twoWayFlight
}
class ChatLogController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
fileprivate var sideBar = SideBar()
lazy var inputTextField: UITextField = {
let textField = UITextField()
textField.placeholder = "Send a message..."
textField.delegate = self
return textField
}()
let textView: UIView = {
let textFieldview = UIView()
textFieldview.backgroundColor = UIColor.white
textFieldview.translatesAutoresizingMaskIntoConstraints = false
return textFieldview
}()
let cellId = "cellId"
let oneWayCellId = "oneWayFlightCell"
let twoWayCellId = "twoWayFlightCell"
var numberOfSections: Int = 0
var numberOfItemsInASection: Int = 0
var cellType: Cells?
var keyboardHeight: CGFloat = 0.0
var textViewBottomAnchor: NSLayoutConstraint?
var userMessages: [String] = ["Hey there!", "I want to book flight for Pokhara, Nepal", "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s", "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.", "Book a hotel for me near lakeside", "book returning flight"]
var systemMessages: [String] = ["Hello Jogendra!", "Pluto at your service - your guide and concierge to help you with the planning ticket booking and finding new and exotic places.", "Go on! Try me out. Won't take long. I promise."]
lazy var messages: [String] = systemMessages + userMessages
override func viewDidLoad() {
super.viewDidLoad()
setupInputComponents()
sideBarSetup()
collectionView?.contentInset = UIEdgeInsets(top: 8.0, left: 0, bottom: 52.0, right: 0)
collectionView?.backgroundColor = UIColor.chatbackgroundColor
// Register Chat Cell
collectionView?.register(ChatMessagesCell.self, forCellWithReuseIdentifier: cellId)
// Regsiter One Way Flight Cell
let oneWayFlightCellNib = UINib(nibName: "OneWayFlightViewCell", bundle: nil)
collectionView?.register(oneWayFlightCellNib, forCellWithReuseIdentifier: oneWayCellId)
// Register Two Way Flight Cell
let twoWayFlightCellNib = UINib(nibName: "TwoWayFlightViewCell", bundle: nil)
collectionView?.register(twoWayFlightCellNib, forCellWithReuseIdentifier: twoWayCellId)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
// Register Notification, To know When Key Board Appear.
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: Notification.Name.UIKeyboardWillShow, object: nil)
// Register Notification, To know When Key Board Hides.
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
// De register the notifications
NotificationCenter.default.removeObserver(self)
}
fileprivate func setupInputComponents() {
// Text View setups
view.addSubview(textView)
textView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
textView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
textView.heightAnchor.constraint(equalToConstant: 44.0).isActive = true
textViewBottomAnchor = textView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
textViewBottomAnchor?.isActive = true
let voiceButton = UIButton(type: .system)
let voiceButtonImage = UIImage(named: DefaultConstants.voiceButtonImageName)
voiceButton.setImage(voiceButtonImage, for: .normal)
textView.addSubview(voiceButton)
voiceButton.translatesAutoresizingMaskIntoConstraints = false
voiceButton.topAnchor.constraint(equalTo: textView.topAnchor).isActive = true
voiceButton.trailingAnchor.constraint(equalTo: textView.trailingAnchor).isActive = true
voiceButton.bottomAnchor.constraint(equalTo: textView.bottomAnchor).isActive = true
voiceButton.widthAnchor.constraint(equalToConstant: 44.0).isActive = true
let sendButton = UIButton(type: .system)
let sendButtonImage = UIImage(named: DefaultConstants.sendButtonImageName)
sendButton.setImage(sendButtonImage, for: .normal)
textView.addSubview(sendButton)
sendButton.addTarget(self, action: #selector(didTapSend), for: .touchUpInside)
sendButton.translatesAutoresizingMaskIntoConstraints = false
sendButton.topAnchor.constraint(equalTo: textView.topAnchor).isActive = true
sendButton.trailingAnchor.constraint(equalTo: voiceButton.leadingAnchor).isActive = true
sendButton.bottomAnchor.constraint(equalTo: textView.bottomAnchor).isActive = true
sendButton.widthAnchor.constraint(equalToConstant: 44.0).isActive = true
textView.addSubview(inputTextField)
inputTextField.translatesAutoresizingMaskIntoConstraints = false
inputTextField.leadingAnchor.constraint(equalTo: textView.leadingAnchor, constant: 4.0).isActive = true
inputTextField.trailingAnchor.constraint(equalTo: sendButton.leadingAnchor, constant: -4.0).isActive = true
inputTextField.topAnchor.constraint(equalTo: textView.topAnchor).isActive = true
inputTextField.bottomAnchor.constraint(equalTo: textView.safeAreaLayoutGuide.bottomAnchor).isActive = true
let separator = UIView()
separator.backgroundColor = UIColor.black.withAlphaComponent(0.4)
textView.addSubview(separator)
separator.translatesAutoresizingMaskIntoConstraints = false
separator.leadingAnchor.constraint(equalTo: textView.leadingAnchor).isActive = true
separator.trailingAnchor.constraint(equalTo: textView.trailingAnchor).isActive = true
separator.topAnchor.constraint(equalTo: textView.topAnchor).isActive = true
separator.heightAnchor.constraint(equalToConstant: 1.0).isActive = true
}
// MARK: - Keyboard Events
#objc func keyboardWillShow(_ notification: Notification) {
if let keyboardFrame: NSValue = notification.userInfo![UIKeyboardFrameEndUserInfoKey] as? NSValue {
let keyboardRectangle = keyboardFrame.cgRectValue
keyboardHeight = keyboardRectangle.height
}
let keyboardDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Double
textViewBottomAnchor?.constant = -keyboardHeight
UIView.animate(withDuration: keyboardDuration!, animations: {
self.view.layoutIfNeeded()
})
}
#objc func keyboardWillHide(_ notification: Notification) {
let keyboardDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Double
textViewBottomAnchor?.constant = 0
UIView.animate(withDuration: keyboardDuration!, animations: {
self.view.layoutIfNeeded()
})
}
// MARK: - Collection View Methods
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
switch section {
case 0:
return messages.count
case 1:
numberOfItemsInASection = 5
return numberOfItemsInASection
case 2:
return 5
default:
numberOfItemsInASection = 5
return numberOfItemsInASection
}
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! ChatMessagesCell
let message = messages[indexPath.item]
cell.chatTextView.text = message
// Align chat cell according
if userMessages.contains(message) {
cell.bubbleView.backgroundColor = UIColor.white
cell.chatTextView.textColor = UIColor.black
cell.bubbleViewRightAnchor?.isActive = true
cell.bubbleViewLeftAnchor?.isActive = false
} else {
cell.bubbleView.backgroundColor = UIColor.chatThemeColor
cell.chatTextView.textColor = UIColor.white
cell.bubbleViewRightAnchor?.isActive = false
cell.bubbleViewLeftAnchor?.isActive = true
}
//Modify the width accordingly
cell.bubbleWidthAnchor?.constant = estimateFrameForText(text: message).width + 32.0
if indexPath.section == 0 {
cellType = Cells.chatCell
return cell
} else if indexPath.section == 1 {
let oneWayFlightCell = collectionView.dequeueReusableCell(withReuseIdentifier: oneWayCellId, for: indexPath) as! OneWayFlightViewCell
cellType = Cells.oneWayFlight
return oneWayFlightCell
} else {
let twoWayFlightCell = collectionView.dequeueReusableCell(withReuseIdentifier: twoWayCellId, for: indexPath) as! TwoWayFlightViewCell
cellType = Cells.twoWayFlight
return twoWayFlightCell
}
}
override func numberOfSections(in collectionView: UICollectionView) -> Int {
numberOfSections = 3
return numberOfSections
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
var cellHeight: CGFloat = 80.0
let text = messages[indexPath.item]
cellHeight = estimateFrameForText(text: text).height + 20.0
if indexPath.section == 1 {
cellHeight = 112
} else if indexPath.section == 2 {
cellHeight = 201
}
return CGSize(width: collectionView.frame.width, height: cellHeight)
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
inputTextField.resignFirstResponder()
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
//{top, left, bottom, right}
return UIEdgeInsetsMake(10, 0, 10, 0)
}
private func estimateFrameForText(text: String) -> CGRect {
let size = CGSize(width: 300.0, height: 1000)
let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
return NSString(string: text).boundingRect(with: size, options: options, attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 17.0)], context: nil)
}
#objc fileprivate func didTapSend() {
if let enteredText = inputTextField.text, !enteredText.isEmpty {
messages.append(enteredText)
userMessages.append(enteredText)
}
collectionView?.reloadData()
inputTextField.text = nil
}
fileprivate func sideBarSetup() {
sideBar = SideBar(sourceView: self.view, menuItems: ["Chat", "Hot Deals", "My Trips", "Experiences", "Settings", "Profile"])
sideBar.delegate = self
}
#IBAction func didTapMenu(_ sender: Any) {
sideBar.showSideBar(!sideBar.isSideBarOpen)
}
#IBAction func didTapHelp(_ sender: Any) {
}
}
extension ChatLogController: SideBarDelegate {
func SideBarDidSelectButtonAtIndex(_ index: Int) {
switch index {
case 0:
sideBar.showSideBar(!sideBar.isSideBarOpen)
case 1:
sideBar.showSideBar(!sideBar.isSideBarOpen)
case 2:
sideBar.showSideBar(!sideBar.isSideBarOpen)
case 3:
sideBar.showSideBar(!sideBar.isSideBarOpen)
case 4:
let settingStoryboard = UIStoryboard(name: "Main", bundle: nil)
let settingsViewController = settingStoryboard.instantiateViewController(withIdentifier: "settingvc")
self.navigationController?.pushViewController(settingsViewController, animated: true)
case 5:
let profileStoryboard = UIStoryboard(name: "Main", bundle: nil)
let profileViewController = profileStoryboard.instantiateViewController(withIdentifier: "profilevc")
self.navigationController?.pushViewController(profileViewController, animated: true)
default:
break
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
inputTextField.resignFirstResponder()
inputTextField.endEditing(true)
}
}
extension ChatLogController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
inputTextField.endEditing(true)
return true
}
}
Designs:
See Screens Section of [this link][1].
Achieved Designs:
[![screenshot1][2]][2]
[![screenshot2][3]][3]
[![screenshot3][4]][4]
[![screenshot4][5]][5]
[1]: https://blubyn.com/
[2]: https://i.stack.imgur.com/S9ZLX.png
[3]: https://i.stack.imgur.com/wLvAu.png
[4]: https://i.stack.imgur.com/nBKbH.png
[5]: https://i.stack.imgur.com/Sota4.png

UICollectionViewCell's UiTextField, overlapping in UICollectionViewController

I am trying to design a multistep sign-up menu. For this purpose I am using UICollectionViewController with screen size cells. In these cells, I have a UITextView to ask questions and a UITextField to collect the answers. I also have a Page object for passing in information from uicollectionviewcontroller upon setting.
The problem I'm having now is that after every 3rd page my textField input from 3 pages ago repeats, instead of showing the placeholder. I have noticed yet another problem, the cells seem to be instantiating just 3 times, and not 6 times for how many pages I have. The instantiation order is very odd too. At first it does it once, then upon button click, twice more, then never again.
How can fix this, I am really struggling with this and I have no idea what's going wrong.
This is my code:
import UIKit
class OnboardingPageViewCell: UICollectionViewCell{
override init(frame: CGRect) {
super.init(frame: frame)
print("made a page")
setupView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var oboardingPage = NewOnboardingPage() {
didSet{
reload()
}
}
private var questionTextField: UITextView = {
var q = UITextView()
q.textColor = UIColor.white
q.textAlignment = .left
q.font = UIFont(name: "Avenir-Black", size: 25)
q.isEditable = true
q.isScrollEnabled = false
q.backgroundColor = UIColor.black
q.translatesAutoresizingMaskIntoConstraints = false
print("made aquestion field")
return q
}()
private var answerField : CustomTextField = {
let tf = CustomTextField.nameField
print("made an answer field")
return tf
}()
private func setupView(){
backgroundColor = UIColor.white
addSubview(questionTextField)
questionTextField.topAnchor.constraint(equalTo: topAnchor, constant: 120).isActive = true
questionTextField.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
questionTextField.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.90).isActive = true
questionTextField.heightAnchor.constraint(equalToConstant: 90).isActive = true
addSubview(answerField)
answerField.topAnchor.constraint(equalTo: questionTextField.bottomAnchor, constant: 20).isActive = true
answerField.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
answerField.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.90).isActive = true
answerField.heightAnchor.constraint(equalToConstant: 90).isActive = true
}
private func reload(){
questionTextField.text = oboardingPage.question
answerField.placeholder = oboardingPage.answerField
}
}
class NewOnboardingPage {
var question : String?
var answerField : String?
}
import UIKit
class SignUpController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
private let cellId = "cellId"
private var pages = [NewOnboardingPage]()
override func viewDidLoad() {
super .viewDidLoad()
setupSignUpControllerView()
addPages()
}
private func addPages(){
let namePage = NewOnboardingPage()
namePage.question = "What's your name?"
namePage.answerField = "What's your name?"
pages.append(namePage)
let birthDayPage = NewOnboardingPage()
birthDayPage.question = "When's your birthdate?"
birthDayPage.answerField = "When's your birthdate?"
pages.append(birthDayPage)
let userNamePage = NewOnboardingPage()
userNamePage.question = "Choose a user name."
userNamePage.answerField = "Choose a user name."
pages.append(userNamePage)
let passWordPage = NewOnboardingPage()
passWordPage.question = "Set a password"
passWordPage.answerField = "Set a password"
pages.append(passWordPage)
let emailAuthPage = NewOnboardingPage()
emailAuthPage.question = "What's your email?"
emailAuthPage.answerField = "What's your email?"
pages.append(emailAuthPage)
let phoneNumberPage = NewOnboardingPage()
phoneNumberPage.question = "What's your phone number?"
phoneNumberPage.answerField = "What's your phone number?"
pages.append(phoneNumberPage)
}
private func setupSignUpControllerView(){
collectionView?.backgroundColor = .white
collectionView?.register(OnboardingPageViewCell.self, forCellWithReuseIdentifier: cellId)
collectionView?.isPagingEnabled = true
collectionView?.isScrollEnabled = true
if let layout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
}
view.addSubview(nextButton)
nextButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 400).isActive = true
nextButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
nextButton.widthAnchor.constraint(equalToConstant: 250).isActive = true
nextButton.heightAnchor.constraint(equalToConstant: 60).isActive = true
}
private let nextButton: UIButton = {
let button = UIButton(type: .system)
button.backgroundColor = UIColor.RED
button.setTitle("next", for: .normal)
button.setTitleColor(UIColor.white, for: .normal)
button.titleLabel?.font = UIFont(name: "Avenir-Black", size: 25)
button.layer.cornerRadius = 30
button.translatesAutoresizingMaskIntoConstraints = false
button.addTarget(self, action: #selector(turnNextPage), for: .touchUpInside)
return button
}()
#objc private func turnNextPage() {
let visibleItems: NSArray = collectionView?.indexPathsForVisibleItems as! NSArray
let currentItem: IndexPath = visibleItems.object(at: 0) as! IndexPath
let nextItem: IndexPath = IndexPath(item: currentItem.item + 1, section: 0)
if nextItem.row < pages.count {
collectionView?.scrollToItem(at: nextItem, at: .left, animated: true)
}
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return pages.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! OnboardingPageViewCell
cell.oboardingPage = pages[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: view.frame.height)
}
}
import UIKit
class CustomTextField: UITextField, UITextFieldDelegate {
convenience init() {
self.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
self.allowsEditingTextAttributes = false
self.autocorrectionType = .no
self.tintColor = UIColor.RED
self.translatesAutoresizingMaskIntoConstraints = false
}
override func willMove(toSuperview newSuperview: UIView?) {
addTarget(self, action: #selector(editingChanged), for: .editingChanged)
editingChanged(self)
}
#objc func editingChanged(_ textField: UITextField) {
guard let text = textField.text else { return }
textField.text = String(text.prefix(30))
}
override func selectionRects(for range: UITextRange) -> [Any] {
return []
}
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(paste(_:)) ||
action == #selector(cut(_:)) ||
action == #selector(copy(_:)) ||
action == #selector(select(_:)) ||
action == #selector(selectAll(_:)){
return false
}
return super.canPerformAction(action, withSender: sender)
}
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! OnboardingPageViewCell
cell.answerField.text = nil
cell.oboardingPage = pages[indexPath.item]
return cell
}
1- textFeild showing same data instead of placeholder bacause of cell dequeuing so you must hook these properties and clear their content in cellForRowAt
2- Instantiation is 3 not 6 aslo cell dequeuing
Solve:
Add two properties to your model NewOnboardingPage name them currentQuestion and currentAnswer and as the user inputs and scroll to next page save them in the modelarray that you should make global to be accessed indside cell and outside set these values to the textfeild and textView as you scroll in cellForRowAt

Custom cell for UICollection view cell unable clear old data

I created a custom UICollection cell but the data sometimes appear in the wrong cell and no matter how much I refresh the UICollection view it refuses to change. I have done a print out to see if the data gotten from the array is wrong but it's not. Is there a way to clear the old data from the cell before inputting the next one. Any suggestion will be appreciated.
custom cell
class customAppointmentViewCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
let thumbnailImageView: UIImageView = {
let tniv = UIImageView()
tniv.translatesAutoresizingMaskIntoConstraints = false
tniv.backgroundColor = UIColor.clear
tniv.contentMode = .scaleAspectFit
return tniv
}()
let seperatorView: UIView = {
let sv = UIView()
sv.translatesAutoresizingMaskIntoConstraints = false
sv.backgroundColor = UIColor(r: 11, g: 49, b: 68)
return sv
}()
let clientNamePlaceHolder: UILabel = {
let fnhp = UILabel()
fnhp.translatesAutoresizingMaskIntoConstraints = false
fnhp.font = UIFont(name: "HelveticaNeue-Medium", size: 17)
fnhp.textColor = UIColor.white
fnhp.textAlignment = .left
return fnhp
}()
let openingTimePlaceHolder: UILabel = {
let fnhp = UILabel()
fnhp.translatesAutoresizingMaskIntoConstraints = false
fnhp.font = UIFont(name: "HelveticaNeue-Medium", size: 12)
fnhp.textColor = UIColor.white
fnhp.textAlignment = .left
return fnhp
}()
let closingTimePlaceHolder: UILabel = {
let fnhp = UILabel()
fnhp.translatesAutoresizingMaskIntoConstraints = false
fnhp.font = UIFont(name: "HelveticaNeue-Medium", size: 12)
fnhp.textColor = UIColor.white
fnhp.textAlignment = .left
return fnhp
}()
let bookedBarberNamePlaceHolder: UILabel = {
let fnhp = UILabel()
fnhp.translatesAutoresizingMaskIntoConstraints = false
fnhp.font = UIFont(name: "HelveticaNeue-Medium", size: 12)
fnhp.textColor = UIColor.white
fnhp.textAlignment = .left
return fnhp
}()
let servicePricePlaceHolder: UILabel = {
let fnhp = UILabel()
fnhp.translatesAutoresizingMaskIntoConstraints = false
fnhp.font = UIFont(name: "HelveticaNeue-Medium", size: 10)
fnhp.textColor = UIColor.white
fnhp.textAlignment = .right
return fnhp
}()
func setupViews(){
addSubview(thumbnailImageView)
addSubview(clientNamePlaceHolder)
addSubview(openingTimePlaceHolder)
addSubview(closingTimePlaceHolder)
addSubview(bookedBarberNamePlaceHolder)
addSubview(servicePricePlaceHolder)
addSubview(seperatorView)
backgroundColor = UIColor(r: 23, g: 69, b: 90)
addContraintsWithFormat(format: "H:|-16-[v0(90)]|", views: thumbnailImageView)
addContraintsWithFormat(format: "H:|-116-[v0][v1(50)]-10-|", views: clientNamePlaceHolder, servicePricePlaceHolder)
addContraintsWithFormat(format: "H:|-116-[v0]-60-|", views: openingTimePlaceHolder)
addContraintsWithFormat(format: "H:|-116-[v0]-60-|", views: closingTimePlaceHolder)
addContraintsWithFormat(format: "H:|-116-[v0]-60-|", views: bookedBarberNamePlaceHolder)
addContraintsWithFormat(format: "V:|-10-[v0(20)][v1(20)][v2(20)][v3(20)]-10-|", views: clientNamePlaceHolder, openingTimePlaceHolder,closingTimePlaceHolder, bookedBarberNamePlaceHolder)
addContraintsWithFormat(format: "V:|-10-[v0(20)]|", views: servicePricePlaceHolder)
addContraintsWithFormat(format: "V:|-10-[v0]-10-[v1(5)]|", views: thumbnailImageView,seperatorView)
addContraintsWithFormat(format: "H:|[v0]|", views: seperatorView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
collection view
extension AppointmentsViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.appointments.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! customAppointmentViewCell
//empty cell data
//real data
cell.openingTimePlaceHolder.text = ""
if let opentime = self.appointments[safe: indexPath.row]?.bookingStartTimeString {
cell.openingTimePlaceHolder.text = opentime
} else {
cell.openingTimePlaceHolder.text = ""
}
cell.closingTimePlaceHolder.text = ""
if let closetime = self.appointments[safe: indexPath.row]?.bookingEndTimeString {
cell.closingTimePlaceHolder.text = closetime
} else {
cell.closingTimePlaceHolder.text = ""
}
cell.bookedBarberNamePlaceHolder.text = ""
if let barberName = self.appointments[safe: indexPath.row]?.bookedBarberName {
cell.bookedBarberNamePlaceHolder.text = barberName
} else {
cell.bookedBarberNamePlaceHolder.text = ""
}
cell.servicePricePlaceHolder.text = ""
if let servicepricee = self.appointments[safe: indexPath.row]?.bookedServicePrice {
cell.servicePricePlaceHolder.text = servicepricee
} else {
cell.servicePricePlaceHolder.text = ""
}
cell.thumbnailImageView.image = UIImage()
if let profileimagess = self.appointments[safe: indexPath.row]?.profileImage {
cell.thumbnailImageView.image = profileimagess
} else {
cell.thumbnailImageView.image = UIImage()
}
cell.clientNamePlaceHolder.text = ""
if let clientnamess = self.appointments[safe: indexPath.row]?.clientName {
cell.clientNamePlaceHolder.text = clientnamess
} else {
cell.clientNamePlaceHolder.text = ""
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectView.frame.width, height: 100)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let uuidAvail = UserDefaults.standard.object(forKey: "theOriginalBarberShopUUID") as? String{
if let bookIDDD = self.appointments[safe: indexPath.row]?.bookingUniqueID {
let orderDetail = OrderDetailViewController()
orderDetail.specificAppintment = self.appointments[indexPath.row]
orderDetail.barberShopID = uuidAvail
orderDetail.bookingUniqueIDDD = bookIDDD
orderDetail.bookedBarberUUIDAX = self.appointments[indexPath.row].bookedBarberUUID
orderDetail.appointmentsviewhold = self
orderDetail.indexPathSelected = indexPath.row
navigationController?.pushViewController(orderDetail, animated: true)
}
}
}
}
thanks
Do this in customAppointmentViewCell
override func prepareForReuse() {
self. thumbnailImageView.image = UIImage()
//add here other variable and set default value for all.
}
prepareForReuse is called when a new cell will show on screen.
And Remove default value set code from your cellForRow as guided by Nikhil Manapure.
Hope this helps you.
Try this -
Implement the method prepareForReuse in your customAppointmentViewCell and in this method remove all the data and reset everything. If you are adding some subView to cell in cellForRow, remove that too.
By doing this you will be able to reduce this-
cell.clientNamePlaceHolder.text = ""
if let clientnamess = self.appointments[safe: indexPath.row]?.clientName {
cell.clientNamePlaceHolder.text = clientnamess
} else {
cell.clientNamePlaceHolder.text = ""
}
to this-
if let clientnamess = self.appointments[safe: indexPath.row]?.clientName {
cell.clientNamePlaceHolder.text = clientnamess
}
After doing this, check if the issue is still there.
Hope this helps :)
Try Passing the model object to the UICollectionViewCell class by assigning a property in cell
example:
UICollectionViewCell:
var object: Model? {
didSet{
// here do your assignment of text to various labels
}
}
CellForRow:
let cell = ...
cell.object = self.appointments[indexPath.item]
return cell
I hope this works.

UICollectionViewCell message sent to deallocated instance right after being dequeued

I have a UICollectionViewCell which is being dequeued for reuse. I recently introduced a sliding drawer functionality which is basically a hidden view which gets displayed when the user swipes.
After the last change this seemed to create a case where the instance was being deallocated while being initialized. The exact location where the Zombie was being reported was on the call to "addGestureRecognizers()" which was being called from setupSlidingDrawer() which was in turn being called from the init function.
I have attached an image of the break point before and after the Zombie call. I have been pulling my hair all day looking at this and keep drawing a blank.
As a work around (hack) I have made the deleteView a instance variable and that seems to keep the class from releasing as the retain count is not decremented.
I feel like like the code for my collection view cell / controller is pretty standard and I am not doing anything crazy.
This seems like it is a Apple bug but I can not seem to find anything on the inter webs to prove it. If
class MomentsViewCell : UICollectionViewCell, UIGestureRecognizerDelegate {
static let reuseIdentifier = "MomentsViewCell"
let imageView = UIImageView()
let activityIndicator = UIActivityIndicatorView()
let shareButton = UIButton()
var shareCallback: (() -> ())?
var isSwiped = false
let overlayViewTag = 999
var delegate: MomentsViewController?
let shareButtonLength: CGFloat = 44
lazy var drawerWidth: CGFloat = {
self.frame.width * 0.15
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(imageView)
imageView.contentMode = UIViewContentMode.ScaleAspectFit
imageView.snp_makeConstraints { (make) -> Void in
make.centerX.equalTo(self.contentView.snp_centerX)
make.width.equalTo(self.contentView.snp_width)
make.top.equalTo(self.snp_top)
make.bottom.equalTo(self.snp_bottom)
}
contentView.addSubview(activityIndicator)
activityIndicator.hidesWhenStopped = true
activityIndicator.snp_makeConstraints { (make) -> Void in
make.center.equalTo(self.snp_center)
}
let shareImage = UIImage(named: "share-moment")
shareButton.setImage(shareImage, forState: .Normal)
shareButton.addTarget(self, action: "didTapShareButton", forControlEvents: .TouchUpInside)
shareButton.enabled = false
shareButton.alpha = 0.0
imageView.addSubview(shareButton)
imageView.userInteractionEnabled = true
shareButton.snp_makeConstraints { (make) -> Void in
let size = CGSizeMake(shareButtonLength, shareButtonLength)
var offset = shareButtonLength / 2
if let imageLength = shareImage?.size.height {
offset = (shareButtonLength - imageLength) / 2
}
make.bottom.equalTo(self.imageView).multipliedBy(0.95).offset(offset)
make.right.equalTo(self.imageView).multipliedBy(0.95).offset(offset)
make.size.equalTo(size)
}
setupSlidingDrawer()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepareForReuse() {
super.prepareForReuse()
imageView.image = nil
exitDeleteMode()
}
func enableSharing() {
shareButton.enabled = true
shareButton.alpha = 1.0
}
func didTapShareButton() {
shareCallback?()
}
func setupSlidingDrawer() {
let deleteView = UIView(frame: CGRectMake(self.frame.width - drawerWidth, self.frame.origin.y, drawerWidth, self.frame.height))
deleteView.backgroundColor = UIColor.whiteColor()
let deleteGradientLayer = CAGradientLayer()
deleteGradientLayer.frame = deleteView.bounds
deleteGradientLayer.colors = [UIColor(hex: 0xE8557C).CGColor, UIColor(hex: 0xCC2B49).CGColor]
deleteView.layer.insertSublayer(deleteGradientLayer, atIndex: 0)
let trashButton = UIButton()
trashButton.setImage(UIImage(named: "trash_can"), forState: UIControlState.Normal)
trashButton.addTarget(self, action: Selector("didPressDelete"), forControlEvents: .TouchUpInside)
deleteView.addSubview(trashButton)
deleteView.bringSubviewToFront(trashButton)
trashButton.snp_makeConstraints(closure: { (make) -> Void in
make.center.equalTo(deleteView.snp_center)
make.width.equalTo(deleteView.snp_width).multipliedBy(0.354)
make.height.equalTo(deleteView.snp_height).multipliedBy(0.07)
})
contentView.addSubview(deleteView)
deleteView.snp_makeConstraints(closure: { (make) -> Void in
make.left.equalTo(self.imageView.snp_right)
make.height.equalTo(self.contentView.snp_height)
make.width.equalTo(drawerWidth)
})
addGestureRecognizers()
}
func addGestureRecognizers() {
let swipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: Selector("didSwipeCell:"))
swipeGestureRecognizer.delegate = self
swipeGestureRecognizer.direction = .Left
self.addGestureRecognizer(swipeGestureRecognizer)
}
class MomentsViewController: ContainerSubController, UICollectionViewDelegate, UICollectionViewDataSource {
var moments: [Moment] = []
let layout = UICollectionViewFlowLayout()
var collectionView = UICollectionView(frame: CGRectZero, collectionViewLayout: UICollectionViewFlowLayout())
let headerIdentifier = "headerCellIdentifier"
let headerLabelText = "Moments"
let headerCellHeight: CGFloat = 103.0
let noMomentsLabelText = "It's looking pretty empty in here! Assign a Moments action (Share Moment To Twitter) to a Hot Key to get started."
let noMomentsReuseIdentifier = "NoMoments"
var currentSwipedCellIndexPath: NSIndexPath?
override func viewDidLoad() {
super.viewDidLoad()
layout.minimumLineSpacing = 0
collectionView = UICollectionView(frame: view.frame, collectionViewLayout: layout)
collectionView.showsVerticalScrollIndicator = false
collectionView.backgroundColor = UIColor.clearColor()
collectionView.registerClass(MomentsViewCell.self, forCellWithReuseIdentifier: MomentsViewCell.reuseIdentifier)
collectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: noMomentsReuseIdentifier)
collectionView.registerClass(UICollectionViewCell.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: headerIdentifier)
collectionView.delegate = self
collectionView.dataSource = self
view.backgroundColor = UIColor.blackColor()
view.addSubview(collectionView)
collectionView.snp_makeConstraints { (make) -> Void in
make.height.equalTo(view)
make.width.equalTo(view)
make.center.equalTo(view)
}
setupTransitionToMainButton()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
refreshMoments()
collectionView.reloadData()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "handleMomentSavedNotifcation", name: MomentNotifcation.MomentSaved.rawValue, object: nil)
}
//MARK: UICollectionViewDataSource
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
guard let momentsViewCell = collectionView.dequeueReusableCellWithReuseIdentifier(MomentsViewCell.reuseIdentifier, forIndexPath: indexPath) as? MomentsViewCell, moment = moments[safe:indexPath.row] else {
return MomentsViewCell()
}
In your guard, make sure to return momentsViewCell, the one you dequeued before.
for example:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
if let momentsViewCell = collectionView.dequeueReusableCellWithReuseIdentifier(MomentsViewCell.reuseIdentifier, forIndexPath: indexPath) as? MomentsViewCell {
return momentsViewCell
else {
return MomentsViewCell()
}
Edit
As I see the screenshots, the log is warning about optimizations. The whole assignment might not work because the variable is not used later on.

Resources