Value of type 'SSBadgeButton' has no member 'animationZoom' - swift

I have following productviewcontroller which says "Value of type 'SSBadgeButton' has no member 'animationZoom'" -
import UIKit
class ProductViewController: UIViewController, UITableViewDataSource,
UITableViewDelegate {
let notificationButton = SSBadgeButton()
let rightbarbuttonimage = UIImage(named:"ic_cart")
fileprivate var cart = Cart()
let scrollView = UIScrollView()
let sections = ["Section A", "Section B","Section C", "Section D","Section E","Section F","Section G","Section H", "Section I","Section J","Section K","Section L"]
let rowspersection = [2,3,1,2,2,3,3,1,4,2,1,2]
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
self.tableView.backgroundColor = UIColor.gray
//Add and setup scroll view
self.tableView.addSubview(self.scrollView)
self.scrollView.translatesAutoresizingMaskIntoConstraints = false;
//Constrain scroll view
self.scrollView.leadingAnchor.constraint(equalTo: self.tableView.leadingAnchor, constant: 20).isActive = true;
self.scrollView.topAnchor.constraint(equalTo: self.tableView.topAnchor, constant: 20).isActive = true;
self.scrollView.trailingAnchor.constraint(equalTo: self.tableView.trailingAnchor, constant: -20).isActive = true;
self.scrollView.bottomAnchor.constraint(equalTo: self.tableView.bottomAnchor, constant: -20).isActive = true;
// customising rightBarButtonItems as notificationbutton
notificationButton.frame = CGRect(x: 0, y: 0, width: 44, height: 44)
notificationButton.setImage(UIImage(named: "ic_cart")?.withRenderingMode(.alwaysTemplate), for: .normal)
notificationButton.badgeEdgeInsets = UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 15)
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: notificationButton)
//following register is needed because I have rightbarbuttonitem customised as uibutton i.e. notificationbutton
notificationButton.addTarget(self, action: #selector(self.registerTapped(_:)), for: .touchUpInside)
}
#objc func registerTapped(_ sender: UIButton) {
self.performSegue(withIdentifier: "showCart", sender: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//Workaround to avoid the fadout the right bar button item
self.navigationItem.rightBarButtonItem?.isEnabled = false
self.navigationItem.rightBarButtonItem?.isEnabled = true
//Update cart if some items quantity is equal to 0 and reload the product table and right button bar item
cart.updateCart()
//self.navigationItem.rightBarButtonItem?.title = "Checkout (\(cart.items.count))"
notificationButton.badge = String(cart.items.count)// making badge equal to no.ofitems in cart
tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// this segue to transfer data
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showCart" {
if let cartViewController = segue.destination as? CartViewController {
cartViewController.cart = self.cart
}
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return productMap.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return productMap[section]?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let product = productMap[indexPath.section]![indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "ProductTableViewCell") as! ProductTableViewCell
cell.imageView?.image = product.imagename
cell.delegate = self as CartDelegate
cell.setButton(state: self.cart.contains(product: product))
return cell
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 44
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch(section) {
case 0: return "Section A"
case 1: return "Section B"
case 2: return "Section C"
case 3: return "Section D"
case 4: return "Section E"
case 5: return "Section F"
case 6: return "Section G"
case 7: return "Section H"
case 8: return "Section I"
case 9: return "Section J"
case 10: return "Section K"
case 11: return "Section L"
default: return ""
}
}
}
extension ProductViewController: CartDelegate {
// MARK: - CartDelegate
func updateCart(cell: ProductTableViewCell) {
guard let indexPath = tableView.indexPath(for: cell) else { return }
let product = productMap[indexPath.section]![indexPath.row]
var selectedIndexPaths = [IndexPath]()
if selectedIndexPaths.contains(indexPath) {
if let index = selectedIndexPaths.firstIndex(of: indexPath) {
selectedIndexPaths.remove(at: index)
removeProductFromCart(indexPath: indexPath)
}
} else {
selectedIndexPaths.append(indexPath)
addProductToCart(indexPath: indexPath)
}
addProductToCart(indexPath: indexPath)
//Update Cart with product
cart.updateCart(with: product)
self.navigationItem.rightBarButtonItem?.title = "Checkout (\(cart.items.count))"
notificationButton.badge = String(cart.items.count) // making badge equal to noofitems in cart
}
func addProductToCart(indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) as? ProductTableViewCell {
if let imageView = cell.imagename {
let initialImageViewFrame = imageView.convert(imageView.frame, to: self.view)
let targetImageViewFrame = self.notificationButton.frame
let imgViewTemp = UIImageView(frame: initialImageViewFrame)
imgViewTemp.clipsToBounds = true
imgViewTemp.contentMode = .scaleAspectFill
imgViewTemp.image = imageView.image
self.view.addSubview(imgViewTemp)
UIView.animate(withDuration: 1.0, animations: {
imgViewTemp.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
}) { _ in
UIView.animate(withDuration: 0.5, animations: {
imgViewTemp.transform = CGAffineTransform(scaleX: 0.2, y: 0.2).rotated(by: CGFloat(Double.pi))
imgViewTemp.frame = targetImageViewFrame
}) { _ in
imgViewTemp.removeFromSuperview()
UIView.animate(withDuration: 1.0, animations: {
self.notificationButton.transform = CGAffineTransform(scaleX: 1.4, y: 1.4)
}, completion: {_ in
self.notificationButton.transform = CGAffineTransform.identity
})
}
}
}
}
}
func removeProductFromCart(indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) as? ProductTableViewCell {
if let imageView = cell.imagename {
let initialImageViewFrame = self.notificationButton.frame
let targetImageViewFrame = imageView.convert(imageView.frame, to: self.view)
let imgViewTemp = UIImageView(frame: initialImageViewFrame)
imgViewTemp.clipsToBounds = true
imgViewTemp.contentMode = .scaleAspectFill
imgViewTemp.image = imageView.image
self.view.addSubview(imgViewTemp)
var initialTransform = CGAffineTransform.identity
initialTransform = initialTransform.scaledBy(x: 0.2, y: 0.2)
initialTransform = initialTransform.rotated(by: CGFloat(Double.pi))
UIView.animate(withDuration: 0.5, animations: {
self.notificationButton.animationZoom(scaleX: 1.4, y: 1.4) ***//Error - Value of type 'SSBadgeButton' has no member 'animationZoom'***
imgViewTemp.transform = initialTransform
}) { _ in
UIView.animate(withDuration: 1, animations: {
self.notificationButton.animationZoom(scaleX: 1, y: 1)
imgViewTemp.transform = CGAffineTransform.identity
imgViewTemp.frame = targetImageViewFrame
}) { _ in
imgViewTemp.removeFromSuperview()
}
}
}
}
}
}
This is my code for "SSBadgeButton" -
import UIKit
class SSBadgeButton: UIButton {
var badgeLabel = UILabel()
var badge: String? {
didSet {
addBadgeToButon(badge: badge)
}
}
public var badgeBackgroundColor = UIColor.red {
didSet {
badgeLabel.backgroundColor = badgeBackgroundColor
}
}
public var badgeTextColor = UIColor.white {
didSet {
badgeLabel.textColor = badgeTextColor
}
}
public var badgeFont = UIFont.systemFont(ofSize: 12.0) {
didSet {
badgeLabel.font = badgeFont
}
}
public var badgeEdgeInsets: UIEdgeInsets? {
didSet {
addBadgeToButon(badge: badge)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
addBadgeToButon(badge: nil)
}
func addBadgeToButon(badge: String?) {
badgeLabel.text = badge
badgeLabel.textColor = badgeTextColor
badgeLabel.backgroundColor = badgeBackgroundColor
badgeLabel.font = badgeFont
badgeLabel.sizeToFit()
badgeLabel.textAlignment = .center
let badgeSize = badgeLabel.frame.size
let height = max(18, Double(badgeSize.height) + 5.0)
let width = max(height, Double(badgeSize.width) + 10.0)
var vertical: Double?, horizontal: Double?
if let badgeInset = self.badgeEdgeInsets {
vertical = Double(badgeInset.top) - Double(badgeInset.bottom)
horizontal = Double(badgeInset.left) - Double(badgeInset.right)
let x = (Double(bounds.size.width) - 10 + horizontal!)
let y = -(Double(badgeSize.height) / 2) - 10 + vertical!
badgeLabel.frame = CGRect(x: x, y: y, width: width, height: height)
} else {
let x = self.frame.width - CGFloat((width / 2.0))
let y = CGFloat(-(height / 2.0))
badgeLabel.frame = CGRect(x: x, y: y, width: CGFloat(width), height: CGFloat(height))
}
badgeLabel.layer.cornerRadius = badgeLabel.frame.height/2
badgeLabel.layer.masksToBounds = true
addSubview(badgeLabel)
badgeLabel.isHidden = badge != nil ? false : true
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.addBadgeToButon(badge: nil)
fatalError("init(coder:) has not been implemented")
}
}
Earlier, it used to work fine. It used to zoom the animation Now, I don't know why it does not work fine ? please help me with this. The code also seems okay. still, it does not work fine.

Related

Xcode Visual Memory Debugger. What does it mean if some object is not released and this object and is a not UIViewController

When I close all VC and go back to my root I see that some element views and cells, like HeaderViewNew, DisposalsShimmering, exist in a heap, these elements are declared like lazy var, why is this element not released from memory if I close VC that use it, it is normal, or I did some mistake?
I know that if I have a few examples of VC in memory this is a retail cycle, but with this element inside the heap hierarchy I am a little confused, and using info inside the Memory graph (main window) I can't solve this problem
Example of an object that has not been released:
import UIKit
protocol HeaderMenuOptionSelected: AnyObject {
func menuSelected(index: Int, title: String)
}
class HeadeViewMenu: UIView, UITableViewDelegate, UITableViewDataSource {
private var hiddenRows: Array<Int> = Array()
private var cellSize: CGFloat = 60
var selectedIndex: Int!
var tabBarHeight: CGFloat!
var tabBar: UIView!
let tabBarView = UIView()
var menuHeight: CGFloat = 0
var P_menuHeightConstraint: NSLayoutConstraint!
var menuArr: Array<HeaderMenuListOfOptions> = Array()
weak var delegate: HeaderMenuOptionSelected?
func clearMenuOptions() {
menuArr.removeAll()
P_menu.reloadData()
}
func setupListOfOptions(menuList: [HeaderMenuListOfOptions]) {
menuArr = menuList
P_menu.reloadData()
}
func setupMenuHeight(countOfElement: Int) {
menuHeight = cellSize * CGFloat(countOfElement)
}
// This trick need to use because if user open menu but user level not yet applied, after fetching setting from server need to update menu in menu open, but only ONE time
private var firstTimeOpen = true
func updateMenuHeight() {
guard firstTimeOpen != false else { return }
firstTimeOpen = false
if (P_menuHeightConstraint.constant != 0) {
menuHeight = cellSize * CGFloat(menuArr.count)
P_menuHeightConstraint.constant = menuHeight
UIView.animate(withDuration: 0.2) {
self.layoutIfNeeded()
} completion: { anim in
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
menuArr.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! HeaderMenuCell
// iOS way to set default text label
// var content = cell.defaultContentConfiguration()
// content.text = "test"
// cell.contentConfiguration = content
cell.P_label.text = menuArr[indexPath.row].title
cell.selectionStyle = .none
cell.P_label.isHidden = needHideElement(index: indexPath.row)
cell.P_img.isHidden = needHideElement(index: indexPath.row)
cell.P_countOfElements.isHidden = needHideElement(index: indexPath.row)
if selectedIndex == indexPath.row {
cell.P_img.image = UIImage(named: menuArr[indexPath.row].selectedImg)
cell.P_label.textColor = menuArr[indexPath.row].selectedColor
cell.initCount(count: menuArr[indexPath.row].count)
} else {
cell.P_img.image = UIImage(named: menuArr[indexPath.row].img)
cell.P_label.textColor = menuArr[indexPath.row].unselectedColor
cell.initCount(count: menuArr[indexPath.row].count)
}
return cell
}
func openPageByImitationGesture(index: Int) {
hideMenu()
delegate?.menuSelected(index: index, title: menuArr[index].title)
selectedIndex = index
P_menu.reloadData()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("index menu \(indexPath.row)")
hideMenu()
// FeedbackGenerator.shared.interactionFeedback()
// guard selectedIndex != indexPath.row else { return }
delegate?.menuSelected(index: indexPath.row, title: menuArr[indexPath.row].title)
// let cell = tableView.cellForRow(at: indexPath) as! HeaderMenuCell
selectedIndex = indexPath.row
tableView.reloadData()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return getRowHeight(index: indexPath.row)
}
func tableView(_ tableView: UITableView, didUnhighlightRowAt indexPath: IndexPath) {
print("index unhi....\(indexPath.row)")
}
lazy var P_menu: UITableView = {
let view = UITableView()
view.translatesAutoresizingMaskIntoConstraints = false
view.delegate = self
view.dataSource = self
view.register(HeaderMenuCell.self, forCellReuseIdentifier: "cell")
view.isScrollEnabled = false
view.separatorColor = .clear
view.separatorStyle = .none
return view
}()
lazy var P_menuView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.translatesAutoresizingMaskIntoConstraints = false
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOpacity = 0.2
view.layer.shadowOffset = CGSize(width: 0, height: 5)
view.layer.shadowRadius = 2
return view
}()
lazy var P_backgroundView: UIView = {
let view = UIView()
view.backgroundColor = .black
view.translatesAutoresizingMaskIntoConstraints = false
view.alpha = 0
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(clickAtBackgroundView))
tapGesture.numberOfTapsRequired = 1
tapGesture.numberOfTouchesRequired = 1
view.addGestureRecognizer(tapGesture)
view.isUserInteractionEnabled = true
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.translatesAutoresizingMaskIntoConstraints = false
setupView()
}
deinit {
print("deinit called NewHeaderMenu")
}
func setupView() {
self.isHidden = true
self.addSubview(P_backgroundView)
self.addSubview(P_menuView)
self.P_menuView.addSubview(P_menu)
P_backgroundView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
P_backgroundView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
P_backgroundView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
P_backgroundView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
P_menu.topAnchor.constraint(equalTo: P_menuView.topAnchor).isActive = true
P_menu.leadingAnchor.constraint(equalTo: P_menuView.leadingAnchor).isActive = true
P_menu.trailingAnchor.constraint(equalTo: P_menuView.trailingAnchor).isActive = true
P_menu.bottomAnchor.constraint(equalTo: P_menuView.bottomAnchor).isActive = true
P_menuView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
P_menuView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
P_menuView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
P_menuHeightConstraint = P_menuView.heightAnchor.constraint(equalToConstant: 0)
P_menuHeightConstraint.isActive = true
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
func openMenu() {
self.isHidden = false
UIView.animate(withDuration: 0.1) {
self.P_backgroundView.alpha = 0.2
self.hideTabBar()
} completion: { anim in
if (anim == true) {
self.P_menuHeightConstraint.constant = self.menuHeight
UIView.animate(withDuration: 0.2) {
self.layoutIfNeeded()
} completion: { anim in
}
}
}
}
func hideMenu() {
P_menuHeightConstraint.constant = 0
UIView.animate(withDuration: 0.2) {
self.layoutIfNeeded()
} completion: { anim in
if (anim == true) {
UIView.animate(withDuration: 0.1) {
self.P_backgroundView.alpha = 0
self.showTabBar()
} completion: { anim in
if (anim == true) {
self.isHidden = true
}
}
}
}
}
func needToHideRows(rows: [Int]) {
hiddenRows = rows
let countOfElements = (menuArr.count - rows.count)
print("Menu count of elements \(countOfElements)")
setupMenuHeight(countOfElement: countOfElements)
P_menu.reloadData()
}
func unhideAllElements(count: Int) {
hiddenRows = []
setupMenuHeight(countOfElement: count)
P_menu.reloadData()
}
func getRowHeight(index: Int) -> CGFloat {
var size: CGFloat = menuHeight / CGFloat(menuArr.count - hiddenRows.count)
hiddenRows.forEach { obj in
if (index == obj) {
size = 0
}
}
return size
}
func needHideElement(index: Int) -> Bool {
var needToHide = false
hiddenRows.forEach { obj in
if (index == obj) {
needToHide = true
}
}
return needToHide
}
func setupTabBar(view: UIView) {
guard tabBarHeight != nil else {
return
}
tabBar = view
tabBar.addSubview(tabBarView)
tabBarView.translatesAutoresizingMaskIntoConstraints = false
tabBarView.backgroundColor = .black
tabBarView.heightAnchor.constraint(equalToConstant: tabBarHeight).isActive = true
tabBarView.leadingAnchor.constraint(equalTo: tabBar.leadingAnchor).isActive = true
tabBarView.trailingAnchor.constraint(equalTo: tabBar.trailingAnchor).isActive = true
tabBarView.bottomAnchor.constraint(equalTo: tabBar.bottomAnchor).isActive = true
tabBarView.alpha = 0
}
func hideTabBar() {
UIView.animate(withDuration: 0.1) {
self.tabBarView.alpha = 0.2
}
}
func showTabBar() {
UIView.animate(withDuration: 0.1) {
self.tabBarView.alpha = 0
}
}
#objc func clickAtBackgroundView() {
hideMenu()
delegate?.menuSelected(index: selectedIndex, title: menuArr[selectedIndex].title)
}
func selectOptionNonProgrammatically(index: Int) {
// This function need for fixind problem when user open app and app had list of sevec filters for disposal tab
hideMenu()
// delegate?.menuSelected(index: index, title: title)
delegate?.menuSelected(index: index, title: menuArr[index].title)
}
func updateCounter(index: Int, count: Int?) {
guard count != nil && count != 0 else { return }
menuArr[index].count = count
P_menu.reloadData()
}
}
Inside VC that contained this element I do next:
1. Init
lazy var P_headerViewNewMenu: HeadeViewMenu = {
let view = HeadeViewMenu()
view.delegate = self
return view
}()
2. Deinit
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
P_headerViewNewMenu.delegate = nil
}
3. Init constraints
self.view.addSubview(P_headerViewNewMenu)
P_headerViewNewMenu.topAnchor.constraint(equalTo: P_headerViewNew.bottomAnchor).isActive = true
P_headerViewNewMenu.leadingAnchor.constraint(equalTo: P_headerViewNew.leadingAnchor).isActive = true
P_headerViewNewMenu.trailingAnchor.constraint(equalTo: P_headerViewNew.trailingAnchor).isActive = true
P_headerViewNewMenu.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
P_headerViewNewMenu.tabBarHeight = self.tabBarController?.tabBar.frame.height
P_headerViewNewMenu.setupTabBar(view: (self.tabBarController?.view)!)
I found the problem with be help of matt, years of experience of asking the right question ;) Problem was inside P_headerViewNewMenu.setupTabBar(view: (self.tabBarController?.view)!)
link to the object was not released.
Because VC was deallocated, and all objects continue to be in the heap, I haven't been understood that these are all objects that not called deinit, but VC was released from memory

