View disappears with delay swift - ios

I have the navigationController with 2 UIViewControllers.
When I press "back button" view from secondViewController disappears with 1 second delay.
P.S. I use iCarousel pod for init the views in secondViewController.
See screenshots:
When I press "back" button from another:
FirstController after 1 second (view from second controller disappeared)
Update:
Second ViewController
class AppsController : UIViewController, iCarouselDataSource, iCarouselDelegate {
let xmlHelper = XmlHelper()
var apps = Apps(data:[App]())
var selectUrl = ""
var selectTitle = ""
var scrollIndex = 0
#IBOutlet var carousel: iCarousel!
override func viewDidLoad() {
super.viewDidLoad()
self.carousel.delegate = self
self.carousel.isPagingEnabled = true
DispatchQueue.main.async {
self.initApps()
}
}
func numberOfItems(in carousel: iCarousel) -> Int {
return apps.data.count
}
func carousel(_ carousel: iCarousel, viewForItemAt index: Int, reusing view: UIView?) -> UIView {
let appView: AppView = Bundle.main.loadNibNamed("appView",
owner: nil,
options: nil)?.first as! AppView!
appView.titleLabel?.text = apps.data[index].title
appView.descLabel?.text = apps.data[index].desc
appView.frame = CGRect(x:0, y:0, width:self.view.frame.width-30, height:carousel.frame.height-60)
appView.backgroundColor = UIColor.white
var shadowLayer: CAShapeLayer!
shadowLayer = CAShapeLayer()
shadowLayer.path = UIBezierPath(roundedRect: appView.bounds, cornerRadius: 0).cgPath
shadowLayer.fillColor = UIColor.white.cgColor
shadowLayer.shadowColor = UIColor.lightGray.cgColor
shadowLayer.shadowPath = shadowLayer.path
shadowLayer.shadowOffset = CGSize(width: 0.0, height: 0.0)
shadowLayer.shadowOpacity = 0.8
shadowLayer.shadowRadius = 2
appView.layer.insertSublayer(shadowLayer, at: 0)
appView.storeButton.addTarget(self, action: #selector(didTapApp), for: UIControlEvents.touchUpInside)
DispatchQueue.main.async {
appView.iconView?.sd_setImage(with: URL(string:self.apps.data[index].icon
), completed: { (image, error, cache, url) in
if error == nil {
appView.iconView.image = appView.iconView.image?.cropToBounds(image: image!, width: 30, height: 30)
}
})
}
return appView
}
func carousel(_ carousel: iCarousel, valueFor option: iCarouselOption, withDefault value: CGFloat) -> CGFloat {
if (option == .spacing) {
return value * 1.1
}
return value
}
func didTapApp() {
if self.apps.data.count != 0 {
UIApplication.shared.open(URL(string: "itms://itunes.apple.com/app/id" + self.apps.data[carousel.currentItemIndex].link)!, options: [:], completionHandler: nil)
}
}
func initApps() {
xmlHelper.getAnoutherApps { (apps) in
if apps != nil{
self.apps = apps!
self.carousel.reloadData()
}
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let backItem = UIBarButtonItem()
backItem.title = constants.back
navigationItem.backBarButtonItem = backItem
if segue.identifier == "toWeb" {
let vc = segue.destination as! WebController
vc.fileUrl = nil
vc.url = self.selectUrl
vc.title = self.selectTitle
self.tabBarController?.tabBar.isHidden = true
}
}
AppView (disappears with delay)
class AppView : UIView {
#IBOutlet var titleLabel : UILabel!
#IBOutlet var descLabel : UILabel!
#IBOutlet var iconView : UIImageView!
#IBOutlet var storeButton : UIButton!
}
First controller
class SettingsController : UITableViewController, MFMailComposeViewControllerDelegate {
var selectUrl : URL?
var selectTitle = ""
var selectStringUrl = ""
override func viewDidLoad() {
super.viewDidLoad()
self.initUI()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 4
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0:
return 2
case 1:
return 1
case 2:
return 1
case 3:
return 3
default:
return 0
}
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch section {
case 0:
return constants.info
case 1:
return constants.settings
case 2:
return constants.connect
case 3:
return constants.community
default:
return ""
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "settingsTitleCell")!
let itemSize = CGSize(width:30, height:30);
UIGraphicsBeginImageContextWithOptions(itemSize, false, UIScreen.main.scale);
let imageRect = CGRect(x:0.0, y:0.0, width:itemSize.width, height:itemSize.height);
cell.imageView?.image!.draw(in: imageRect)
cell.imageView?.image! = UIGraphicsGetImageFromCurrentImageContext()!;
UIGraphicsEndImageContext();
switch indexPath.section {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: "settingsTitleCell")!
cell.textLabel?.text = constants.infoTitles[indexPath.row]
cell.detailTextLabel?.text = constants.infoDetail[indexPath.row]
cell.imageView?.image = cell.imageView?.image?.cropToBounds(image: constants.infoImages[indexPath.row], width: 30, height: 30)
return cell
case 1:
let cell = tableView.dequeueReusableCell(withIdentifier: "fontCell") as! FontCell
return cell
case 2:
let cell = tableView.dequeueReusableCell(withIdentifier: "settingsTitleCell")!
cell.textLabel?.text = constants.connectTitles[indexPath.row]
cell.imageView?.image = cell.imageView?.image?.cropToBounds(image: constants.connectImages[indexPath.row], width: 30, height: 30)
cell.detailTextLabel?.text = ""
return cell
case 3:
let cell = tableView.dequeueReusableCell(withIdentifier: "settingsTitleCell")!
cell.textLabel?.text = constants.communityTitles[indexPath.row]
cell.detailTextLabel?.text = constants.communityDetail[indexPath.row]
cell.imageView?.image = cell.imageView?.image?.cropToBounds(image: constants.communityImages[indexPath.row], width: 30, height: 30)
return cell
default:
return cell
}
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 1 {
return 80
} else {
return 45
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch indexPath.section {
case 0:
if indexPath.row == 0 {
self.initWebView(url: Bundle.main.url(forResource: "caution", withExtension: "html"), stringUrl: nil, titlePage: constants.infoTitles[indexPath.row])
} else {
self.selectTitle = constants.infoTitles[indexPath.row]
self.performSegue(withIdentifier: "toApps", sender: self)
}
case 2:
self.sendMessage()
break;
case 3:
switch indexPath.row {
case 0:
self.initWebView(url: Bundle.main.url(forResource: "about", withExtension: "html"), stringUrl: nil, titlePage: constants.communityTitles[indexPath.row])
break;
case 1:
self.initWebView(url: nil, stringUrl: "https://vk.com/electronicengineer", titlePage: constants.communityTitles[indexPath.row])
case 2:
self.initWebView(url: nil, stringUrl: "https://fb.com", titlePage: constants.communityTitles[indexPath.row])
break;
default:
break;
}
default:
break;
}
}
func initUI() {
self.title = constants.settings
self.tableView.tableFooterView = UIView()
}
func initWebView(url:URL?, stringUrl:String?, titlePage:String) {
if stringUrl != nil {
self.selectStringUrl = stringUrl!
self.selectUrl = nil
} else {
self.selectUrl = url!
}
self.selectTitle = titlePage
self.performSegue(withIdentifier: "toWeb", sender: self)
}
func sendMessage() {
let mailComposeViewController = configuredMailComposeViewController()
if MFMailComposeViewController.canSendMail() {
self.present(mailComposeViewController, animated: true, completion: nil)
}
}
func configuredMailComposeViewController() -> MFMailComposeViewController {
let mailComposerVC = MFMailComposeViewController()
mailComposerVC.mailComposeDelegate = self
mailComposerVC.setToRecipients(["postboxapp#yandex.ru"])
mailComposerVC.setSubject("Электроник на Android")
mailComposerVC.setMessageBody("", isHTML: false)
return mailComposerVC
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let backItem = UIBarButtonItem()
backItem.title = constants.back
navigationItem.backBarButtonItem = backItem
if segue.identifier == "toWeb" {
let vc = segue.destination as! WebController
vc.fileUrl = self.selectUrl
vc.url = self.selectStringUrl
vc.title = self.selectTitle
self.tabBarController?.tabBar.isHidden = true
}
if segue.identifier == "toApps" {
let vc = segue.destination as! AppsController
vc.title = self.selectTitle
self.tabBarController?.tabBar.isHidden = true
}
}
}

Problem solved:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
self.carousel.isHidden = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
self.carousel.isHidden = false
}

Hiding and unhiding is just a work-around to the actual problem.
As answered to a similar question, set yourCarousel.clipsToBounds = true

Related

Add Animation on TableView Cells

I have made a tableView with cells that take the data from an API. I have imported ViewAnimator Package because I want to add some animation when the cells appear but the animation starts while the tableview had already be presented with data.
Maybe I have made a mistake at the logic but I can't find the solution.
The OpeningViewController is this :
import UIKit
import ViewAnimator
class OpeningViewController: UIViewController {
//MARK: - IBProperties
#IBOutlet var openingImg: UIImageView!
#IBOutlet var startButton: UIButton!
//MARK: - Properties
var nft : Nft?
//MARK: - Life Cyrcle
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let animation = AnimationType.from(direction: .top, offset: 50)
openingImg.animate(animations: [animation] , delay: 0.3, duration: 2)
openingImg.layer.shadowColor = UIColor.black.cgColor
openingImg.layer.shadowOffset = CGSize(width: 0, height: 0)
openingImg.layer.shadowOpacity = 0.65
openingImg.layer.shadowRadius = 10
}
//MARK: - Methods
#IBAction func startApp(_ sender: Any) {
HapticsManager.shared.selectionVibrate()
let storyBoard = UIStoryboard(name: "Lobby", bundle: nil)
let controller = storyBoard.instantiateViewController(withIdentifier: "LobbyViewController") as! LobbyViewController
controller.modalTransitionStyle = .flipHorizontal
self.navigationController?.pushViewController(controller, animated: true)
}
}
The presentation happens in LobbyViewController :
import UIKit
import ViewAnimator
class LobbyViewController: UIViewController {
// MARK: - IBProperties
#IBOutlet weak var tableView: UITableView!
// MARK: - Properties
var data: [DataEnum] = []
var likes:[Int] = []
var numlikes: Int = 0
var nfts: [Nft] = []
let creators : [Creator] = []
var icons: [Icon] = []
var loadData = APICaller()
// MARK: - Life Cyrcle
override func viewDidLoad() {
super.viewDidLoad()
let nib = UINib(nibName: "AssetTableViewCell", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "AssetTableViewCell")
let nib2 = UINib(nibName: "CreatorsTableViewCell", bundle: nil)
tableView.register(nib2, forCellReuseIdentifier: "CreatorsTableViewCell")
tableView.dataSource = self //method to generate cells,header and footer before they are displaying
tableView.delegate = self //method to provide information about these cells, header and footer ....
downloadJSON {
self.tableView.reloadData()
print("success")
}
loadData.downloadData { (result) in
print(result)
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let animation = AnimationType.from(direction: .top, offset: 300)
UIView.animate(views: tableView.visibleCells,
animations: [animation], delay: 1, duration: 2)
}
//stelnei ta dedomena apo to kathe row ston PresentViewController
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? PresentViewController {
if tableView.cellForRow(at: tableView.indexPathForSelectedRow!) is AssetTableViewCell {
destination.nft = nfts[tableView.indexPathForSelectedRow!.row-1]
destination.delegate = self
} else {
//add alert action
let alert = UIAlertController(title: "Invalid Touch", message: "You press wrong row. Choose one of the following list.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
present(alert, animated: true, completion: {
return
})
}
}
}
// MARK: - Methods
func downloadJSON(completed: #escaping () -> ()) {
let url = URL(string: "https://public.arx.net/~chris2/nfts.json")
URLSession.shared.dataTask(with: url!) { [self] data, response, error in
if error == nil {
do {
self.nfts = try JSONDecoder().decode([Nft].self, from: data!)
let creators = nfts.map { nft in
nft.creator
}
self.data.append(.type1(creators: creators))
self.nfts.forEach { nft in
self.data.append(.type2(nft: nft))
}
DispatchQueue.main.async {
completed()
}
}
catch {
print("error fetching data from api")
}
}
}.resume()
}
}
// MARK: - Extensions
extension LobbyViewController : UITableViewDelegate , UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
indexPath.row == 0 ? 100 : UITableView.automaticDimension
}
//gemizo ta rows tou table
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch self.data[indexPath.item] {
case .type1(let creators):
print("--->", creators)
let cell = tableView.dequeueReusableCell(withIdentifier: "CreatorsTableViewCell",
for: indexPath) as! CreatorsTableViewCell
cell.layer.cornerRadius = 15
cell.layer.shadowColor = UIColor.black.cgColor
cell.layer.shadowOffset = CGSize(width: 0, height: 0)
cell.layer.shadowOpacity = 0.8
cell.layer.shadowRadius = 15
cell.layer.cornerRadius = cell.frame.height/2
cell.updateCreators(creators)
return cell
case .type2(let nft):
let cell = tableView.dequeueReusableCell(withIdentifier: "AssetTableViewCell",
for: indexPath) as! AssetTableViewCell
cell.nameLabel?.text = nft.name
cell.nameLabel.layer.cornerRadius = cell.nameLabel.frame.height/2
cell.likesLabel?.text = "\((numlikes))"
let imgUrl = (nft.image_url)
print(imgUrl)
cell.iconView.downloaded(from: imgUrl)
cell.iconView.layer.cornerRadius = cell.iconView.frame.height/2
return cell
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "showDetails", sender: self)
}
}
extension LobbyViewController : TestDelegate{
func sendBackTheLikess(int: Int) {
numlikes = int
tableView.reloadData()
}
}
// MARK: - Enums
enum DataEnum {
case type1(creators: [Creator])
case type2(nft: Nft)
}
// MARK: - Struct
struct Constants {
static let url = "https://public.arx.net/~chris2/nfts.json"
}
The APICaller :
import Foundation
final class APICaller {
static let shared = APICaller()
public struct Constants {
static let url = "https://public.arx.net/~chris2/nfts.json"
}
public func downloadData(completion:#escaping (Result<[Nft], Error>) -> Void )
{
guard let url = URL(string:Constants.url)else{
return
}
let task = URLSession.shared.dataTask(with: url) { data, response, error in
//print(response)
print("here")
guard let data = data , error == nil else{
print("something went wrong with data")
return
}
print("here4")
//mexri edo exoume parei ta data kai tora me to do-catch tha ta kanoume convert se object
do{
//Decode the response
let nfts = try JSONDecoder().decode([Nft].self, from: data)
completion(.success(nfts))
print(nfts)
}catch{
completion(.failure(error))
}
}
task.resume()
}
}
and here is a video as a gif of what happen fro better understanding
https://gifyu.com/image/SEGkZ

Cannot find 'selectedIndexPaths' in scope

My Viewcontroller shows "Cannot find 'selectedIndexPaths' in scope" and other errors
My viewcontroller with errors:- 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]()` defined inside `ProductViewController`, to keep track of the selected products// **error -Cannot find 'selectedIndexPaths' in scope**
if selectedIndexPaths.contains(indexPath) {**//error -Cannot find 'selectedIndexPaths' in scope**
if let index = selectedIndexPaths.firstIndex(of: indexPath) {
selectedIndexPaths.remove(at: index)**//error -Cannot find 'selectedIndexPaths' in scope**
removeProductFromCart(indexPath: indexPath)
}
} else {
selectedIndexPaths.append(indexPath)
addProductToCart(indexPath: indexPath)
}
// addProductToCart(indexPath: indexPath)
/// **I commented this out because I don't have the code for `Cart`**
//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)
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()
}
}
}
}
}
screenshot of the error-
I have tableview in my productviewcotroller as shown below. so, thats not an issusem still errors:-
There are other errors also which it is showing.
How to sort it out ?
var selectedIndexPaths = IndexPath
Please define selectedIndexPaths inside the main class not in the extension then check it again .

Random grey bar appears on top of ViewController in iOS (swift)

I am making an app currently and on the main screen where I load multiple items from Parse, I see a weird grey bar. I don't know where this bar came from as it does not show up on the storyboard and I don't know how to fix it. It never was a problem until it randomly recently showed up. Here is the code for that ViewController.
import UIKit
import Parse
import ParseUI
import Kingfisher
class HomeTableViewController: PFQueryTableViewController
{
override func viewDidLoad ()
{
super.viewDidLoad()
setTitle()
self.navigationController?.isNavigationBarHidden = true
self.navigationController?.navigationBar.setHeight(0.0)
// self.tableView.scrollsToTop = true
// self.tableView.scrollToNearestSelectedRow(at: UITableViewScrollPosition.bottom, animated: false)
// self.tableView.scrollToNearestSelectedRow(at: UITableViewScrollPosition.top, animated: true)
}
func setTitle()
{
var parentView = self.parent
while parent != nil
{
if let menu = parentView as? CucuMenuController
{
// menu.setTitleForLabel("Cucus")
menu.setTitleForLabel("")
break
}
parentView = parentView?.parent
}
}
var firstTime = true
var totalArticles = 0
let appDel = UIApplication.shared.delegate as! AppDelegate
required init!(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
setupHomefeed()
}
func setupHomefeed()
{
// This runs before didFinishLoadingWithOptions
self.parseClassName = "Article"
self.pullToRefreshEnabled = true
self.paginationEnabled = true
self.objectsPerPage = 10
self.loadingViewEnabled = true
}
override func objectsDidLoad(_ error: Error?)
{
super.objectsDidLoad(error)
if firstTime
{
firstTime = false
self.loadObjects()
self.tableView.reloadData()
}
else
{
PFObject.pinAll(inBackground: self.objects)
}
}
override func numberOfSections(in tableView: UITableView) -> Int
{
return 1
}
override func viewDidAppear(_ animated: Bool)
{
navigationController?.isNavigationBarHidden = false
if PFUser.current() == nil || PFUser.current()!["name"] == nil
{
let viewController = storyboard!.instantiateViewController(withIdentifier: "LoginController")
UIApplication.shared.keyWindow?.rootViewController = viewController
}
else if UserDefaults.standard.bool(forKey: "showDemo")
{
self.performSegue(withIdentifier: "detailSegue", sender: self)
}
else
{
self.loadObjects()
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
if self.objects!.count < totalArticles && self.objects!.count > 0
{
return self.objects!.count + 1
}
return self.objects!.count
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
if indexPath.row == self.objects?.count
{
return 70.0
}
else
{
return 221.5
}
}
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 0.0
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 0.0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as UITableViewCell!
if indexPath.row == self.objects!.count
{
return tableView.dequeueReusableCell(withIdentifier: "loadCell") as UITableViewCell!
}
if (indexPath.row > self.objects!.count)
{
return cell!
}
let imageView = cell?.viewWithTag(200) as! UIImageView
let titleText = cell?.viewWithTag(101) as! UILabel
let timeLabel = cell?.viewWithTag(102) as! UILabel
let newImage = cell?.viewWithTag(100) as! UIImageView
let diffImage = cell?.viewWithTag(300) as! UIImageView
let scoreLabel = cell?.viewWithTag(301) as! UILabel
let catLabel = cell?.viewWithTag(103) as! UILabel
let article = Article(parseData: self.objects![indexPath.row])
titleText.text = article.title
timeLabel.text = article.duration
catLabel.text = article.category.uppercased()
let hasRead = UserController.hasReadArticle(article.objectId)
newImage.isHidden = hasRead
if hasRead
{
let score = UserController.getScoreForArticle(article.objectId)
scoreLabel.text = NSString(format: "YOUR SCORE: %.0f", score) as String
var performance = "hard"
if score >= article.idealScore { performance = "easy" }
else if score * 2 >= article.idealScore { performance = "medium" }
diffImage.image = UIImage(named: performance + "ScoreTag")
if UserController.getPlayableForArticle(article.objectId) {
cell?.isUserInteractionEnabled = true
}
}
else
{
scoreLabel.text = NSString(format: "AVG. SCORE: %.0f", article.idealScore) as String
diffImage.image = UIImage(named: article.difficulty.lowercased() + "ScoreTag")
}
//Image
let resource = ImageResource(downloadURL: article.getImageURL(), cacheKey: article.objectId)
imageView.kf.setImage(with: resource)
UIHelper.addShadowToHomeCell((cell?.viewWithTag(1)!)!)
return cell!
}
var selectedIndex = -1
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
if indexPath.row == self.objects!.count
{
self.loadNextPage()
}
else
{
selectedIndex = indexPath.row
self.performSegue(withIdentifier: "detailSegue", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.identifier == "detailSegue"
{
let dest = segue.destination as? ArticlePreviewViewController
if UserDefaults.standard.bool(forKey: "showDemo")
{
dest?.article = DemoArticle().article
}
else
{
dest?.article = Article(parseData: self.objects![selectedIndex])
}
}
NotificationCenter.default.post(name: Notification.Name(rawValue: "CUCU_START"), object: nil)
}
override func queryForTable() -> PFQuery<PFObject>
{
let q = PFQuery(className: "Article").whereKey("releaseDate", lessThanOrEqualTo: Date()).whereKey("validated", equalTo: true)
if firstTime
{
q.fromLocalDatastore()
}
else
{
let mods = PFQuery(className: "Question").whereKey("article", matchesQuery: q)
mods.findObjectsInBackground
{
(objects, err) -> Void in
PFObject.pinAll(inBackground: objects)
}
}
print(firstTime)
totalArticles = q.countObjects(nil)
q.order(byDescending: "createdAt")
return q
}
}
Here are a few images of what the problem looks like:
Edit 1:
As suggested in the comments, I even tried to debug view hierarchy but I don't know which element to delete to make the grey bar go away.
It looks like it might be your navigation bar. Have you tried using this:
self.navigationController?.setNavigationBarHidden(true, animated: true)
instead of the statement you have of:
self.navigationController?.isNavigationBarHidden = true
Update #2:
Actually, I just realized you have that in the viewDidLoad. Move that to viewWillAppear and I bet it will work.
Update #3:
Just to reflect the true fix here, the offending code was in the viewDidAppear:
navigationController?.isNavigationBarHidden = false

Filtering UItableview Swift IOS

I am trying to filter a UITableView based on variables that have been passed back from another VC which is a Eureka form handling the filter UI.
I would like to filter the tableview based on these two variables :
var filterByPrice: Float?
var filteredRentalTypes: Set<String>?
I have got the price filter working but I am having trouble filtering with the rental type. There may be a more efficient way of doing this but this is my code so far. With my current code I get an 'index out of range' crash for the rental type filter.
This is my TableViewVC:
class RentalTableViewVC: UIViewController, UITableViewDataSource, UITableViewDelegate {
var rentalsArray = [Rental]()
var filteredArrary = [Rental]()
var myRentals = [String]()
var filterByPrice: Float?
var filteredRentalTypes: Set<String>?
static var imageCache: NSCache<NSString, UIImage> = NSCache()
#IBOutlet weak var tableView: UITableView!
var hidingBarMangar: HidingNavigationBarManager?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toDetailVC" {
let destination = segue.destination as? DetailVC
let value = tableView.indexPathForSelectedRow?.row
if filteredArrary.count != 0 {
destination?.emailAdress = filteredArrary[value!].email!
destination?.bond = filteredArrary[value!].bond!
destination?.dateAval = filteredArrary[value!].dateAval!
destination?.pets = filteredArrary[value!].pets!
destination?.rent = filteredArrary[value!].price!
destination?.rentalTitle = filteredArrary[value!].title!
destination?.imageURL = filteredArrary[value!].imageURL!
destination?.des = filteredArrary[value!].description!
destination?.rentalType = filteredArrary[value!].rentalType!
destination?.streetName = filteredArrary[value!].streetName!
destination?.city = filteredArrary[value!].city!
destination?.postcode = filteredArrary[value!].postcode!
} else {
destination?.emailAdress = rentalsArray[value!].email!
destination?.bond = rentalsArray[value!].bond!
destination?.dateAval = rentalsArray[value!].dateAval!
destination?.pets = rentalsArray[value!].pets!
destination?.rent = rentalsArray[value!].price!
destination?.rentalTitle = rentalsArray[value!].title!
destination?.imageURL = rentalsArray[value!].imageURL!
destination?.des = rentalsArray[value!].description!
destination?.rentalType = rentalsArray[value!].rentalType!
destination?.streetName = rentalsArray[value!].streetName!
destination?.city = rentalsArray[value!].city!
destination?.postcode = rentalsArray[value!].postcode!
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if filteredArrary.count != 0 {
return filteredArrary.count
} else {
return rentalsArray.count
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var rental = rentalsArray[indexPath.row]
if self.filteredArrary.count != 0 {
rental = filteredArrary[indexPath.row]
}
if let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? RentalCell {
var rentalImage = ""
if rental.imageURL != nil {
rentalImage = rental.imageURL!
}
if let img = RentalTableViewVC.imageCache.object(forKey: rentalImage as NSString) {
cell.configureCell(rental: rental, image: img)
return cell
} else {
cell.configureCell(rental: rental, image: nil)
return cell
}
} else {
return RentalCell()
}
}
#IBAction func backPressed(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
hidingBarMangar?.viewWillAppear(animated)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
hidingBarMangar?.viewDidLayoutSubviews()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
hidingBarMangar?.viewWillDisappear(animated)
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.dataSource = self
//Firebase observer
DataService.ds.DBrefRentals.observe(.value) { (snapshot) in
self.rentalsArray = []
self.filteredArrary = []
if let snapshots = snapshot.children.allObjects as? [DataSnapshot] {
for snap in snapshots {
if let dicOfRentals = snap.value as? Dictionary<String,AnyObject> {
let key = snap.key
let rental = Rental(postID: key, userData: dicOfRentals)
self.rentalsArray.append(rental)
//Placing filtered items in the filtered array
if self.filterByPrice != nil {
let priceAsFloat = (rental.price! as NSString).floatValue
if self.filterByPrice! >= priceAsFloat {
self.filteredArrary.append(rental)
}
}
if self.filteredRentalTypes != nil {
for rentals in self.filteredRentalTypes! {
if rental.rentalType == rentals {
print("******hh\(String(describing: self.filteredRentalTypes))")
self.filteredArrary.append(rental)
}
}
}
}
}
self.tableView.reloadData()
}
}
addHidingBar()
}
override func viewDidAppear(_ animated: Bool) {
print("**********\(String(describing: filterByPrice)))")
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
rentalsArray[indexPath.row].incrimentViews()
let postViewsToFB = DataService.ds.DBrefRentals.child(rentalsArray[indexPath.row].postID!)
postViewsToFB.child("views").setValue(rentalsArray[indexPath.row].views)
performSegue(withIdentifier: "toDetailVC" , sender: nil)
}
func addHidingBar() {
let extensionView = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 40))
extensionView.layer.borderColor = UIColor.lightGray.cgColor
extensionView.layer.borderWidth = 1
extensionView.backgroundColor = UIColor(white: 230/255, alpha: 1)
/*let label = UILabel(frame: extensionView.frame)
label.text = "Extension View"
label.textAlignment = NSTextAlignment.center
extensionView.addSubview(label) */
let btn = UIButton(frame: CGRect(x: 20, y: 15, width: 75, height: 10))
btn.setTitle("Filter", for: .normal)
let btnColour = UIColor(displayP3Red: 0.0, green: 122.0/255.0, blue: 1.0, alpha: 1.0)
btn.setTitleColor(btnColour, for: .normal)
btn.titleLabel?.font = headerFont
btn.addTarget(self, action: #selector(filterBtnPressed), for: .touchUpInside)
extensionView.addSubview(btn)
hidingBarMangar = HidingNavigationBarManager(viewController: self, scrollView: tableView)
hidingBarMangar?.addExtensionView(extensionView)
}
#objc func filterBtnPressed() {
performSegue(withIdentifier: "toFilterVC", sender: nil)
}
}
You may return different array in numberOfRows and their sizes may be different so check count before indexing any array as if array count != 0 doesn't mean you can index it with index path.row that may be greater then 0 ,Change this line in cellForRow
if self.filteredArrary.count != 0 {
rental = filteredArrary[indexPath.row]
}
to
if indexPath.row < self.filteredArrary.count {
rental = filteredArrary[indexPath.row]
}

Getting a UITableView to refresh users after one begins a live stream

The landing page for an app I am working on has a place holder avatar named after the application that is present when no user is actively live streaming (using the Red5 Pro streaming framework for this).
However when someone does begin to stream, I want it to automatically refresh the tableview and display the new user's avatar. What I've written so far kind of works, but not entirely. When someone begins livestreaming the placeholder avatar does disappear, but the user that's streaming's avatar doesn't appear.
If I close the app and reopen it, then it is displayed correctly. Here's my code in Swift 3, what am I doing wrong? Should the call to refresh be moved out of ViewDidLoad? Am I using Dispatch Queue incorrectly? Thanks
import UIKit
import Firebase
class HomeController: UIViewController, UITableViewDataSource, UITableViewDelegate, cellDelegate {
#IBOutlet var tableView: UITableView!
var stream: String!
var top: [SSStream] = []
var recent: [SSStream] = [SSStream()]
var trending: [SSStream] = [SSStream()]
var ref: FIRDatabaseReference!
override func viewDidLoad() {
navigationItem.title = "Swiffshot"
navigationController?.navigationBar.isTranslucent = false
let settings = UIButton(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
settings.setImage(#imageLiteral(resourceName: "Settings"), for: .normal)
settings.addTarget(self, action: #selector(settingsPressed), for: .touchUpInside)
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: settings)
let friends = UIButton(frame: CGRect(x: 0, y: 0, width: 23, height: 20))
friends.setImage(#imageLiteral(resourceName: "AllFriends"), for: .normal)
friends.addTarget(self, action: #selector(friendsPressed), for: .touchUpInside)
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: friends)
let nib = UINib(nibName: "MainHeader", bundle: Bundle.main)
tableView.register(nib, forHeaderFooterViewReuseIdentifier: "MainHeader")
ref = FIRDatabase.database().reference()
if !SSContact.shared.active {
performSegue(withIdentifier: "fromMainToAuth", sender: self)
}
SSContact.shared.load() { SSContact.shared.propertyCheck(self) { } }
// SSContact.shared.subscribeToTop(pulse: { (streams) in
// self.top.removeAll()
// self.top.append(contentsOf: streams)
// self.tableView.reloadSections(IndexSet(integer: 0), with: .automatic)
// })
ref.child("streams").observe(.value, with: { (snapshot) in
print("I ran")
self.top.removeAll()
if let userData = snapshot.value as? NSDictionary {
for stream in userData {
let newStream = SSStream()
newStream.username = stream.key as! String
print("Found stream \(stream.key as! String)")
newStream.isPrivate = !((stream.value as! NSDictionary)["public"] as! Bool)
newStream.views = (stream.value as! NSDictionary)["views"] as! Int
newStream.isEnabled = true
self.top.append(newStream)
}
}
if self.top.isEmpty {
print("No Streams Found")
self.top.append(SSStream())
}
DispatchQueue.main.async {
self.tableView.reloadSections(IndexSet(integer: 0), with: .automatic)
self.tableView.reloadData()
}
})
}
func cellGotPressed(_ stream: String) {
self.stream = stream
performSegue(withIdentifier: "toPlayer", sender: self)
}
func settingsPressed() {
performSegue(withIdentifier: "toSettings", sender: self)
}
func friendsPressed() {
performSegue(withIdentifier: "fromMainToExpandable", sender: self)
}
func cameraTapped() {
performSegue(withIdentifier: "toRed", sender: self)
}
func cellTapped() {
print("Cell Tapped")
}
// MARK: Segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toPlayer" {
let player = segue.destination as! VideoPlayerViewController
player.isSubscribing = true
player.stream = stream
}
}
// MARK: Table View Functions
func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "big") as! CategoryRow
cell.section = indexPath.section
cell.top = top
cell.delegate = self
cell.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(cameraTapped)))
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "small") as! CategoryRow
cell.section = indexPath.section
cell.recent = recent
cell.trending = trending
cell.delegate = self
return cell
}
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if section == 0 {
return nil
} else {
let cell = self.tableView.dequeueReusableHeaderFooterView(withIdentifier: "MainHeader")
let header = cell as! MainHeader
if section == 1 {
header.fillHeader("RECENT")
} else if section == 2 {
header.fillHeader("Trending + Now")
} else {
print("Unknown Section")
}
return header
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0 {
return 300
} else {
return 100
}
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if section == 0 {
return 0
} else {
return 50
}
}
func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
return 50
}
}
I realized what I needed to do. I needed to set the
ref.child("streams").observe
in the call to Dispatch.Queue. By setting the reference before dispatch was called, the program wasn't syncing properly. It should be like this:
DispatchQueue.main.async {
ref.child("streams").observe(.value, with: { (snapshot) in
self.tableView.reloadSections(IndexSet(integer: 0), with: .automatic)
self.tableView.reloadData()
}
})

Resources