How to deselect all buttons when one of them is selected

I have a tableview and inside one of my rows I have buttons. I want to deselect all buttons when one is selected and change the background color to the red when button is selected. I saw lots of example but I couldn't do it in my own code.
func configure(_ modelArray : [UnitAndColors], colorTitle:String, packingTitle:String) {
self.unitStackView.removeAllArrangedSubviews()
self.arrayUnitsAndColor?.removeAll()
self.arrayUnitsAndColor = modelArray
let filteredArray = self.arrayUnitsAndColor?.unique { $0.colorDesc }
var i : Int = 0
filteredArray?.forEach { units in
let vw = self.createUnits(units, tag: i)
self.unitStackView.addArrangedSubview(vw)
vw.snp.makeConstraints {
$0.size.equalTo(40.0)
}
i = i + 1
}
}
func createUnits(_ model : UnitAndColors, tag: Int) -> UIStackView {
let stackViewMain = UIStackView()
stackViewMain.axis = .horizontal
stackViewMain.spacing = 4
let labelPackingUnit = UIButton()
labelPackingUnit.backgroundColor = Colors().colorWhite
labelPackingUnit.tag = tag
labelPackingUnit.setTitleColor(Colors().colorRed, for: .normal)
labelPackingUnit.addTarget(self, action: #selector(selectUnit(_:)), for: .touchUpInside)
labelPackingUnit.titleLabel?.font = UIFont.fontBold16
labelPackingUnit.contentHorizontalAlignment = .center
labelPackingUnit.setBorder(width: 1, color: Colors().colorRed)
labelPackingUnit.setCornerRound(value: 20.0)
labelPackingUnit.setTitle(model.unitDesc, for: .normal)
stackViewMain.addArrangedSubview(labelPackingUnit)
labelPackingUnit.snp.makeConstraints {
$0.size.equalTo(40)
}
return stackViewMain
}
#objc private func selectButton(_ sender : UIButton) {
let tag : Int = sender.tag
guard let model : UnitAndColors = self.arrayUnitsAndColor?.filter({ $0.colorDesc == selectedColorName })[tag] else { return }
selectedUnit = model.unitDesc ?? ""
delegate?.changePrice(selectedPrice: model.modelPrice, arrayUnitsAndColor ?? [])
}
It's pretty frustrating to understand what's happening in your code, but I think that's what you're looking for:
#objc private func selectButton(_ sender : UIButton) {
let tag : Int = sender.tag
guard let model: UnitAndColors = self.arrayUnitsAndColor?.filter({ $0.colorDesc == selectedColorName })[tag] else { return }
selectedUnit = model.unitDesc ?? ""
for stackView in unitStackView.arrangedSubviews as? [UIStackView] ?? [] {
guard let button = stackView.arrangedSubviews.first as? UIButton else {
return
}
button.isSelected = false
button.backgroundColor = .clear
}
selectedUnit.isSelected = true
selectedUnit.backgroundColor = .red
delegate?.changePrice(selectedPrice: model.modelPrice, arrayUnitsAndColor ?? [])
}
var selectedRows: [Int] = [Int]()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.allowMultipleSelection = true
}
func selectAll(){
for i in 0..<totalRows.count{
selectedRows.append(i)
let indexPath = IndexPath(row: i, section: 0)
self.tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
}
}
func deselectAll(){
for i in 0..<totalRows.count{
selectedRows.append(i)
let indexPath = IndexPath(row: i, section: 0)
self.tableView.deselectRow(at: indexPath, animated: true)
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
selectedRows.append(indexPath.row)
print(selectedRows)
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let index = selectedRows.firstIndex(of: indexPath.row) {
selectedRows.remove(at: index)
}
print(selectedRows)
if selectedRows.isEmpty{
}
}
}
class TableViewCell: UITableViewCell{
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
if (selected) {
print("selected")
contentView.backgroundColor = .red
} else {
contentView.backgroundColor = .red
}
}
}

Style content in a TableView without causing the scrolling to lag

I have a TableView, with about 15 to 20 displayed cells. The cell has a Label with the following class:
import Foundation
import UIKit
class RoundedLabel: UILabel {
var inset: CGFloat = 16
override func drawText(in rect: CGRect) {
let insets = UIEdgeInsets(top: 2, left: 2, bottom: 2, right: 2)
super.drawText(in: rect.inset(by: insets))
}
override func layoutSubviews() {
super.layoutSubviews()
updateCornerRadius()
}
override var intrinsicContentSize: CGSize {
let size = super.intrinsicContentSize
return CGSize(
width: size.width + inset,
height: size.height
)
}
#IBInspectable var rounded: Bool = false {
didSet {
updateCornerRadius()
}
}
func updateCornerRadius() {
layer.cornerRadius = rounded ? frame.size.height / 2 : 0
layer.masksToBounds = true
}
}
In my VC I have the following (I have to TableViews in one VC):
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == tableViewMainLatest {
let cell = tableViewMainLatest.dequeueReusableCell(withIdentifier: "cellMainLatest", for: indexPath) as! MainLatestTableViewCell
let postDate = posts[indexPath.row].postDate ?? 0
let formattedPostDate = Date(timeIntervalSince1970: postDate)
let timeAgo = formattedPostDate.timeAgo(numericDates: false)
let postCity = posts[indexPath.row].postFromCity ?? "?"
let postCountry = posts[indexPath.row].postFromCountry ?? "?"
let postComments = posts[indexPath.row].comments ?? 0
let maxPostComments: String?
// Only show the number if comment amount is less than 100
if postComments > 99 {
maxPostComments = "99+"
} else {
maxPostComments = String(postComments)
}
cell.labelPostDate.text = timeAgo
cell.labelPostFrom.text = postCity + ", " + postCountry
cell.labelAmountComments.text = maxPostComments
return cell
} else if tableView == tableViewCategories {
let cell = tableViewCategories.dequeueReusableCell(withIdentifier: "cellMainCategories", for: indexPath) as! MainApplicationCategoriesTableViewCell
cell.labelCategories.text = pseudo[indexPath.row] as? String
cell.alpha = 0.55
UIView.animate(withDuration: 0.5, animations: {
cell.alpha = 1
})
return cell
}
return UITableViewCell()
}
My CustomCell:
class MainApplicationCategoriesTableViewCell: UITableViewCell {
// Storyboard
#IBOutlet weak var labelCategories: UILabel! {
didSet {
labelCategories.layer.borderWidth = 1
labelCategories.layer.borderColor = UIColor(red:0.88, green:0.88, blue:0.88, alpha:1.0).cgColor
}
}
override func awakeFromNib() {
super.awakeFromNib()
self.selectionStyle = .none
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
When I use this piece of code:
// Storyboard
#IBOutlet weak var labelCategories: UILabel! {
didSet {
labelCategories.layer.borderWidth = 1
labelCategories.layer.borderColor = UIColor(red:0.88, green:0.88, blue:0.88, alpha:1.0).cgColor
}
}
The scrolling of the TableView is lagging. Where do I have to apply the borderWidth / borderColor, to still have a good user experience without lagging?

Swift Toolbar button triggers a exec_bad_instruction only on one scene

I'm changing my app to start to use toolbar buttons for the main pages instead of a menu. All of the menu links work and the toolbar buttons work on every page except one. When I click on the button the app freezes, and Xcode brings me to this line:
'weak var itemDetailPage = segue.destination as? ItemDetailViewController' with this error:
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
All the variables are nil.
Any help would be monumental!
Here is the code for the view controller it is specifically happening on:
import UIKit
import AVFoundation
import Alamofire
#objc protocol FavRefreshLikeCountsDelegate: class {
func updateLikeCounts(_ likeCount: Int)
}
#objc protocol FavRefreshReviewCountsDelegate: class {
func updateReviewCounts(_ reviewCount: Int)
}
class FavouriteItemsViewController: UICollectionViewController {
var populationItems = false
var selectedSubCategoryId:Int = 0
var selectedCityId:Int = 1
var selectedCityLat: String!
var selectedCityLng: String!
var items = [ItemModel]()
var currentPage = 0
var loginUserId:Int = 0
weak var selectedCell : AnnotatedPhotoCell!
#IBOutlet weak var menuButton: UIBarButtonItem!
var defaultValue: CGPoint!
override func viewDidLoad() {
if self.revealViewController() != nil {
menuButton.target = self.revealViewController()
menuButton.action = #selector(SWRevealViewController.revealToggle(_:))
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
collectionView!.register(AnnotatedPhotoCell.classForCoder(), forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: "AnnotatedPhotoCell")
if let layout = collectionView?.collectionViewLayout as? PinterestLayout {
layout.delegate = self
}
loadLoginUserId()
loadFavouriteItems()
defaultValue = collectionView?.frame.origin
animateCollectionView()
}
override func viewDidAppear(_ animated: Bool) {
updateNavigationStuff()
}
override var preferredStatusBarStyle : UIStatusBarStyle {
return UIStatusBarStyle.lightContent
}
override func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
loadFavouriteItems()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
weak var itemCell = sender as? AnnotatedPhotoCell
weak var itemDetailPage = segue.destination as? ItemDetailViewController
itemDetailPage!.selectedItemId = Int((itemCell!.item?.itemId)!)!
itemDetailPage!.selectedShopId = Int((itemCell!.item?.itemShopId)!)!
itemDetailPage!.favRefreshLikeCountsDelegate = self
itemDetailPage!.favRefreshReviewCountsDelegate = self
selectedCell = itemCell
updateBackButton()
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
var cell : AnnotatedPhotoCell
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "AnnotatedPhotoCell", for: indexPath) as! AnnotatedPhotoCell
cell.item = items[(indexPath as NSIndexPath).item]
let imageURL = configs.imageUrl + items[(indexPath as NSIndexPath).item].itemImage
cell.imageView?.loadImage(urlString: imageURL) { (status, url, image, msg) in
if(status == STATUS.success) {
print(url + " is loaded successfully.")
self.items[indexPath.item].itemImageBlob = image
}else {
print("Error in loading image" + msg)
}
}
cell.imageView.alpha = 0
cell.captionLabel.alpha = 0
UIView.animate(withDuration: 1, delay: 0, options: UIViewAnimationOptions.curveEaseIn, animations: {
cell.imageView.alpha = 1.0
cell.captionLabel.alpha = 1.0
}, completion: nil)
return cell
}
func updateBackButton() {
let backItem = UIBarButtonItem()
backItem.title = ""
navigationItem.backBarButtonItem = backItem
}
func updateNavigationStuff() {
self.navigationController?.navigationBar.topItem?.title = language.favouritePageTitle
self.navigationController?.navigationBar.titleTextAttributes = [ NSAttributedStringKey.font: UIFont(name: customFont.boldFontName, size: CGFloat(customFont.boldFontSize))!, NSAttributedStringKey.foregroundColor:UIColor.white]
self.navigationController!.navigationBar.barTintColor = Common.instance.colorWithHexString(configs.barColorCode)
}
func loadLoginUserId() {
let plistPath = Common.instance.getLoginUserInfoPlist()
let myDict = NSDictionary(contentsOfFile: plistPath)
if let dict = myDict {
loginUserId = Int(dict.object(forKey: "_login_user_id") as! String)!
print("Login User Id : " + String(loginUserId))
} else {
print("WARNING: Couldn't create dictionary from LoginUserInfo.plist! Default values will be used!")
}
}
func loadFavouriteItems() {
if self.currentPage == 0 {
_ = EZLoadingActivity.show("Loading...", disableUI: true)
}
Alamofire.request(APIRouters.GetFavouriteItems( loginUserId, configs.pageSize, self.currentPage)).responseCollection {
(response: DataResponse<[Item]>) in
if self.currentPage == 0 {
_ = EZLoadingActivity.hide()
}
if response.result.isSuccess {
if let items: [Item] = response.result.value {
if(items.count > 0) {
for item in items {
let oneItem = ItemModel(item: item)
self.items.append(oneItem)
self.currentPage+=1
}
}
}
self.collectionView!.reloadData()
} else {
print(response)
}
}
}
func animateCollectionView() {
moveOffScreen()
UIView.animate(withDuration: 1, delay: 0,
usingSpringWithDamping: 0.9,
initialSpringVelocity: 0.9, options: UIViewAnimationOptions.curveEaseOut, animations: {
self.collectionView?.frame.origin = self.defaultValue
}, completion: nil)
}
fileprivate func moveOffScreen() {
collectionView?.frame.origin = CGPoint(x: (collectionView?.frame.origin.x)!,
y: (collectionView?.frame.origin.y)! + UIScreen.main.bounds.size.height)
}
}
extension FavouriteItemsViewController : PinterestLayoutDelegate {
func collectionView(_ collectionView:UICollectionView, heightForPhotoAtIndexPath indexPath:IndexPath , withWidth width:CGFloat) -> CGFloat {
let item = items[(indexPath as NSIndexPath).item]
let boundingRect = CGRect(x: 0, y: 0, width: width, height: CGFloat(MAXFLOAT))
let size = CGSize(width: item.itemImageWidth, height: item.itemImageHeight)
var rect : CGRect
if item.itemImageBlob != nil {
rect = AVMakeRect(aspectRatio: item.itemImageBlob!.size, insideRect: boundingRect)
}else{
rect = AVMakeRect(aspectRatio: size, insideRect: boundingRect)
}
return rect.size.height
}
func collectionView(_ collectionView: UICollectionView, heightForAnnotationAtIndexPath indexPath: IndexPath, withWidth width: CGFloat) -> CGFloat {
let annotationPadding = CGFloat(4)
let annotationHeaderHeight = CGFloat(17)
let height = annotationPadding + annotationHeaderHeight + annotationPadding + 30
return height
}
}
extension FavouriteItemsViewController : FavRefreshLikeCountsDelegate, FavRefreshReviewCountsDelegate {
func updateLikeCounts(_ likeCount: Int) {
if selectedCell != nil {
selectedCell.lblLikeCount.text = "\(likeCount)"
}
}
func updateReviewCounts(_ reviewCount: Int) {
if selectedCell != nil {
selectedCell.lblReviewCount.text = "\(reviewCount)"
}
}
}
You should try be checking your ItemDetailViewController.
for example:
if segue.identifier == "ItemDetailVC" {
weak var itemCell = sender as? AnnotatedPhotoCell
weak var itemDetailPage = segue.destination as? ItemDetailViewController
...
}

swift 3 table view with slide out menu

I got problem with making table view on the same view with slide menu, could you help me how to do that, I created view controller and embeded navigation controller, now I just want add table vie behind the slide menu and show table view with two section and show data with one custom cell.
#Egle Matutyte, I am supposing that you have done all work except SlideBar.
I am providing code for SlideBar. Just add and try.
First Add the SideBar class i.e. below without any change
import UIKit
#objc protocol SideBarDelegate{
func sideBarDidSelectButtonAtIndex(_ index:Int)
#objc optional func sideBarWillClose()
#objc optional func sideBarWillOpen()
}
class SideBar: NSObject, SideBarTableViewControllerDelegate {
let barWidth:CGFloat = 150.0
let sideBarTableViewTopInset:CGFloat = 64.0
let sideBarContainerView:UIView = UIView()
let sideBarTableViewController:SideBarTableViewController = SideBarTableViewController()
var originView:UIView = UIView()
var animator:UIDynamicAnimator!
var delegate:SideBarDelegate?
var isSideBarOpen:Bool = false
override init() {
super.init()
}
init(sourceView:UIView, menuItems:Array<String>){
super.init()
originView = sourceView
sideBarTableViewController.tableData = menuItems
setupSideBar()
animator = UIDynamicAnimator(referenceView: originView)
let showGestureRecognizer:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(SideBar.handleSwipe(_:)))
showGestureRecognizer.direction = UISwipeGestureRecognizerDirection.right
originView.addGestureRecognizer(showGestureRecognizer)
let hideGestureRecognizer:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(SideBar.handleSwipe(_:)))
hideGestureRecognizer.direction = UISwipeGestureRecognizerDirection.left
originView.addGestureRecognizer(hideGestureRecognizer)
}
func setupSideBar(){
//sideBarContainerView.frame = CGRect(x: -barWidth - 1, y: originView.frame.origin.y, width: barWidth, height: originView.frame.size.height)
sideBarContainerView.frame = CGRect(x: -barWidth - 1, y: sideBarTableViewTopInset, width: barWidth, height: originView.frame.size.height)
sideBarContainerView.backgroundColor = UIColor.clear
sideBarContainerView.clipsToBounds = false
originView.addSubview(sideBarContainerView)
let blurView:UIVisualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.light))
blurView.frame = sideBarContainerView.bounds
sideBarContainerView.addSubview(blurView)
sideBarTableViewController.delegate = self
sideBarTableViewController.tableView.frame = sideBarContainerView.bounds
sideBarTableViewController.tableView.clipsToBounds = false
sideBarTableViewController.tableView.separatorStyle = UITableViewCellSeparatorStyle.none
sideBarTableViewController.tableView.backgroundColor = UIColor.clear
sideBarTableViewController.tableView.scrollsToTop = false
//sideBarTableViewController.tableView.contentInset = UIEdgeInsetsMake(sideBarTableViewTopInset, 0, 0, 0)
sideBarTableViewController.tableView.contentInset = UIEdgeInsetsMake(1, 0, 0, 0)
sideBarTableViewController.tableView.reloadData()
sideBarContainerView.addSubview(sideBarTableViewController.tableView)
}
func handleSwipe(_ recognizer:UISwipeGestureRecognizer){
if recognizer.direction == UISwipeGestureRecognizerDirection.left{
showSideBar(false)
delegate?.sideBarWillClose?()
}else{
showSideBar(true)
delegate?.sideBarWillOpen?()
}
}
func showSideBar(_ shouldOpen:Bool){
animator.removeAllBehaviors()
isSideBarOpen = shouldOpen
let gravityX:CGFloat = (shouldOpen) ? 0.5 : -0.5
let magnitude:CGFloat = (shouldOpen) ? 20 : -20
let boundaryX:CGFloat = (shouldOpen) ? barWidth : -barWidth - 1
let gravityBehavior:UIGravityBehavior = UIGravityBehavior(items: [sideBarContainerView])
gravityBehavior.gravityDirection = CGVector(dx: gravityX, dy: 0)
animator.addBehavior(gravityBehavior)
let collisionBehavior:UICollisionBehavior = UICollisionBehavior(items: [sideBarContainerView])
collisionBehavior.addBoundary(withIdentifier: "sideBarBoundary" as NSCopying, from: CGPoint(x: boundaryX, y: 20), to: CGPoint(x: boundaryX, y: originView.frame.size.height))
animator.addBehavior(collisionBehavior)
let pushBehavior:UIPushBehavior = UIPushBehavior(items: [sideBarContainerView], mode: UIPushBehaviorMode.instantaneous)
pushBehavior.magnitude = magnitude
animator.addBehavior(pushBehavior)
let sideBarBehavior:UIDynamicItemBehavior = UIDynamicItemBehavior(items: [sideBarContainerView])
sideBarBehavior.elasticity = 0.3
animator.addBehavior(sideBarBehavior)
}
func sideBarControlDidSelectRow(_ indexPath: IndexPath) {
delegate?.sideBarDidSelectButtonAtIndex(indexPath.row)
showSideBar(false)
}
}
After this, add a new swift class
SideBarTableViewController
which inherit UITableViewController
import UIKit
protocol SideBarTableViewControllerDelegate{
func sideBarControlDidSelectRow(_ indexPath:IndexPath)
}
class SideBarTableViewController: UITableViewController {
var delegate:SideBarTableViewControllerDelegate?
var tableData:Array<String> = []
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell:UITableViewCell? = tableView.dequeueReusableCell(withIdentifier: "Cell")
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
cell!.backgroundColor = UIColor.clear
cell!.textLabel?.textColor = UIColor.darkText
let selectedView:UIView = UIView(frame: CGRect(x: 0, y: 0, width: cell!.frame.size.width, height: cell!.frame.size.height))
selectedView.backgroundColor = UIColor.black.withAlphaComponent(0.3)
cell!.selectedBackgroundView = selectedView
}
cell!.textLabel?.text = tableData[indexPath.row]
return cell!
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 45
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
delegate?.sideBarControlDidSelectRow(indexPath)
}
}
Now paste the code below in your TableViewController or the page on which you want to add SlideBar.
let the name of your page is Dashboard, add the delegate as below
class Dashboard: UIViewController, SideBarDelegate
{
//declare sidebar
var sideBar:SideBar = SideBar()
override func viewWillAppear(_ animated: Bool)
{
//Initialise the content of SlideBar Row
sideBar = SideBar(sourceView: self.view, menuItems: ["Home", "Dashboard"])
sideBar.delegate = self
}
func sideBarControlDidSelectRow(_ indexPath: IndexPath) {
print("Selected from SlideBar")
}
func sideBarDidSelectButtonAtIndex(_ index: Int)
{
//
}
//Add a button(Optional)in ViewDidLoad()
override func viewDidLoad()
{
super.viewDidLoad()
let btn_Hamburger = UIButton(frame: CGRect(x: 10, y: 70, width: 100, height: 25))
btn_Hamburger.addTarget(self, action: #selector(btn_hamburger(sender:)), for: .touchUpInside)
//add Image on Hamburger button
btn_Hamburger.setImage(#imageLiteral(resourceName: "img_hemberger"), for: .normal)
view.addSubview(btn_Hamburger)
}
//To in and out SideBar menu
var flag:Bool = true
func btn_hamburger(sender: UIButton!)
{
if flag == true {
sideBar.showSideBar(true)
flag = false
}
else{
sideBar.showSideBar(false)
flag = true
}
}
}