swift - Updating several uiimageview - swift

I have been working on this project which needs several uiimageviews which, they are in a uicollectionviewcell, to be updated based on the information on the database!
i have tried background threads but it didnt help!im wondering why the images wont update!
here is my code
func update_cells()
{
if sqlite3_prepare(self.db, "SELECT * FROM `habit_days` WHERE `habit_id` = \(self.id!)", -1, &self.stmt, nil) == SQLITE_OK
{
while(sqlite3_step(self.stmt) == SQLITE_ROW)
{
if(String(cString: sqlite3_column_text(self.stmt, 3 )) == "checked")
{
DispatchQueue.main.async {
let image = self.view.viewWithTag(self.day_id) as? UIImageView
image?.image = UIImage(named: "mark")
self.day_id = self.day_id + 1
}
}else{
DispatchQueue.main.async {
let image = self.view.viewWithTag(self.day_id) as? UIImageView
image?.image = UIImage(named: "uncheck")
self.day_id = self.day_id + 1
}
}
self.date = String(cString:sqlite3_column_text(self.stmt, 2))
let frmt = DateFormatter()
frmt.dateFormat = "yyyy/MM/dd HH:mm:ss"
self.lastdate = frmt.date(from: self.date!)
}
self.todayedate = Date()
}
}
any help would be appriciated
///////////////////
UPDATE
So i have changed my code to this and now i have my code working but still 1 problem :| all the cells are changing except the first one!
//
// Habit_Activity.swift
// Habit
//
// Created by shayan rahimian on 3/3/18.
// Copyright © 2018 shayan rahimian. All rights reserved.
//
import UIKit
import SQLite3
class Habit_check: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return days
}
#IBOutlet weak var des: UITextView!
#IBOutlet weak var col: UICollectionView!
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
cell.layer.borderWidth = 1.5
cell.layer.borderColor = self.hexStringToUIColor(hex: "#a0a0a0").cgColor
let image = UIImageView(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
print(indexPath.row)
image.tag = indexPath.row
cell.contentView.addSubview(image)
return cell
}
#IBAction func back(_ sender: Any) {
let back = UIStoryboard(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "habits_list") as? Habits_list
self.present(back!, animated: true, completion: nil)
}
#IBAction func check(_ sender: Any) {
let frmt = DateFormatter()
frmt.dateFormat = "yyyy/MM/dd HH:mm:ss"
let mystr = frmt.string(from: todayedate)
print(mystr)
if ( days_passed > 0){
sqlite3_exec(db, "INSERT INTO `habit_days`(`id`,`habit_id`,`time`,`state`) VALUES(null,\(self.id!),'\(mystr)','checked')", nil, nil, nil)
let image = self.view.viewWithTag(day_id) as? UIImageView
image?.image = UIImage(named: "mark")
days_passed = 0
day_id = day_id + 1
}
else{
self.view.makeToast("باید از اخرین تغیریرات شما ۲۴ ساعت گذشته باشد", duration: 2.0, point: CGPoint(x: 110.0, y: 110.0), title: "", image: nil, style: ToastStyle.init(), completion: nil)
}
}
#IBOutlet weak var cell_view: UIView!
#IBAction func del(_ sender: Any) {
let frmt = DateFormatter()
frmt.dateFormat = "yyyy/MM/dd HH:mm:ss"
let mystr = frmt.string(from: todayedate)
if ( days_passed > 0){
sqlite3_exec(db, "INSERT INTO `habit_days`(`id`,`habit_id`,`time`,`state`) VALUES(null,\(self.id!),'\(mystr)','unchecked')", nil, nil, nil)
let image = self.view.viewWithTag(self.day_id) as? UIImageView
image?.image = UIImage(named: "uncheck")
days_passed = 0
day_id = day_id + 1
}
else{
self.view.makeToast("باید از اخرین تغیریرات شما ۲۴ ساعت گذشته باشد", duration: 2.0, point: CGPoint(x: 110.0, y: 110.0), title: "", image: nil, style: ToastStyle.init(), completion: nil)
}
}
#IBOutlet weak var name_label: UILabel!
var id : Int!
var db: OpaquePointer?
var stmt:OpaquePointer?
var name: String!
var days: Int!
var day_id = 0
var date: String!
var lastdate: Date!
var todayedate: Date!
var days_passed = 999
weak var delegate: Habits_list!
override func viewDidLoad() {
super.viewDidLoad()
cell_view.layer.borderWidth = 3
cell_view.layer.borderColor = self.hexStringToUIColor(hex: "#a0a0a0").cgColor
cell_view.layer.cornerRadius = 10
col.layer.borderWidth = 3
col.layer.borderColor = self.hexStringToUIColor(hex: "#a0a0a0").cgColor
col.layer.cornerRadius = 10
des.layer.borderWidth = 3
des.layer.borderColor = self.hexStringToUIColor(hex: "#a0a0a0").cgColor
des.layer.cornerRadius = 10
get_info()
DispatchQueue.global(qos: .background).async {
self.update_cells()
if (self.lastdate != nil) {
self.days_passed = Calendar.current.dateComponents([.day], from: self.lastdate, to: self.todayedate).day!
}
}
}
func update_cells()
{
if sqlite3_prepare(self.db, "SELECT * FROM `habit_days` WHERE `habit_id` = \(self.id!)", -1, &self.stmt, nil) == SQLITE_OK
{
while(sqlite3_step(self.stmt) == SQLITE_ROW)
{
if(String(cString: sqlite3_column_text(self.stmt, 3 )) == "checked")
{
DispatchQueue.main.async {
let image = self.view.viewWithTag(self.day_id) as? UIImageView
image?.image = UIImage(named: "mark")
self.day_id = self.day_id + 1
}
}else{
DispatchQueue.main.async {
let image = self.view.viewWithTag(self.day_id) as? UIImageView
image?.image = UIImage(named: "uncheck")
self.day_id = self.day_id + 1
}
}
self.date = String(cString:sqlite3_column_text(self.stmt, 2))
let frmt = DateFormatter()
frmt.dateFormat = "yyyy/MM/dd HH:mm:ss"
self.lastdate = frmt.date(from: self.date!)
}
self.todayedate = Date()
}
}
func get_info()
{
let fileNameToDelete = "habits.sqlite"
var filePath = ""
// Fine documents directory on device
let dirs : [String] = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.allDomainsMask, true)
if dirs.count > 0
{
let dir = dirs[0] //documents directory
filePath = dir.appendingFormat("/" + fileNameToDelete)
print("Local path = \(filePath)")
} else
{
print("Could not find local directory to store file")
return
}
let fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent("user.sqlite")
if sqlite3_open(fileURL.path, &db) == SQLITE_OK
{
if sqlite3_prepare(db, "SELECT * FROM `habits` WHERE `id` = \(self.id!)", -1, &stmt, nil) == SQLITE_OK
{
while(sqlite3_step(stmt) == SQLITE_ROW){
self.name = String(cString: sqlite3_column_text(stmt, 1))
name_label.text = self.name
self.days = Int(sqlite3_column_int(stmt, 2))
}
}
}
}
}
cell with tag number 0 is not changing! but other ones are ok.
///////////////////////
UPDATE 3 (Some how solved)
i have updated my code as below, it is not what i wanted but it is a work around in some way
//
// Habit_Activity.swift
// Habit
//
// Created by shayan rahimian on 3/3/18.
// Copyright © 2018 shayan rahimian. All rights reserved.
//
import UIKit
import SQLite3
class Habit_check: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return days + 1
}
#IBOutlet weak var des: UITextView!
#IBOutlet weak var col: UICollectionView!
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
cell.transform = CGAffineTransform(scaleX: -1, y: 1)
if indexPath.row != 0 {
cell.layer.borderWidth = 1.5
cell.layer.borderColor = self.hexStringToUIColor(hex: "#a0a0a0").cgColor
let image = UIImageView(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
image.tag = indexPath.row
cell.contentView.addSubview(image)
}
return cell
}
#IBAction func back(_ sender: Any) {
let back = UIStoryboard(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "habits_list") as? Habits_list
self.present(back!, animated: true, completion: nil)
}
#IBAction func check(_ sender: Any) {
let frmt = DateFormatter()
frmt.dateFormat = "yyyy/MM/dd HH:mm:ss"
let mystr = frmt.string(from: todayedate)
print(mystr)
if (day_id <= days) {
if ( days_passed > 0){
sqlite3_exec(db, "INSERT INTO `habit_days`(`id`,`habit_id`,`time`,`state`) VALUES(null,\(self.id!),'\(mystr)','checked')", nil, nil, nil)
let image = self.view.viewWithTag(day_id) as? UIImageView
image?.image = UIImage(named: "mark")
days_passed = 0
day_id = day_id + 1
}
else{
self.view.makeToast("باید از اخرین تغییرات شما ۲۴ ساعت گذشته باشد", duration: 2.0, point: CGPoint(x: 110.0, y: 110.0), title: "", image: nil, style: ToastStyle.init(), completion: nil)
}
}else{
self.view.makeToast("تعداد روز های عادت شما به پایان رسیده", duration: 2.0, point: CGPoint(x: 110.0, y: 110.0), title: "", image: nil, style: ToastStyle.init(), completion: nil)
}
}
#IBOutlet weak var cell_view: UIView!
#IBAction func del(_ sender: Any) {
let frmt = DateFormatter()
frmt.dateFormat = "yyyy/MM/dd HH:mm:ss"
let mystr = frmt.string(from: todayedate)
if (day_id <= days) {
if ( days_passed > 0){
sqlite3_exec(db, "INSERT INTO `habit_days`(`id`,`habit_id`,`time`,`state`) VALUES(null,\(self.id!),'\(mystr)','unchecked')", nil, nil, nil)
let image = self.view.viewWithTag(self.day_id) as? UIImageView
image?.image = UIImage(named: "uncheck")
days_passed = 0
day_id = day_id + 1
}
else{
self.view.makeToast("باید از اخرین تغیریرات شما ۲۴ ساعت گذشته باشد", duration: 2.0, point: CGPoint(x: 110.0, y: 110.0), title: "", image: nil, style: ToastStyle.init(), completion: nil)
}
}else{
self.view.makeToast("تعداد روز های عادت شما به پایان رسیده", duration: 2.0, point: CGPoint(x: 110.0, y: 110.0), title: "", image: nil, style: ToastStyle.init(), completion: nil)
}
}
#IBOutlet weak var name_label: UILabel!
var id : Int!
var db: OpaquePointer?
var stmt:OpaquePointer?
var name: String!
var days: Int!
var day_id = 1
var date: String!
var lastdate: Date!
var todayedate: Date!
var days_passed = 999
weak var delegate: Habits_list!
override func viewDidLoad() {
super.viewDidLoad()
get_info()
des.textAlignment = .right
des.makeTextWritingDirectionRightToLeft(self)
col.transform = CGAffineTransform(scaleX: -1, y: 1)
}
override func viewDidAppear(_ animated: Bool) {
cell_view.layer.borderWidth = 3
cell_view.layer.borderColor = self.hexStringToUIColor(hex: "#a0a0a0").cgColor
cell_view.layer.cornerRadius = 10
col.layer.borderWidth = 3
col.layer.borderColor = self.hexStringToUIColor(hex: "#a0a0a0").cgColor
col.layer.cornerRadius = 10
des.layer.borderWidth = 3
des.layer.borderColor = self.hexStringToUIColor(hex: "#a0a0a0").cgColor
des.layer.cornerRadius = 10
DispatchQueue.global(qos: .background).async {
self.update_cells()
if (self.lastdate != nil) {
self.days_passed = Calendar.current.dateComponents([.day], from: self.lastdate, to: self.todayedate).day!
}
}
}
func update_cells()
{
if sqlite3_prepare(self.db, "SELECT * FROM `habit_days` WHERE `habit_id` = \(self.id!)", -1, &self.stmt, nil) == SQLITE_OK
{
while(sqlite3_step(self.stmt) == SQLITE_ROW)
{
if(String(cString: sqlite3_column_text(self.stmt, 3 )) == "checked")
{
DispatchQueue.main.async {
let image = self.view.viewWithTag(self.day_id) as? UIImageView
image?.image = UIImage(named: "mark")
self.day_id = self.day_id + 1
}
}else{
DispatchQueue.main.async {
let image = self.view.viewWithTag(self.day_id) as? UIImageView
image?.image = UIImage(named: "uncheck")
self.day_id = self.day_id + 1
}
}
self.date = String(cString:sqlite3_column_text(self.stmt, 2))
let frmt = DateFormatter()
frmt.dateFormat = "yyyy/MM/dd HH:mm:ss"
self.lastdate = frmt.date(from: self.date!)
}
self.todayedate = Date()
}
}
func get_info()
{
let fileNameToDelete = "habits.sqlite"
var filePath = ""
// Fine documents directory on device
let dirs : [String] = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.allDomainsMask, true)
if dirs.count > 0
{
let dir = dirs[0] //documents directory
filePath = dir.appendingFormat("/" + fileNameToDelete)
print("Local path = \(filePath)")
} else
{
print("Could not find local directory to store file")
return
}
let fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent("user.sqlite")
if sqlite3_open(fileURL.path, &db) == SQLITE_OK
{
if sqlite3_prepare(db, "SELECT * FROM `habits` WHERE `id` = \(self.id!)", -1, &stmt, nil) == SQLITE_OK
{
while(sqlite3_step(stmt) == SQLITE_ROW){
self.name = String(cString: sqlite3_column_text(stmt, 1))
name_label.text = self.name
self.des.text = String(cString: sqlite3_column_text(stmt, 3))
self.days = Int(sqlite3_column_int(stmt, 2))
}
}
}
}
}

Related

Why is my alert controller not dismissing in my Swift app?

I have a custom view controller class which presents an alert controller when it receives a not connected notification from my network services class. I want to dismiss the alert controller when I receive a further connected notification from the network services class but I am unable to dismiss the presenting alert.
Here is my custom view controller class;
class CompanyPriceListVC: UITableViewController {
// MARK: - Properties
let companyStockSymbols = ["AAPL","AMZN", "MSFT", "GOOGL", "TSLA", "META","COINBASE:BTC", "BINANCE:BTCUSDT", "BINANCE:BNBBTC", "IC MARKETS:1", "IC MARKETS:2"]
let defaultStockInfo = StockInfo(tradeConditions: nil, price: 0.00, symbol: "-", timestamp: 0.0, volume: 0.0)
lazy var companyStockInfo = [StockInfo](repeating: defaultStockInfo, count: companyStockSymbols.count)
var companyDetailsVC:CompanyDetailsVC?
var tableRowSelected: Int?
let defaultPriceHistory = PriceHistory(previous: nil, relative: 0.0, absolute: 0.0)
lazy var priceHistory = [PriceHistory](repeating: defaultPriceHistory , count: companyStockSymbols.count)
var deviceOrientation: Orientation = .portrait
let activityIndicator: UIActivityIndicatorView = {
let activityIndicator = UIActivityIndicatorView()
activityIndicator.style = .large
activityIndicator.hidesWhenStopped = true
activityIndicator.color = .white
activityIndicator.translatesAutoresizingMaskIntoConstraints = false
activityIndicator.startAnimating()
return activityIndicator
}()
let isConnected = Notification.Name(rawValue: isConnectedNotificationKey)
let isNotConnected = Notification.Name(rawValue: isDisconnectedNotificationKey)
let alertController = UIAlertController(title: "Connectivity Error", message: "Network connection lost. Please check your WiFi settings, mobile data settings or reception coverage.", preferredStyle: .alert)
// MARK: - Lifecycle Methods
override func viewDidLoad() {
super.viewDidLoad()
if UIDevice.current.orientation.isPortrait {
self.deviceOrientation = .portrait
self.tableView.register(CompanyStockCellPortrait.self, forCellReuseIdentifier: "CompanyStockCellPortrait")
} else {
self.deviceOrientation = .landscape
self.tableView.register(CompanyStockCellLandscape.self, forCellReuseIdentifier: "CompanyStockCellLandscape")
}
configureNavigationBar()
view.backgroundColor = .black
configureTableView()
configureConstraints()
createObservers()
}
deinit {
NotificationCenter.default.removeObserver(self)
}
private func createObservers() {
NotificationCenter.default.addObserver(self, selector: #selector(CompanyPriceListVC.dismissAndFetchStockInfo), name: isConnected, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(CompanyPriceListVC.notifyUserOnScreen(notification:)), name: isNotConnected, object: nil)
}
#objc private func fetchStockInfo() {
NetworkServices.sharedInstance.fetchStockInfo(symbols: companyStockSymbols, delegate: self)
}
#objc private func notifyUserOnScreen(notification: NSNotification) {
self.present(alertController, animated: true)
}
#objc public func dismissAndFetchStockInfo() {
print("DEBUG: isBeingPresented: \(alertController.isBeingPresented)")
if alertController.isBeingPresented {
self.alertController.dismiss(animated: true, completion: nil)
}
fetchStockInfo()
}
override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
super.willTransition(to: newCollection, with: coordinator)
coordinator.animate(alongsideTransition: { (context) in
guard let windowInterfaceOrientation = self.windowInterfaceOrientation else { return }
if windowInterfaceOrientation.isPortrait {
self.deviceOrientation = .portrait
self.tableView.register(CompanyStockCellPortrait.self, forCellReuseIdentifier: "CompanyStockCellPortrait")
self.tableView.reloadData()
} else {
self.deviceOrientation = .landscape
self.tableView.register(CompanyStockCellLandscape.self, forCellReuseIdentifier: "CompanyStockCellLandscape")
self.tableView.reloadData()
}
})
}
private var windowInterfaceOrientation: UIInterfaceOrientation? {
return self.view.window?.windowScene?.interfaceOrientation
}
// MARK: - TableView Data Source Methods
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return companyStockInfo.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch deviceOrientation {
case .portrait:
let tableViewCellPortrait = tableView.dequeueReusableCell(withIdentifier: "CompanyStockCellPortrait", for: indexPath) as! CompanyStockCellPortrait
tableViewCellPortrait.symbolValue.text = companyStockInfo[indexPath.row].symbol
var latestPrice = companyStockInfo[indexPath.row].price
latestPrice = round(latestPrice * 100.0) / 100.00
tableViewCellPortrait.priceValue.text = String(format: "%.2f", arguments:[latestPrice])
if let _ = priceHistory[indexPath.row].previous {
let absoluteDifference = priceHistory[indexPath.row].absolute
let relativeDifference = priceHistory[indexPath.row].relative
if absoluteDifference > 0.0 {
tableViewCellPortrait.priceDirectionImageView.image = UIImage(systemName: "arrowtriangle.up.fill")
tableViewCellPortrait.priceDirectionImageView.tintColor = .systemGreen
tableViewCellPortrait.relativePriceDiffValue.text = String(format: "%.2f%%", arguments: [relativeDifference])
tableViewCellPortrait.relativePriceDiffValue.textColor = .systemGreen
tableViewCellPortrait.absolutePriceDiffValue.text = String(format: "(%.2f)", arguments: [absoluteDifference])
tableViewCellPortrait.absolutePriceDiffValue.textColor = .systemGreen
} else if absoluteDifference < 0.0 {
tableViewCellPortrait.priceDirectionImageView.image = UIImage(systemName: "arrowtriangle.down.fill")
tableViewCellPortrait.priceDirectionImageView.tintColor = .systemRed
tableViewCellPortrait.relativePriceDiffValue.text = String(format: "%.2f%%", arguments: [relativeDifference])
tableViewCellPortrait.relativePriceDiffValue.textColor = .systemRed
tableViewCellPortrait.absolutePriceDiffValue.text = String(format: "(%.2f)", arguments: [absoluteDifference])
tableViewCellPortrait.absolutePriceDiffValue.textColor = .systemRed
} else {
tableViewCellPortrait.priceDirectionImageView.image = UIImage(systemName: "diamond.fill")
tableViewCellPortrait.priceDirectionImageView.tintColor = .white
tableViewCellPortrait.relativePriceDiffValue.text = "0.00%"
tableViewCellPortrait.relativePriceDiffValue.textColor = .white
tableViewCellPortrait.absolutePriceDiffValue.text = "(0.00)"
tableViewCellPortrait.absolutePriceDiffValue.textColor = .white
}
} else {
tableViewCellPortrait.priceDirectionImageView.image = UIImage()
tableViewCellPortrait.priceDirectionImageView.tintColor = .white
tableViewCellPortrait.relativePriceDiffValue.text = ""
tableViewCellPortrait.absolutePriceDiffValue.text = ""
}
return tableViewCellPortrait
case .landscape:
let tableViewCellLandscape = tableView.dequeueReusableCell(withIdentifier: "CompanyStockCellLandscape", for: indexPath) as! CompanyStockCellLandscape
tableViewCellLandscape.symbolValue.text = companyStockInfo[indexPath.row].symbol
var latestPrice = companyStockInfo[indexPath.row].price
latestPrice = round(latestPrice * 100.0) / 100.00
tableViewCellLandscape.priceValue.text = String(format: "%.2f", arguments:[latestPrice])
if let _ = priceHistory[indexPath.row].previous {
let absoluteDifference = priceHistory[indexPath.row].absolute
let relativeDifference = priceHistory[indexPath.row].relative
if absoluteDifference > 0.0 {
tableViewCellLandscape.priceDirectionImageView.image = UIImage(systemName: "arrowtriangle.up.fill")
tableViewCellLandscape.priceDirectionImageView.tintColor = .systemGreen
tableViewCellLandscape.relativePriceDiffValue.text = String(format: "%.2f%%", arguments: [relativeDifference])
tableViewCellLandscape.relativePriceDiffValue.textColor = .systemGreen
tableViewCellLandscape.absolutePriceDiffValue.text = String(format: "(%.2f)", arguments: [absoluteDifference])
tableViewCellLandscape.absolutePriceDiffValue.textColor = .systemGreen
} else if absoluteDifference < 0.0 {
tableViewCellLandscape.priceDirectionImageView.image = UIImage(systemName: "arrowtriangle.down.fill")
tableViewCellLandscape.priceDirectionImageView.tintColor = .systemRed
tableViewCellLandscape.relativePriceDiffValue.text = String(format: "%.2f%%", arguments: [relativeDifference])
tableViewCellLandscape.relativePriceDiffValue.textColor = .systemRed
tableViewCellLandscape.absolutePriceDiffValue.text = String(format: "(%.2f)", arguments: [absoluteDifference])
tableViewCellLandscape.absolutePriceDiffValue.textColor = .systemRed
} else {
tableViewCellLandscape.priceDirectionImageView.image = UIImage(systemName: "diamond.fill")
tableViewCellLandscape.priceDirectionImageView.tintColor = .white
tableViewCellLandscape.relativePriceDiffValue.text = "0.00%"
tableViewCellLandscape.relativePriceDiffValue.textColor = .white
tableViewCellLandscape.absolutePriceDiffValue.text = "(0.00)"
tableViewCellLandscape.absolutePriceDiffValue.textColor = .white
}
} else {
tableViewCellLandscape.priceDirectionImageView.image = UIImage()
tableViewCellLandscape.priceDirectionImageView.tintColor = .white
tableViewCellLandscape.relativePriceDiffValue.text = ""
tableViewCellLandscape.absolutePriceDiffValue.text = ""
}
return tableViewCellLandscape
}
}
// MARK: - TableView Delegate Methods
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100.0
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
companyDetailsVC = CompanyDetailsVC(companyStockInfo: companyStockInfo[indexPath.row])
tableRowSelected = indexPath.row
navigationController?.pushViewController(companyDetailsVC!, animated: true)
}
// MARK: - Helper Functions
private func configureNavigationBar() {
UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
navigationController?.navigationBar.topItem?.title = "Trade Tracker"
navigationController?.navigationBar.barStyle = .black
navigationController?.navigationBar.prefersLargeTitles = true
}
private func configureTableView() {
tableView.delegate = self
tableView.dataSource = self
tableView.separatorStyle = .singleLine
tableView.separatorColor = .white
tableView.tableFooterView = UIView()
}
private func configureConstraints() {
tableView.addSubview(activityIndicator)
NSLayoutConstraint.activate([
activityIndicator.centerXAnchor.constraint(equalTo: tableView.centerXAnchor),
activityIndicator.topAnchor.constraint(equalTo: tableView.topAnchor, constant: 250)
])
tableView.layoutSubviews()
}
}
// MARK: - Network Service Delegate Method
extension CompanyPriceListVC: NetworkServicesDelegate {
func sendStockInfo(stocksInfo: [String : StockInfo]) {
DispatchQueue.main.async {
// Compute absolute and relative price differences
for (index, symbol) in self.companyStockSymbols.enumerated() {
if stocksInfo[symbol] != nil {
self.priceHistory[index].previous = self.companyStockInfo[index].price
self.companyStockInfo[index] = stocksInfo[symbol]!
var latestPrice = self.companyStockInfo[index].price
latestPrice = round(latestPrice * 100.0) / 100.00
if let previous = self.priceHistory[index].previous {
let previousPrice = round(previous * 100.0) / 100.0
var absoluteDifference = latestPrice - previousPrice
absoluteDifference = round(absoluteDifference * 100.0) / 100.0
self.priceHistory[index].absolute = absoluteDifference
var relativeDifference = 0.0
if previousPrice != 0.00 {
relativeDifference = (absoluteDifference / previousPrice) * 100.0
relativeDifference = round(relativeDifference * 100) / 100.0
}
self.priceHistory[index].relative = relativeDifference
}
}
}
self.tableView.reloadData()
self.activityIndicator.stopAnimating()
guard let rowSelected = self.tableRowSelected else { return }
self.companyDetailsVC!.companyStockInfo = self.companyStockInfo[rowSelected]
self.companyDetailsVC!.relativeDifference = self.priceHistory[rowSelected].relative
self.companyDetailsVC!.absoluteDifference = self.priceHistory[rowSelected].absolute
}
}
}
and here is my network services class;
import UIKit
import Starscream
import Network
protocol NetworkServicesDelegate: AnyObject {
func sendStockInfo(stocksInfo: [String: StockInfo])
}
final class NetworkServices {
static let sharedInstance = NetworkServices()
var request = URLRequest(url: FINNHUB_SOCKET_STOCK_INFO_URL!)
var socket: WebSocket!
public private(set) var isConnected = false
var stocksInfo: [String: StockInfo] = [:]
var socketResults: [String: [StockInfo]] = [:]
weak var delegate: NetworkServicesDelegate?
var stockSymbols: [String] = []
private init() {
request.timeoutInterval = 5
socket = WebSocket(request: request)
socket.delegate = self
}
private let queue = DispatchQueue.global()
private let monitor = NWPathMonitor()
public func startMonitoring() {
monitor.start(queue: queue)
self.monitor.pathUpdateHandler = { [weak self] path in
if path.status == .satisfied {
// connect the socket
self?.socket.connect()
} else {
// disconnect the socket
self?.socket.disconnect()
// post notification that socket is now disconnected
DispatchQueue.main.async {
let name = Notification.Name(rawValue: isDisconnectedNotificationKey)
NotificationCenter.default.post(name: name, object: nil)
}
}
}
}
public func stopMonitoring() {
monitor.cancel()
}
func fetchStockInfo(symbols: [String], delegate: CompanyPriceListVC) {
stockSymbols = symbols
self.delegate = delegate
for symbol in symbols {
let string = FINNHUB_SOCKET_MESSAGE_STRING + symbol + "\"}"
socket.write(string: string)
}
}
private func parseJSONSocketData(_ socketString: String) {
self.socketResults = [:]
self.stocksInfo = [:]
let decoder = JSONDecoder()
do {
let socketData = try decoder.decode(SocketData.self, from: socketString.data(using: .utf8)!)
guard let stockInfoData = socketData.data else { return }
for stockInfo in stockInfoData {
let symbol = stockInfo.symbol
if self.socketResults[symbol] == nil {
self.socketResults[symbol] = [StockInfo]()
}
self.socketResults[symbol]?.append(stockInfo)
}
for (symbol, stocks) in self.socketResults {
for item in stocks {
if self.stocksInfo[symbol] == nil {
self.stocksInfo[symbol] = item
} else if item.timestamp > self.stocksInfo[symbol]!.timestamp {
self.stocksInfo[symbol] = item
}
}
}
self.delegate?.sendStockInfo(stocksInfo: self.stocksInfo)
} catch {
print("DEBUG: error: \(error.localizedDescription)")
}
}
func fetchCompanyInfo(symbol: String, completion: #escaping (CompanyInfo?, UIImage?)->()) {
let urlString = FINNHUB_HTTP_COMPANY_INFO_URL_STRING + symbol + "&token=" + FINNHUB_API_TOKEN
guard let url = URL(string: urlString) else { return }
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
print("Error fetching company info: \(error)")
}
guard let data = data else { return }
let decoder = JSONDecoder()
do {
let companyInfo = try decoder.decode(CompanyInfo.self, from: data)
guard let logoURL = URL(string: companyInfo.logo) else { return }
let task = URLSession.shared.dataTask(with: logoURL) { data, response, error in
if let error = error {
print("Error fetching logo image: \(error)")
}
guard let data = data else { return }
guard let logoImage = UIImage(data: data) else { return }
completion(companyInfo, logoImage)
}
task.resume()
} catch {
print("Error decoding JSON: \(error)")
completion(nil, nil)
}
}
task.resume()
}
}
extension NetworkServices: WebSocketDelegate {
func didReceive(event: WebSocketEvent, client: WebSocket) {
switch event {
case .connected(_):
self.isConnected = true
// post notification that socket is now connected
let name = Notification.Name(rawValue: isConnectedNotificationKey)
NotificationCenter.default.post(name: name, object: nil)
case .disconnected(let reason, let code):
print("DEBUG: Got disconnected.")
self.isConnected = false
case .cancelled:
print("DEBUG: cancelled.")
// post notification that socket is not connected
case .reconnectSuggested(let suggestReconnect):
print("DEBUG: suggestReconnect = \(suggestReconnect)")
// post notification that socket is not connected
case .viabilityChanged(let viabilityChanged):
print("DEBUG: viabilityChange = \(viabilityChanged)")
case .error(let error):
print("DEBUG error: \(String(describing: error?.localizedDescription))")
case .text(let socketString):
parseJSONSocketData(socketString)
default:
break
}
}
}
I've tried querying the isBeingPresented property of the alert controller but it always tests as false even though I can see the alert controller is being presented.
You could do a check if the currently presented UIViewController is actually the alertController like this:
#objc public func dismissAndFetchStockInfo() {
if presentedViewController == alertController {
alertController.dismiss(animated: true, completion: nil)
}
fetchStockInfo()
}
This is because isBeingPresented is only valid inside the view[Will|Did][Disa|A]ppear methods.

Custom Collection View layout: 'Invalid parameter not satisfying: self.supplementaryViewProvider'

I am using two collectionViews in my view controller. 1 has a custom layout and custom attributes for its supplementary views.
Here is the view controller:
class ProgressViewController: UIViewController {
private lazy var data = fetchData()
private lazy var recordsDataSource = makeRecordsDataSource()
private lazy var timelineDataSource = makeTimelineDataSource()
fileprivate typealias RecordsDataSource = UICollectionViewDiffableDataSource<YearMonthDay, TestRecord>
fileprivate typealias RecordsDataSourceSnapshot = NSDiffableDataSourceSnapshot<YearMonthDay, TestRecord>
fileprivate typealias TimelineDataSource = UICollectionViewDiffableDataSource<TimelineSection,YearMonthDay>
fileprivate typealias TimelineDataSourceSnapshot = NSDiffableDataSourceSnapshot<TimelineSection,YearMonthDay>
private var timelineMap = TimelineMap()
private var curItemIndex = 0
private var curRecordsOffset: CGFloat = 0
private var curTimelineOffset: CGFloat = 0
private var timelineStart: Date?
#IBOutlet var recordsCollectionView: UICollectionView!
#IBOutlet var timelineCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
data = fetchData()
timelineStart = Array(data.keys).first?.date
configureRecordsDataSource()
configureTimelineDataSource()
configureTimelineSupplementaryViews()
applyRecordsSnapshot()
applyTimelineSnapshot()
if let collectionViewLayout = timelineCollectionView.collectionViewLayout as? TimelineLayout {
collectionViewLayout.delegate = self
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
var i: CGFloat = 0
for _ in data {
let recordOffset = self.recordsCollectionView.frame.width * i
let timelineOffset = (timelineCollectionView.frame.width + CGFloat(10)) * i
timelineMap.set(recordOffset: recordOffset, timelineOffset: timelineOffset)
i += 1
}
}
private func fetchData() -> [YearMonthDay:[TestRecord]] {
var data: [YearMonthDay:[
TestRecord]] = [:]
var testRecords:[TestRecord] = []
for i in 0...6{
let testRecord = TestRecord(daysBack: i*2, progression: 0)
testRecords.append(testRecord)
}
for record in testRecords {
let ymd = YearMonthDay(date:record.timeStamp,records: [])
if var day = data[ymd] {
day.append(record)
} else {
data[ymd] = [record]
}
}
return data
}
extension ProgressViewController {
//RECORDS data
fileprivate func makeRecordsDataSource() -> RecordsDataSource {
let dataSource = RecordsDataSource(
collectionView: recordsCollectionView,
cellProvider: { (collectionView, indexPath, testRecord) ->
UICollectionViewCell? in
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: RecordCollectionViewCell.identifier, for: indexPath) as? RecordCollectionViewCell
cell?.configure(with: testRecord)
return cell
})
return dataSource
}
func configureRecordsDataSource() {
self.recordsCollectionView.register(RecordCollectionViewCell.nib, forCellWithReuseIdentifier: RecordCollectionViewCell.identifier)
}
func applyRecordsSnapshot() {
// 2
var snapshot = RecordsDataSourceSnapshot()
for (ymd,records) in data {
snapshot.appendSections([ymd])
snapshot.appendItems(records,toSection: ymd)
}
recordsDataSource.apply(snapshot, animatingDifferences: false)
}
}
extension ProgressViewController {
enum TimelineSection {
case main
}
fileprivate func makeTimelineDataSource() -> TimelineDataSource {
let dataSource = TimelineDataSource(
collectionView: self.timelineCollectionView,
cellProvider: { (collectionView, indexPath, testRecord) ->
UICollectionViewCell? in
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TimelineDayCell.identifier, for: indexPath) as? TimelineDayCell
cell?.backgroundColor = .orange
cell?.dayLabel.text = String(indexPath.section)+","+String(indexPath.row)
return cell
})
return dataSource
}
func configureTimelineDataSource() {
self.timelineCollectionView!.register(TimelineDayCell.nib, forCellWithReuseIdentifier: TimelineDayCell.identifier)
timelineCollectionView.register(
UINib(nibName: "MonthHeader", bundle: nil),
forSupplementaryViewOfKind: TimelineLayout.Element.month.kind,
withReuseIdentifier: TimelineLayout.Element.month.id)
timelineCollectionView.register(
UINib(nibName: "TimelineDayCell", bundle: nil),
forSupplementaryViewOfKind: TimelineLayout.Element.day.kind,
withReuseIdentifier: TimelineLayout.Element.day.id)
timelineCollectionView.register(
UINib(nibName: "YearLabel", bundle: nil),
forSupplementaryViewOfKind: TimelineLayout.Element.year.kind,
withReuseIdentifier: TimelineLayout.Element.year.id)
}
func applyTimelineSnapshot(animatingDifferences: Bool = false) {
// 2
var snapshot = TimelineDataSourceSnapshot()
snapshot.appendSections([.main])
snapshot.appendItems(Array(data.keys))
timelineDataSource.apply(snapshot, animatingDifferences: animatingDifferences)
}
func configureTimelineSupplementaryViews(){
timelineDataSource.supplementaryViewProvider = { (
collectionView: UICollectionView,
kind: String,
indexPath: IndexPath) -> UICollectionReusableView? in
switch kind {
case TimelineLayout.Element.month.kind:
let supplementaryView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: TimelineLayout.Element.month.id, for: indexPath)
if let monthLabelView = supplementaryView as? MonthHeader {
let active = Calendar.current.date(byAdding: .month, value: indexPath.item, to: self.timelineStart!)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM"
let monthString = dateFormatter.string(from: active!)
monthLabelView.monthLabel.text = monthString
}
return supplementaryView
case TimelineLayout.Element.year.kind:
let supplementaryView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: TimelineLayout.Element.year.id, for: indexPath)
if let yearLabelView = supplementaryView as? YearLabel {
let labelDate = Calendar.current.date(byAdding: .year, value: indexPath.item, to: self.timelineStart!)!
let year = Calendar.current.component(.year, from: labelDate)
yearLabelView.yearLabel.text = String(year)
}
return supplementaryView
default:
fatalError("This should never happen!!")
}
}
}
}
extension ProgressViewController: TimelineLayoutDelegate {
func collectionView(_ collectionView: UICollectionView, dateAtIndexPath indexPath: IndexPath) -> Date? {
return timelineDataSource.itemIdentifier(for: indexPath)?.date
}
}
Then in my custom TimelineLayout I have
class TimelineLayout: UICollectionViewLayout {
weak var delegate: TimelineLayoutDelegate!
enum Element: String {
case day
case month
case year
var id: String {
return self.rawValue
}
var kind: String {
return "Kind\(self.rawValue.capitalized)"
}
}
private var oldBounds = CGRect.zero
private var visibleLayoutAttributes = [UICollectionViewLayoutAttributes]()
private var contentWidth = CGFloat()
private var cache = [Element: [IndexPath: UICollectionViewLayoutAttributes]]()
private var monthHeight: CGFloat = 19
private var yearHeight: CGFloat = 11
private var dayHeight: CGFloat = 30
private var cellWidth: CGFloat = 2.5
private var collectionViewStartY: CGFloat {
guard let collectionView = collectionView else {
return 0
}
return collectionView.bounds.minY
}
private var collectionViewHeight: CGFloat {
return collectionView!.frame.height
}
override public var collectionViewContentSize: CGSize {
return CGSize(width: contentWidth, height: collectionViewHeight)
}
}
extension TimelineLayout {
override public func prepare() {
guard let collectionView = collectionView,
cache.isEmpty else {
return
}
collectionView.decelerationRate = .fast
updateInsets()
cache.removeAll(keepingCapacity: true)
cache[.year] = [IndexPath: UICollectionViewLayoutAttributes]()
cache[.month] = [IndexPath: UICollectionViewLayoutAttributes]()
cache[.day] = [IndexPath: UICollectionViewLayoutAttributes]()
oldBounds = collectionView.bounds
var timelineStart: Date?
var timelineEnd: Date?
for item in 0 ..< collectionView.numberOfItems(inSection: 0) {
let cellIndexPath = IndexPath(item: item, section: 0)
guard let cellDate = delegate.collectionView(collectionView, dateAtIndexPath: cellIndexPath) else {
return
}
if item == 0 {
let firstDate = cellDate
timelineStart = Calendar.current.startOfDay(for: firstDate)
}
if item == collectionView.numberOfItems(inSection: 0) - 1 {
timelineEnd = cellDate
}
let startX = CGFloat(cellDate.days(from: timelineStart!)) * cellWidth
let dayCellattributes = UICollectionViewLayoutAttributes(forCellWith: cellIndexPath)
dayCellattributes.frame = CGRect(x: startX, y: collectionViewStartY + yearHeight + monthHeight, width: cellWidth, height: dayHeight)
cache[.day]?[cellIndexPath] = dayCellattributes
contentWidth = max(startX + cellWidth,contentWidth)
}
///TODO - what if there are no items in the section....
guard let monthStart = timelineStart?.startOfMonth(), let monthEnd = timelineEnd?.endOfMonth() else { return }
let begin = Calendar.current.date(byAdding: .month, value: -4, to: monthStart)
let end = Calendar.current.date(byAdding: .month, value: 4, to: monthEnd)
var date: Date = begin!
let initalOffset = CGFloat((timelineStart?.days(from: date))!) * cellWidth
var monthOffset: CGFloat = 0
var monthIndex: Int = 0
var yearIndex: Int = 0
while date <= end! {
let daysInMonth = Calendar.current.range(of: .day, in: .month, for: date)?.count
let monthWidth = cellWidth * CGFloat(daysInMonth!)
//let monthIndex = date.months(from: timelineStart!)
let monthLabelIndexPath = IndexPath(item: monthIndex, section: 0)
let monthLabelAttributes = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: Element.month.kind, with: monthLabelIndexPath)
let startX = monthOffset - initalOffset
monthLabelAttributes.frame = CGRect(x: startX, y: collectionViewStartY + yearHeight, width: monthWidth, height: monthHeight)
print(startX,"spaghet")
cache[.month]?[monthLabelIndexPath] = monthLabelAttributes
monthOffset += monthWidth
if Calendar.current.component(.month, from: date) == 1 || yearIndex == 0 {
//draw year
//let year = Calendar.current.component(.year, from: date)
//let yearIndex = date.years(from: timelineStart!)
let daysFromStartOfYear = date.days(from: date.startOfYear())
let startYearX = startX - CGFloat(daysFromStartOfYear) * cellWidth
let yearLabelIndexPath = IndexPath(item: yearIndex, section: 0)
let yearLabelAttributes = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: Element.year.kind, with: yearLabelIndexPath)
yearLabelAttributes.frame = CGRect(x: startYearX, y: collectionViewStartY, width: CGFloat(30), height: yearHeight)
cache[.year]?[yearLabelIndexPath] = yearLabelAttributes
yearIndex += 1
}
date = Calendar.current.date(byAdding: .month, value: 1, to: date)!
monthIndex += 1
}
}
}
extension TimelineLayout {
public override func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
switch elementKind {
case Element.year.kind:
return cache[.year]?[indexPath]
default:
return cache[.month]?[indexPath]
}
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
visibleLayoutAttributes.removeAll(keepingCapacity: true)
if let yearAttrs = cache[.year], let monthAttrs = cache[.month], let dayAttrs = cache[.day] {
for (_, attributes) in yearAttrs {
if attributes.frame.intersects(rect) {
visibleLayoutAttributes.append(attributes)
}
}
for (_, attributes) in monthAttrs {
if attributes.frame.intersects(rect) {
visibleLayoutAttributes.append(attributes)
}
}
for (_, attributes) in dayAttrs {
if attributes.frame.intersects(rect) {
visibleLayoutAttributes.append(attributes)
}
// visibleLayoutAttributes.append(self.shiftedAttributes(from: attributes))
}
}
return visibleLayoutAttributes
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
guard let attributes = cache[.day]?[indexPath] else { fatalError("No attributes cached") }
return attributes
// return shiftedAttributes(from: attributes)
}
override public func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
if oldBounds.size != newBounds.size {
cache.removeAll(keepingCapacity: true)
}
return true
}
override func invalidateLayout(with context: UICollectionViewLayoutInvalidationContext) {
if context.invalidateDataSourceCounts { cache.removeAll(keepingCapacity: true) }
super.invalidateLayout(with: context)
}
}
As you can see I do create timelineDataSource supplementary View Provider in the view controller. Then in the Timeline Layout I implement layoutAttributesForElements(in rect: CGRect) and layoutAttributesForSupplementaryView(ofKind .... The latter never gets called - the error comes first. layoutAttributesForElements(in rect: CGRect) does get called and filled with dayAttrs, monthAttrs, and yearAttrs. However still, the error occurs afterwards:
libc++abi.dylib: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: self.supplementaryViewProvider || (self.supplementaryReuseIdentifierProvider && self.supplementaryViewConfigurationHandler)'
terminating with uncaught exception of type NSException
What am I missing?
Edit: I want to add the detail that when I put a breakpoint in that supplementaryViewProvider it's never called. So maybe I am doing something wrong in layoutAttributesForElements(in Rect?)

ALAMOFIRE post request image download and binding in a UICollectionView

I need to download images I created a alamofire post request with parameter i dont have any problem in that . After that i need to download the image url from the Json response generated, I dont know how to download the image url from json and keep that in a array , after that have to download the inage from the url need to bind it in a image view of collectionView . I dont have any idea about how to take the image url from the json response then keep that in a array , then have to download the image bind it in a collectionView. Please help me
I have updated the json response for my post request. please give me a solution. I can get the below response in console.
( {
ActualPrice = 0;
AssuredTitle = "<null>";
CashBackAmount = 0;
CashBackDiscountPercentage = 0;
Code = "";
Cost = "<null>";
CreateDate = "<null>";
CustomSize = 0;
Delivery = "<null>";
DeliveryDate = "<null>";
DeliveryDays = "<null>";
Designer = "<null>";
Discount = "<null>";
DiscountCost = "<null>";
DispatchDateDisplay = "<null>";
Exclusive = "<null>";
Gender = "<null>";
HasReadyMadeColor = 0;
HasReadyMadeSizes = 0;
ID = 41;
ImageUrl = "https://images.cbazaar.com/images/aqua-blue-georgette-abaya-isbs1805991-u.jpg";
Is7DD = "<null>";
IsCustomizable = 0;
IsExclusive = 0;
IsFree = "<null>";
IsFreeShipping = 0;
IsInWishlist = 0;
IsLookUp = 0;
IsNew = 0;
IsProductAnimation = 0;
IsReadyToShip = 0;
LargeImageUrl = "<null>";
ListingImage = "<null>";
LowerLargeImage = "<null>";
LowerThumbImage = "<null>";
MoneyFactor = "<null>";
MoneyOffFactor = "<null>";
Name = "Islamic wear";
OfferImageUrl = "<null>";
OldPrice = 0;
OutOfStock = 0;
PDUrl = "<null>";
ProductBigLink = "<null>";
ProductCollectionReference = "<null>";
ProductHisImage = "<null>";
ProductSaleCycle = 0;
ProductType = 168;
ProductV2VRatio = 0;
PromotionTypeID = "<null>";
Promotions = "<null>";
PromotionsIcon = "<null>";
Rating = "<null>";
SalePrice = "<null>";
ShowOldPrice = 0;
SizeChart = "<null>";
SuperClassification = "<null>";
TypeGroup = "<null>";
TypeShortCode = "<null>";
UpperLargeImage = "<null>";
UpperThumbImage = "<null>";
VendorType = "<null>";
VisitCount = 0;
})
Complete ViewController File
import UIKit
import Alamofire
import AlamofireImage
class EthnoVogueDesignConsultationViewController: UIViewController, UIScrollViewDelegate, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var header_scrollView: UIScrollView!
#IBOutlet weak var pagecontroller: UIPageControl!
#IBOutlet weak var step_label: UILabel!
#IBOutlet weak var segmented_View: UIView!
#IBOutlet weak var segmented_Control: UISegmentedControl!
#IBOutlet weak var stylistView: UIView!
#IBOutlet weak var categorycollectionview: UICollectionView!
#IBOutlet weak var pagecontrollerview: UIView!
let image_array = ["slider1","slider2","slider1","slider2"]
let name_label = ["Salwar kameez","saree", "Anarkali", "Leghenga"]
static var deepLinkingFlag:Int = 0
static var deepLinkingFlagAfterKilling:Int = 0
var httpObj = HTTPHelper()
var apiRequestParameters:NSMutableDictionary = NSMutableDictionary()
var dictResult: NSDictionary = NSDictionary()
// var imageCache = [String:UIImage]()
//Array of images from the URL
var imageArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
globalConstants.deepLinkingFlagAfterKilling = 0
globalConstants.deepLinkingFlag = 0
apiclass()
// imagedownload()
//View which holds the stylist Name
stylistView.backgroundColor = UIColor(red: 235/255, green: 232/255, blue: 232/255, alpha: 1)
pagecontrollerview.backgroundColor = UIColor(red: 235/255, green: 232/255, blue: 232/255, alpha: 1)
//Label with holds the step 1
step_label.layer.borderWidth = 2
step_label.layer.borderColor = UIColor(red: 249/255, green: 8/255, blue: 129/255, alpha: 1).cgColor
stylistView.layer.shadowOffset = CGSize(width: 1, height: 1)
step_label.layer.shadowOpacity = 4
step_label.layer.shadowColor = UIColor(red: 249/255, green: 8/255, blue: 129/255, alpha: 1).cgColor
//Customising the segmented control with background color and tint color, font size
segmented_Control.tintColor = UIColor(red: 249/255, green: 8/255, blue: 129/255, alpha: 1)
segmented_Control.backgroundColor = UIColor.white
segmented_Control.layer.cornerRadius = 20
// let font = UIFont.systemFont(ofSize: 20)
let font = UIFont.boldSystemFont(ofSize: 20)
segmented_Control.setTitleTextAttributes([NSAttributedStringKey.font: font],
for: .normal)
let cellSize = CGSize(width:250 , height:400)
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.itemSize = cellSize
layout.sectionInset = UIEdgeInsets(top: 1, left: 1, bottom: 1, right: 1)
layout.minimumLineSpacing = 10.0
layout.minimumInteritemSpacing = 10.0
categorycollectionview.setCollectionViewLayout(layout, animated: true)
categorycollectionview.setCollectionViewLayout(layout, animated: false)
categorycollectionview.delegate = self
categorycollectionview.dataSource = self
// Do any additional setup after loading the view, typically from a nib.
self.header_scrollView.frame = CGRect(x:0, y:0, width:self.view.frame.width, height:225)
let scrollViewWidth:CGFloat = self.header_scrollView.frame.width
let scrollViewHeight:CGFloat = self.header_scrollView.frame.height
header_scrollView.backgroundColor = UIColor.black
//set image to the particular image in uiscrollview
let imgOne = UIImageView(frame: CGRect(x:0, y:0,width:scrollViewWidth, height:scrollViewHeight))
imgOne.image = UIImage(named: "slider2")
let imgTwo = UIImageView(frame: CGRect(x:scrollViewWidth, y:0,width:scrollViewWidth, height:scrollViewHeight))
imgTwo.image = UIImage(named: "slider1")
//Adding subview for the scrollview
self.header_scrollView.addSubview(imgOne)
self.header_scrollView.addSubview(imgTwo)
//setting size of the content view
self.header_scrollView.contentSize = CGSize(width:self.header_scrollView.frame.width * 4, height:self.header_scrollView.frame.height)
//header scroll view delegate selection
self.header_scrollView.delegate = self
self.pagecontroller.currentPage = 0
// time interval to move the slide show
Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(moveToNextPage), userInfo: nil, repeats: true)
//step label for rounded corners
step_label.layer.masksToBounds = true
step_label.layer.cornerRadius = 15.0
NotificationCenter.default.addObserver(self, selector: #selector(EthnoVogueDesignConsultationViewController.deepLinking(_:)), name:NSNotification.Name(rawValue: "deepLinking"), object: nil)
}
#objc func deepLinking(_ notification:Notification){
print("its here")
// globalConstants.isSortCleared = 0
if(globalConstants.deepLinkingFlag == 1){
self.tabBarController?.selectedIndex = 0
// let viewController = self.storyboard?.instantiateViewController(withIdentifier:"catalog") as? CatalogController
// self.navigationController?.pushViewController(viewController!, animated: false)
}
else if(globalConstants.deepLinkingFlag == 2){
self.tabBarController?.selectedIndex = 0
// let viewController = self.storyboard?.instantiateViewController(withIdentifier:"productDetails") as? ProductDetailViewController
// self.navigationController?.pushViewController(viewController!, animated: false)
}
else if(globalConstants.deepLinkingFlag == 3){
self.tabBarController?.selectedIndex = 0
// let viewController = self.storyboard?.instantiateViewController(withIdentifier:"ols") as? OLSViewController
// self.navigationController?.pushViewController(viewController!, animated: false)
}
else if(globalConstants.deepLinkingFlag == 4){
self.tabBarController?.selectedIndex = 0
// let viewController = self.storyboard?.instantiateViewController(withIdentifier:"home") as? HomeController
// self.navigationController?.pushViewController(viewController!, animated: false)
}
else if(globalConstants.deepLinkingFlag == 5){
//self.navigationController?.popToRootViewControllerAnimated(false)
self.tabBarController?.selectedIndex = 1
}
else if(globalConstants.deepLinkingFlag == 6){
//self.navigationController?.popToRootViewControllerAnimated(false)
self.tabBarController?.selectedIndex = 2
}
else if(globalConstants.deepLinkingFlag == 7){
//self.navigationController?.popToRootViewControllerAnimated(false)
self.tabBarController?.selectedIndex = 0
}
}
// move to next image image view in file
#objc func moveToNextPage (){
let pageWidth:CGFloat = self.header_scrollView.frame.width
let maxWidth:CGFloat = pageWidth * 2
let contentOffset:CGFloat = self.header_scrollView.contentOffset.x
var slideToX = contentOffset + pageWidth
if contentOffset + pageWidth == maxWidth
{
slideToX = 0
}
self.header_scrollView.scrollRectToVisible(CGRect(x:slideToX, y:0, width:pageWidth, height:self.header_scrollView.frame.height), animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//scrollView Method for chaning the page control while swiping the image
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pagenumber = scrollView.contentOffset.x / scrollView.frame.size.width
pagecontroller.currentPage = Int(pagenumber)
}
//CollectionView for Categories image
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
switch segmented_Control.selectedSegmentIndex {
case 0:
return imageArray.count
case 1:
return 10
default:
break
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let Cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imagecell", for: indexPath) as! CategorySegmentCollectionViewCell
let url = NSURL(string: self.imageArray[indexPath.item])!
Cell.category_image.af_setImage(withURL: url as URL, placeholderImage: UIImage(named: "noimage.png"), filter: nil, imageTransition: .noTransition, runImageTransitionIfCached: true, completion: nil)
switch segmented_Control.selectedSegmentIndex{
case 0:
// let img : UIImage = UIImage(named:"pink")!
//
// Cell.category_image.image = img
// Cell.category_name_label.text = name_label[indexPath.item]
break
case 1:
// let img : UIImage = UIImage(named:"dark")!
// Cell.category_image.image = img
// Cell.category_name_label.text = "condition"
break
default:
break
}
//let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "brandCell", for: indexPath) as! BrandCollectionViewCell
// use this to download images
return Cell
}
func collectionView(_ collectionView: UICollectionView, didHighlightItemAt indexPath: IndexPath) {
UIView.animate(withDuration: 0.5) {
if let cell = collectionView.cellForItem(at: indexPath) as? CategorySegmentCollectionViewCell {
cell.category_image.transform = .init(scaleX: 0.95, y: 0.95)
cell.contentView.backgroundColor = UIColor(red: 0.95, green: 0.95, blue: 0.95, alpha: 1)
}
}
}
func collectionView(_ collectionView: UICollectionView, didUnhighlightItemAt indexPath: IndexPath) {
UIView.animate(withDuration: 0.5) {
if let cell = collectionView.cellForItem(at: indexPath) as? CategorySegmentCollectionViewCell {
cell.category_image.transform = .identity
cell.contentView.backgroundColor = .clear
}
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
switch segmented_Control.selectedSegmentIndex{
case 0:
if (collectionView.cellForItem(at: indexPath) as? CategorySegmentCollectionViewCell) != nil {
self.segmented_Control.setEnabled(true, forSegmentAt: 1)
segmented_Control.selectedSegmentIndex = 1
collectionView.reloadData()
//print(cell)
}
break
case 1:
if (collectionView.cellForItem(at: indexPath) as? CategorySegmentCollectionViewCell) != nil {
self.segmented_Control.setEnabled(true, forSegmentAt: 2)
let categoryTaskVC = storyboard?.instantiateViewController(withIdentifier: "fabrics") as! FabricsViewController
self.navigationController?.pushViewController(categoryTaskVC, animated: true)
}
break
default:
break
}
}
override func viewWillAppear(_ animated: Bool) {
if(segmented_Control.selectedSegmentIndex == 0){
self.segmented_Control.setEnabled(false, forSegmentAt: 1)
self.segmented_Control.setEnabled(false, forSegmentAt: 2)
}
}
#IBAction func segmented_tapped_action(_ sender: Any) {
categorycollectionview.reloadData()
}
func apiclass(){
if(globalConstants.prefs.value(forKey: "authToken") == nil){
self.httpObj.getAuthToken()
}
else if(globalConstants.prefs.value(forKey: "authExpireDate") != nil && Date().compare((globalConstants.prefs.value(forKey: "authExpireDate") as? Date)!) == ComparisonResult.orderedDescending){
globalConstants.prefs.setValue(nil, forKey: "authToken")
self.httpObj.getAuthToken()
}
DispatchQueue.main.async(execute: {
if(globalConstants.prefs.value(forKey: "authToken") != nil){
var request:NSMutableURLRequest = NSMutableURLRequest(url: globalConstants.tokenUrl as URL)
let authToken:String = (globalConstants.prefs.value(forKey: "authToken") as? String)!
request = NSMutableURLRequest(url: globalConstants.tokenUrl as URL)
request.addValue("Bearer \(authToken)", forHTTPHeaderField: "Authorization")
request.addValue(UIDevice.current.identifierForVendor!.uuidString, forHTTPHeaderField: "X-Device-ID")
request.addValue((globalConstants.prefs.value(forKey: "UUID") as? String)!, forHTTPHeaderField: "X-Unique-ID")
request.addValue((globalConstants.prefs.value(forKey: "countryCode") as? String)!, forHTTPHeaderField: "X-Country-Code")
request.addValue((globalConstants.prefs.value(forKey: "currencyCode") as? String)!, forHTTPHeaderField: "X-Currency-Code")
request.addValue((globalConstants.prefs.value(forKey: "currencySymbol") as? String)!, forHTTPHeaderField: "X-Currency-Symbol")
request.addValue(String(stringInterpolationSegment: (globalConstants.prefs.value(forKey: "currencyFactor"))!), forHTTPHeaderField: "X-Currency-Factor")
request.addValue((globalConstants.prefs.value(forKey: "appSource") as? String)!, forHTTPHeaderField: "X-App-Source")
request.addValue(globalConstants.appVersion, forHTTPHeaderField: "X-App-Version")
request.addValue(String(stringInterpolationSegment: (globalConstants.prefs.value(forKey: "estoreId") as? Int)!), forHTTPHeaderField: "X-EStore-ID")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
if(globalConstants.prefs.value(forKey: "userEmail") != nil){
request.addValue((globalConstants.prefs.value(forKey: "userEmail") as? String)!, forHTTPHeaderField: "X-Email")
}
if(globalConstants.prefs.value(forKey: "userId") != nil){
request.addValue(String(stringInterpolationSegment: (globalConstants.prefs.value(forKey: "userId"))!), forHTTPHeaderField: "X-User-ID")
}
print(self.apiRequestParameters)
var requestParameters:NSMutableDictionary = NSMutableDictionary()
requestParameters = [
"mode" : "design",
"productGroup" : 0
]
print(requestParameters)
request.url = globalConstants.ESDCUrl as URL
self.httpObj.sendRequest("POST", requestDict: requestParameters, request: request as URLRequest, completion: { (result, error) in
print(result!)
if(error == nil){
guard let json = result as! [[String:Any]]? else{
return
}
print("Response \(json)")
for images in json
{
if let ImageUrl = images["ImageUrl"] as? String
{
self.imageArray.append(ImageUrl)
}
DispatchQueue.main.async {
self.categorycollectionview.reloadData()
}
}
// self.dictResult = result as! NSDictionary
// self.categorycollectionview.reloadData()
//self.collectionView.reloadData()
// let requestDataDict:NSDictionary = incomingRequetArray[0] as! NSDictionary
// let newDict: NSURL = requestDataDict.object(forKey: "ImageUrl") as? NSDictionary
//
}
else{
let alert = UIAlertView()
alert.isHidden = true
alert.addButton(withTitle: "OK")
alert.message = globalConstants.apiErrorMessage
alert.show()
}
})
}
})
}
//typealaising the headerscrollview to the view controller
private typealias Header_scrollView = EthnoVogueDesignConsultationViewController
// extending the header_scrollview
extension Header_scrollView
{
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView){
// Test the offset and calculate the current page after scrolling ends
let pageWidth:CGFloat = scrollView.frame.width
let currentPage:CGFloat = floor((scrollView.contentOffset.x-pageWidth/2)/pageWidth)+1
// Change the indicator
self.pagecontroller.currentPage = Int(currentPage);
UIView.animate(withDuration: 1.0, animations: { () -> Void in
// self.startButton.alpha = 1.0
})
}
}

Apple Mach-O Linker Error (static, not ld)

I have recently encountered the Apple Mach-O Linker Error. Most guides suggest to change bitcode in Build Settings to "No", however it only applies to the ld error, which is different from mine. I will provide a screenshot, please help to fix the bug.
The pod HandySwift is causing the bugs to appear.
Here is the Github code source for it. https://github.com/Flinesoft/HandySwift
It is from the CSV Importer pod on Cocoapods.
https://cocoapods.org/pods/CSVImporter
Click here to look at the overview of the HandySwift files
Click here for the screenshot of the error
Code referencing the error:
"static (extension in HandySwift):Swift.Double.seconds(Swift.Double) -> Swift.Double", referenced from:
//
// CalendarViewController.swift
// DBS
//
// Created by SDG on 18/10/2017.
// Copyright © 2017 DBSSDG. All rights reserved.
//
import UIKit
import JTAppleCalendar
import CSVImporter
import SystemConfiguration
enum EventTypes{
case SE,PH,SH
}
struct events{
var Title : String
var StartDate : Date
var EndDate : Date
var EventType : EventTypes
}
var PassingEvent = ("G7-G11 Mid-year Exam (4-19)", Date(), Date(), EventTypes.SE)
var TodayEvent = [events] ()
extension Array where Element:Equatable {
func removeDuplicates() -> [Element] {
var result = [Element]()
for value in self {
if result.contains(value) == false {
result.append(value)
}
}
return result
}
}
class CalendarViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIViewControllerPreviewingDelegate {
#IBOutlet weak var CalendarView: JTAppleCalendarView!
#IBOutlet weak var CalendarStackView: UIStackView!
#IBOutlet weak var EventsTableView: UITableView!
#IBOutlet weak var StackView: UIStackView!
#IBOutlet weak var year: UILabel!
#IBOutlet weak var month: UILabel!
#IBOutlet weak var todayButton: UIButton!
var didScroll = false
#IBAction func TodayButton(_ sender: Any) {
CalendarView.scrollToDate(Date())
CalendarView.deselectAllDates()
CalendarView.selectDates([Date()])
EventsTableView.reloadData()
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(0.5), execute: {
self.CalendarView.selectDates([Date()])
self.EventsTableView.reloadData()
})
}
var index = 0
var CurrentDayEventsArray = [(Date, events)] ()
var CurrentDay = Date()
var DayEvents = [(Date, events)] ()
var SEBlue = UIColor(red: 97.0/255.0, green: 142.0/255.0, blue: 249.0/255.0, alpha: 1)
var SHOrange = UIColor(red: 1, green: 142.0/255.0, blue: 80.0/255.0, alpha: 1)
var currentmonth : String = ""
let formatter : DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.timeZone = Calendar.current.timeZone
dateFormatter.locale = Calendar.current.locale
dateFormatter.dateFormat = "yyyy MM dd"
return dateFormatter
}()
#IBOutlet weak var DaysStack: UIStackView!
func WillAddCalendar(acrion: UIAlertAction){
let StringURL = "https://calendar.google.com/calendar/ical/g.dbs.edu.hk_tdmjqqq8vlv8keepi7a65f7j7s%40group.calendar.google.com/public/basic.ics"
let url = URL(string: StringURL)!
if isInternetAvailable(){
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}else{
let networkAlert = UIAlertController(title: "ERROR", message: "Please check your network availability.", preferredStyle: .alert)
networkAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
present(networkAlert, animated: true)
}
}
func ShareCalendar(action: UIAlertAction){
let StringURL = "https://calendar.google.com/calendar/ical/g.dbs.edu.hk_tdmjqqq8vlv8keepi7a65f7j7s%40group.calendar.google.com/public/basic.ics"
let url = URL(string: StringURL)!
let ActivityController = UIActivityViewController(activityItems: [url], applicationActivities: nil)
present(ActivityController, animated: true, completion: nil)
}
func ActionSheetFunc(){
//Actions
let AddCalendarAction = UIAlertAction(title: "Add Calendar to Phone", style: .default, handler: WillAddCalendar)
let ShareAction = UIAlertAction(title: "Share Calendar", style: .default, handler: ShareCalendar)
let CancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
//Action Sheet
let ActionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
ActionSheet.addAction(AddCalendarAction)
ActionSheet.addAction(ShareAction)
ActionSheet.addAction(CancelAction)
present(ActionSheet, animated: true)
}
func AllEvents(){
performSegue(withIdentifier: "Calendar to All Events", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Calendar"
setUpCalendarView()
ParseCSV()
//UI Set up
year.frame = CGRect(x: 16, y: self.view.frame.height * 0.125, width: 100, height: 30)
todayButton.frame = CGRect(x: self.view.frame.width - todayButton.frame.size.width - 16, y: year.frame.origin.y, width: 0, height: 30)
todayButton.sizeToFit()
month.frame = CGRect(x: 16, y: year.frame.origin.y + year.frame.size.height, width: self.view.frame.width, height: 30)
CalendarView.frame.size.width = self.view.frame.width
CalendarView.frame.size.height = self.view.frame.height * 0.425
CalendarView.sizeToFit()
CalendarStackView.frame.origin.y = self.view.frame.height * 0.25
CalendarStackView.frame.origin.x = 0
CalendarStackView.frame.size.width = self.view.frame.width
CalendarStackView.frame.size.height = DaysStack.frame.height + CalendarView.frame.height
StackView.frame = CalendarStackView.frame
EventsTableView.frame.origin.y = CalendarStackView.frame.origin.y + CalendarStackView.frame.size.height
EventsTableView.frame.origin.x = 0
EventsTableView.frame.size.width = self.view.frame.width
EventsTableView.frame.size.height = self.view.frame.height - EventsTableView.frame.origin.y
EventsTableView.isScrollEnabled = true
self.registerForPreviewing(with: self, sourceView: EventsTableView)
//let EventsTableViewBottomConstraint = NSLayoutConstraint(item: EventsTableView, attribute: .bottomMargin, relatedBy: .equal, toItem: self.view, attribute: .bottomMargin, multiplier: 1, constant: 0)
//NSLayoutConstraint.activate([EventsTableViewBottomConstraint])
if #available(iOS 11.0, *) {
navigationItem.largeTitleDisplayMode = .never
}
EventsArray = [events]()
TodayEvent = [events]()
CurrentDayEventsArray = [(Date, events)]()
CalendarView.scrollToDate(Date())
TodayButton(self)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let AddCalendar = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(ActionSheetFunc))
let AllEvents = UIBarButtonItem(title: "All Events", style: .plain, target: self, action: #selector(self.AllEvents))
self.navigationItem.rightBarButtonItems = [AddCalendar, AllEvents]
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
CalendarView.selectDates([Date()])
}
func ParseCSV (){
let path = Bundle.main.path(forResource: "2017 - 2018 School Events New", ofType: "csv")!
let importer = CSVImporter<[String: String]>(path: path)
importer.startImportingRecords(structure: { (headerValues) -> Void in
}) { $0 }.onFinish { importedRecords in
for record in importedRecords {
self.formatter.dateFormat = "d/M/yyyy"
let EventStartDate = self.formatter.date(from: record["Start Date"]!)
let EventEndDate = self.formatter.date(from: record["End Date"]!)
let string = record["Title"]!
let input = string
var output = ""
var didColon = false
for i in input{
if didColon{
output += "\(i)"
}
if i == Character(":"){
didColon = true
}
}
output.removeFirst()
switch record["Type"]! {
case "PH" :
EventsArray += [events(Title: output, StartDate: EventStartDate!, EndDate: EventEndDate!, EventType: .PH)]
if EventStartDate! <= Date() && EventEndDate! >= Date(){
TodayEvent += [events(Title: output, StartDate: EventStartDate!, EndDate: EventEndDate!, EventType: .PH)]
}
case "SH" :
EventsArray += [events(Title: output, StartDate: EventStartDate!, EndDate: EventEndDate!, EventType: .SH)]
if EventStartDate! <= Date() && EventEndDate! >= Date(){
TodayEvent += [events(Title: output, StartDate: EventStartDate!, EndDate: EventEndDate!, EventType: .SH)]
}
case "SE" :
EventsArray += [events(Title: output, StartDate: EventStartDate!, EndDate: EventEndDate!, EventType: .SE)]
if EventStartDate! <= Date() && EventEndDate! >= Date(){
TodayEvent += [events(Title: output, StartDate: EventStartDate!, EndDate: EventEndDate!, EventType: .SE)]
}
default:
print("ERROR")
}
}
self.ParseAdoptionTimetable()
for i in TodayEvent{
self.CurrentDayEventsArray += [(Date(), i)]
}
self.EventsTableView.reloadData()
}
}
func ParseAdoptionTimetable(){
// if let url = URL(string: "http://www.dbs.edu.hk/index.php?section=calendar&listall=1") {
// do {
// let html = try String(contentsOf: url)
// for i in html.split(separator: ">") {
// if i.components(separatedBy: " adopts ").count == 2 {
// let String = (i.split(separator: "<")[0])
// print(String)
// //events(Title: i.split(separator: "<")[0], StartDate: <#T##Date#>, EndDate: <#T##Date#>, EventType: <#T##EventTypes#>)
// }
// }
// }catch{
// print("ERROR")
// }
// }
let Formatter = DateFormatter()
Formatter.dateFormat = "dd MM yyyy"
EventsArray += [events(Title: "30/4 Mon Adopts Tue Timetable", StartDate: Formatter.date(from: "30 04 2018")!, EndDate: Formatter.date(from: "30 04 2018")!, EventType: .SE), events(Title: "14/5 Mon Adopts Fri Timetable", StartDate: Formatter.date(from: "14 05 2018")!, EndDate: Formatter.date(from: "14 05 2018")!, EventType: .SE)]
EventsArray = EventsArray.sorted(by: { $0.StartDate <= $1.StartDate })
}
func setUpCalendarView(){
// Set up calendar spacing
CalendarView.minimumLineSpacing = 0
CalendarView.minimumInteritemSpacing = 0
// Set up labels
CalendarView.visibleDates{(visibleDates) in
let date = visibleDates.monthDates.first!.date
self.formatter.dateFormat = "yyyy"
self.year.text = self.formatter.string(from: date)
if self.year.text == self.formatter.string(from: Date()){
self.year.textColor = UIColor.red
} else {
self.year.textColor = UIColor.black
}
self.formatter.dateFormat = "MMMM"
self.month.text = self.formatter.string(from: date)
self.currentmonth = self.formatter.string(from: date)
if self.month.text == self.formatter.string(from: Date()){
self.month.textColor = UIColor.red
} else {
self.month.textColor = UIColor.black
}
}
}
func handleCellTextColor(view: JTAppleCell?, cellState: CellState) {
guard let validCell = view as? CustomCell else { return }
if cellState.isSelected {
validCell.selectedView.isHidden = false
} else {
validCell.selectedView.isHidden = true
}
}
func LoadEvents(view: JTAppleCell?, cellState: CellState) -> Any {
guard let validCell = view as? CustomCell else {return "Load Events Error"}
let CellDate = cellState.date
var CellDateEventsArray = [(Date, events)] ()
for event in EventsArray{
let EventStartDate = event.StartDate
let EventEndDate = event.EndDate
if CellDate >= EventStartDate && CellDate <= EventEndDate{
CellDateEventsArray += [(CellDate, event)]
}
}
CurrentDayEventsArray = CellDateEventsArray
if cellState.date == Date(){
self.EventsTableView.reloadData()
}
//CurrentDate = cellState.date
return CellDateEventsArray
}
func handleCellSelected(view: JTAppleCell?, cellState: CellState) {
guard let validCell = view as? CustomCell else { return }
var isPublicHoliday = false
for i in CurrentDayEventsArray{
if i.1.EventType == .PH{
isPublicHoliday = true
}
}
if cellState.isSelected {
validCell.datelabel.textColor = UIColor.white
}else{
if cellState.dateBelongsTo == .thisMonth{
//validCell.datelabel.textColor = UIColor.init(red: 253/255.0, green: 114/255.0, blue: 116.0/255.0, alpha: 1.0)
if cellState.day == .sunday || isPublicHoliday{
validCell.datelabel.textColor = UIColor.red
}else{
validCell.datelabel.textColor = UIColor.black
}
validCell.isUserInteractionEnabled = true
}else{
validCell.datelabel.textColor = UIColor.lightGray
//validCell.isUserInteractionEnabled = false
}
}
}
func setUpViewsForCalendar(from visibleDates: DateSegmentInfo){
let date = visibleDates.monthDates.first!.date
self.formatter.dateFormat = "yyyy"
self.year.text = self.formatter.string(from: date)
self.formatter.dateFormat = "MMMM"
self.month.text = self.formatter.string(from: date)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var count = 0
for _ in CurrentDayEventsArray{
count += 1
}
if count == 0{
return 1
}
return count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
DayEvents = CurrentDayEventsArray
let cell = tableView.dequeueReusableCell(withIdentifier: "CalendarEventCell")! as UITableViewCell
cell.isUserInteractionEnabled = true
if CurrentDayEventsArray.isEmpty{
cell.textLabel?.text = "No events"
cell.textLabel?.textAlignment = .center
cell.detailTextLabel?.text = ""
cell.imageView?.image = nil
cell.isUserInteractionEnabled = false
cell.accessoryType = .none
return cell
}
//Manage Date
let StartDate = CurrentDayEventsArray[indexPath.row].1.StartDate
let EndDate = CurrentDayEventsArray[indexPath.row].1.EndDate
self.formatter.dateFormat = "d/M"
let StartDateString = formatter.string(from: StartDate)
let EndDateString = formatter.string(from: EndDate)
//Image
let EventType = CurrentDayEventsArray[indexPath.row].1.EventType
if let image = UIImage(named: "dot"){
let tintableImage = image.withRenderingMode(.alwaysTemplate)
cell.imageView?.image = tintableImage
}
switch EventType {
case .PH:
cell.imageView?.tintColor = UIColor.red
case .SH:
cell.imageView?.tintColor = SHOrange
case .SE:
cell.imageView?.tintColor = SEBlue
default:
cell.imageView?.tintColor = UIColor.red
}
//Title
cell.textLabel?.adjustsFontSizeToFitWidth = true
cell.textLabel?.text = String(describing: CurrentDayEventsArray[indexPath.row].1.Title)
//Subtitle
let Subtitle = "\(StartDateString) - \(EndDateString)"
if StartDate != EndDate{
cell.detailTextLabel?.text = Subtitle
}else{
cell.detailTextLabel?.text = StartDateString
}
//Arrow
cell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
//cell.selectionStyle = .gray
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
index = indexPath.row
PassingEvent = (DayEvents[index].1.Title, DayEvents[index].1.StartDate, DayEvents[index].1.EndDate, DayEvents[index].1.EventType)
performSegue(withIdentifier: "Detail Event", sender: self)
}
/*
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let DestViewController = segue.destination as! DetailedEventViewController
DestViewController.PassingEvent = (CurrentDayEventsArray[index].1.Title, CurrentDayEventsArray[index].1.StartDate, CurrentDayEventsArray[index].1.EndDate, CurrentDayEventsArray[index].1.EventType)
}
*/
public func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
guard let indexPath = EventsTableView.indexPathForRow(at: location) else {
return nil
}
previewingContext.sourceRect = EventsTableView.cellForRow(at: indexPath)!.frame
let index = indexPath.row
PassingEvent = (DayEvents[index].1.Title, DayEvents[index].1.StartDate, DayEvents[index].1.EndDate, DayEvents[index].1.EventType)
let destViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Detail Event") as! DetailedEventViewController
return destViewController
return nil
}
public func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
navigationController?.pushViewController(viewControllerToCommit, animated: true)
}
func isInternetAvailable() -> Bool {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {zeroSockAddress in
SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress)
}
}
var flags = SCNetworkReachabilityFlags()
if !SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) {
return false
}
let isReachable = flags.contains(.reachable)
let needsConnection = flags.contains(.connectionRequired)
return (isReachable && !needsConnection)
}
}
extension CalendarViewController: JTAppleCalendarViewDelegate, JTAppleCalendarViewDataSource {
func calendar(_ calendar: JTAppleCalendarView, willDisplay cell: JTAppleCell, forItemAt date: Date, cellState: CellState, indexPath: IndexPath) {
EventsTableView.reloadData()
}
func configureCalendar(_ calendar: JTAppleCalendarView) -> ConfigurationParameters {
formatter.dateFormat = "yyy MM dd"
formatter.timeZone = Calendar.current.timeZone
formatter.locale = Calendar.current.locale
let startDate = formatter.date(from: "2017 09 01")
let endDate = formatter.date(from: "2019 08 31")
let generateInDates: InDateCellGeneration = .forAllMonths
let generateOutDates: OutDateCellGeneration = .tillEndOfGrid
let firstDayOfWeek: DaysOfWeek = .sunday
let parameters = ConfigurationParameters(startDate: startDate!, endDate: endDate!, numberOfRows: 4, calendar: Calendar.current, generateInDates: generateInDates, generateOutDates: generateOutDates, firstDayOfWeek: firstDayOfWeek, hasStrictBoundaries: true)
//let parameters = ConfigurationParameters(startDate: startDate!, endDate: endDate!)
return parameters
}
func calendar(_ calendar: JTAppleCalendarView, cellForItemAt date: Date, cellState: CellState, indexPath: IndexPath) -> JTAppleCell {
let CalendarCell = calendar.dequeueReusableJTAppleCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
CalendarCell.datelabel.text = cellState.text
CalendarCell.selectedView.layer.cornerRadius = CalendarCell.selectedView.frame.width/2
CalendarCell.backgroundColor = UIColor.white
CalendarCell.EventCircle.layer.cornerRadius = CalendarCell.EventCircle.frame.width / 2
CalendarCell.EventCircle.isHidden = true
CalendarCell.SchoolHolidayBar.backgroundColor = self.SHOrange
CalendarCell.SchoolHolidayBar.isHidden = true
CalendarCell.isUserInteractionEnabled = false
if cellState.dateBelongsTo == .thisMonth{
CalendarCell.isSelected = false
}
LoadEvents(view: CalendarCell, cellState: cellState)
for i in CurrentDayEventsArray{
if i.1.EventType == .SH{
CalendarCell.SchoolHolidayBar.isHidden = true
CalendarCell.EventCircle.backgroundColor = SHOrange
CalendarCell.EventCircle.isHidden = false
break
}else if i.1.EventType == .PH{
CalendarCell.datelabel.textColor = UIColor.red
}else if i.1.EventType == .SE{
CalendarCell.EventCircle.backgroundColor = UIColor.lightGray
CalendarCell.EventCircle.isHidden = false
}else{
}
}
if cellState.date == Date(){
LoadEvents(view: CalendarCell, cellState: cellState)
EventsTableView.reloadData()
}
handleCellTextColor(view: CalendarCell, cellState: cellState)
handleCellSelected(view: CalendarCell, cellState: cellState)
return CalendarCell
}
func calendar(_ calendar: JTAppleCalendarView, didSelectDate date: Date, cell: JTAppleCell?, cellState: CellState) {
if didScroll{
calendar.deselect(dates: [CurrentDay])
didScroll = false
}
CurrentDay = date
//calendar.deselectAllDates()
//calendar.selectDates([date])
handleCellTextColor(view: cell, cellState: cellState)
handleCellSelected(view: cell, cellState: cellState)
LoadEvents(view: cell, cellState: cellState)
EventsTableView.reloadData()
}
func calendar(_ calendar: JTAppleCalendarView, didDeselectDate date: Date, cell: JTAppleCell?, cellState: CellState) {
handleCellTextColor(view: cell, cellState: cellState)
handleCellSelected(view: cell, cellState: cellState)
//calendar.deselect(dates: [date])
}
func calendar(_ calendar: JTAppleCalendarView, didScrollToDateSegmentWith visibleDates: DateSegmentInfo) {
let date = visibleDates.monthDates.first!.date
formatter.dateFormat = "yyyy"
year.text = self.formatter.string(from: date)
formatter.dateFormat = "MMMM"
month.text = self.formatter.string(from: date)
setUpCalendarView()
}
func calendarDidScroll(_ calendar: JTAppleCalendarView) {
didScroll = true
}
}
//}
In your TodayButton(_:) instead of:
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(0.5), execute: {
//...
})
do:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
//...
})
That .seconds(Int) takes an Int. So passing a Double in it by doing .seconds(0.5) makes it ambiguous as there is no .seconds(Double) in the DispatchTimeInterval enum.
To achieve this 0.5 second delay you can either do it in 2 ways:
+ 0.5
+ .milliseconds(500)

Set the KILabel or ActiveLabel's height to 0 when it has no string. But Original UILabel is working fine

This question is related the UITableView and UILabel's height.
Hi I'm using the auto layout to set the dynamic Height in rows.
This is my layout in the table's cell.
Description Label
LikeCountLabel is blue color "1"
Comment Label
Time table is grey "Label"
Time Label
I also checked UILabel's property
import UIKit
import Parse
class ShopDetailCell: UITableViewCell {
#IBOutlet weak var commentBtn: UIButton!
#IBOutlet weak var likeBtn: UIButton!
#IBOutlet weak var profileImg: UIImageView!
#IBOutlet weak var postImg: UIImageView!
#IBOutlet weak var moreBtn: UIButton!
#IBOutlet weak var userNameBtn: UIButton!
#IBOutlet weak var uuidLabel: UILabel!
#IBOutlet weak var descriptionLabel: KILabel!
#IBOutlet weak var likesLabel: UILabel!
#IBOutlet weak var commentLabel: KILabel!
#IBOutlet weak var dateLabel: UILabel!
}
My TableView Controller
import UIKit
import Parse
import SDWebImage
class FeedVC: UITableViewController {
//UI Objects
#IBOutlet weak var indicator: UIActivityIndicatorView!
var refresher=UIRefreshControl()
//arrays to hold server data
var profileArray = [PFFile]()
var usernameArray = [String]()
var dateArray = [NSDate?]()
var postArray = [PFFile]()
var uuidArray = [String]()
var descriptionArray = [String]()
var commentsArray = [String]()
var isLoadedView:Bool = false
var sellingArray = [Bool]()
var followArray = [String]()
//advertise
var advArray = [PFFile]()
//page size
var page : Int = 10
//Default func
override func viewDidLoad() {
super.viewDidLoad()
//background color
tableView?.backgroundColor = UIColor(red: 0.0 / 255.0, green: 0.0 / 255.0, blue: 0.0 / 255.0, alpha: 1)
//automatic row height
tableView.estimatedRowHeight = 450
tableView.rowHeight = UITableViewAutomaticDimension
//pull to refresh
refresher.addTarget(self, action: #selector(FeedVC.loadPosts), forControlEvents: UIControlEvents.ValueChanged)
tableView.addSubview(refresher)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(FeedVC.refresh), name: "liked", object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(FeedVC.uploaded(_:)), name: "Uploaded", object: nil)
self.navigationController?.setNavigationBarHidden(true, animated: true)
//calling function to load posts
loadPosts()
//receive notification from UploadViewController
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(FeedVC.scrollToFirstRow(_:)), name: "scrollToTop", object: nil)
}
func scrollToFirstRow(notification:NSNotification) {
if isLoadedView == true {
print("scrollToTop!!!!!")
let indexPath = NSIndexPath(forRow: 0, inSection: 0)
self.tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Top, animated: true)
}
}
// reloading func with posts after received notification
func uploaded(notification:NSNotification){
print("receicev")
loadPosts()
}
//refresh function
func refresh(){
self.tableView.reloadData()
}
// load posts
func loadPosts() {
//STEP 1. Find posts related to people who we are following
let followQuery = PFQuery(className: "fans")
followQuery.whereKey("myfans", equalTo: PFUser.currentUser()!.username!)
followQuery.findObjectsInBackgroundWithBlock ({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
//clean up
self.followArray.removeAll(keepCapacity: false)
//Appending where people following..
//find related objects
for object in objects! {
self.followArray.append(object.objectForKey("fan") as! String)
}
//append current user to see own posts in feed
self.followArray.append(PFUser.currentUser()!.username!)
//STEP 2. Find posts made by people appended to followArray
let query = PFQuery(className: "posts")
query.whereKey("username", containedIn: self.followArray)
query.limit = self.page
query.addDescendingOrder("createdAt")
query.findObjectsInBackgroundWithBlock({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
//clean up
self.usernameArray.removeAll(keepCapacity: false)
self.profileArray.removeAll(keepCapacity: false)
self.dateArray.removeAll(keepCapacity: false)
self.postArray.removeAll(keepCapacity: false)
self.descriptionArray.removeAll(keepCapacity: false)
self.uuidArray.removeAll(keepCapacity: false)
//find related objects
for object in objects! {
self.usernameArray.append(object.objectForKey("username") as! String)
self.profileArray.append(object.objectForKey("profileImg") as! PFFile)
self.dateArray.append(object.createdAt)
self.postArray.append(object.objectForKey("postImg") as! PFFile)
self.descriptionArray.append(object.objectForKey("title") as! String)
self.uuidArray.append(object.objectForKey("uuid") as! String)
}
//reload tableView & end spinning of refresher
self.tableView.reloadData()
self.refresher.endRefreshing()
} else {
print(error!.localizedDescription)
}
})
} else {
print(error!.localizedDescription)
}
})
}
//scrolled down
override func scrollViewDidScroll(scrollView: UIScrollView) {
if scrollView.contentOffset.y >= scrollView.contentSize.height - self.view.frame.size.height * 2 {
loadMore()
}
}
// pagination
func loadMore(){
//if posts on the server are more than shown
if page <= uuidArray.count {
//start animating indicator
indicator.startAnimating()
//increase page size to load + 10 posts
page = page + 10
//STEP 1. Find posts related to people who we are following
let followQuery = PFQuery(className: "fans")
followQuery.whereKey("myfans", equalTo: PFUser.currentUser()!.username!)
followQuery.findObjectsInBackgroundWithBlock ({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
//clean up
self.followArray.removeAll(keepCapacity: false)
//Appending where people following..
//find related objects
for object in objects! {
self.followArray.append(object.objectForKey("fan") as! String)
}
//append current user to see own posts in feed
self.followArray.append(PFUser.currentUser()!.username!)
//STEP 2. Find posts made by people appended to followArray
let query = PFQuery(className: "posts")
query.whereKey("username", containedIn: self.followArray)
query.limit = self.page
query.addDescendingOrder("createdAt")
query.findObjectsInBackgroundWithBlock({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
//clean up
self.usernameArray.removeAll(keepCapacity: false)
self.profileArray.removeAll(keepCapacity: false)
self.dateArray.removeAll(keepCapacity: false)
self.postArray.removeAll(keepCapacity: false)
self.descriptionArray.removeAll(keepCapacity: false)
self.uuidArray.removeAll(keepCapacity: false)
//find related objects
for object in objects! {
self.usernameArray.append(object.objectForKey("username") as! String)
self.profileArray.append(object.objectForKey("profileImg") as! PFFile)
self.dateArray.append(object.createdAt)
self.postArray.append(object.objectForKey("postImg") as! PFFile)
self.descriptionArray.append(object.objectForKey("title") as! String)
self.uuidArray.append(object.objectForKey("uuid") as! String)
}
//reload tableView stop indicator animation
self.tableView.reloadData()
self.indicator.stopAnimating()
} else {
print(error!.localizedDescription)
}
})
} else {
print(error!.localizedDescription)
}
})
}
}
//number of cell
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return uuidArray.count + 1
}
// cell config
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// 가장 첫 페이지는 광고영역..
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCellWithIdentifier("AdvertiseCell", forIndexPath: indexPath) as! AdvertiseCell
return cell
}
//define cell
let cell = tableView.dequeueReusableCellWithIdentifier("ShopDetailCell", forIndexPath: indexPath) as! ShopDetailCell
cell.userNameBtn.setTitle(usernameArray[indexPath.row - 1], forState: UIControlState.Normal)
cell.userNameBtn.sizeToFit()
cell.uuidLabel.text = uuidArray[indexPath.row - 1]
cell.descriptionLabel.text = descriptionArray[indexPath.row - 1]
cell.descriptionLabel.sizeToFit()
// manipulate like button depending on did user like it or not
let isComments = PFQuery(className: "comments")
isComments.whereKey("to", equalTo: cell.uuidLabel.text!)
isComments.limit = 1
isComments.addAscendingOrder("createdAt")
isComments.countObjectsInBackgroundWithBlock({(count:Int32, error:NSError?) -> Void in
//if no any likes are found, else found likes
if count==0 {
cell.commentLabel.text = nil
cell.commentLabel.sizeToFit()
// cell.commentHeight.constant = 0
}else{
//STEP 2. Request last (page size 15) comments
let query = PFQuery(className: "comments")
query.whereKey("to", equalTo: cell.uuidLabel.text!)
query.limit = 1
query.addDescendingOrder("createdAt")
query.findObjectsInBackgroundWithBlock({(objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
//find related object
for object in objects!{
let comment = object.objectForKey("comment") as! String
let by = object.objectForKey("username") as! String
let commentString = by + " " + comment
let boldString = NSMutableAttributedString(string: commentString)
boldString.addAttribute(NSFontAttributeName, value: UIFont(name: "SFUIText-Bold", size: 14)!, range: NSRange(0...by.characters.count))
cell.commentLabel.attributedText = boldString
cell.commentLabel.sizeToFit()
// self.tableView?.reloadData()
}
}else {
print(error?.localizedDescription)
}
})
}
})
//STEP 1. Load data of guest
let profileImgQuery = PFQuery(className: "_User")
profileImgQuery.whereKey("username", equalTo: usernameArray[indexPath.row - 1])
profileImgQuery.findObjectsInBackgroundWithBlock({(objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
//shown wrong user
if objects!.isEmpty {
print("Wrong User")
}
//find related to user information
for object in objects! {
//Set Image
let profilePictureObject = object.objectForKey("profileImg") as? PFFile
profilePictureObject?.getDataInBackgroundWithBlock { (imageData:NSData?, error:NSError?) -> Void in
if(imageData != nil)
{
let profileURL : NSURL = NSURL(string: profilePictureObject!.url!)!
cell.profileImg.sd_setImageWithURL(profileURL, placeholderImage: UIImage(named: "holderImg"))
}
}
}
} else {
print(error?.localizedDescription)
}
})
// place post picture using the sdwebimage
let postURL : NSURL = NSURL(string: postArray[indexPath.row - 1].url!)!
cell.postImg.sd_setImageWithURL(postURL, placeholderImage: UIImage(named: "holderImg"))
//Calculate post date
let from = dateArray[indexPath.row - 1]
let now = NSDate()
let components : NSCalendarUnit = [.Second, .Minute, .Hour, .Day, .WeekOfMonth]
let difference = NSCalendar.currentCalendar().components(components, fromDate: from!, toDate: now, options: [])
// logic what to show : Seconds, minutes, hours, days, or weeks
if difference.second <= 0 {
cell.dateLabel.text = "NOW"
}
if difference.second > 0 && difference.minute == 0 {
cell.dateLabel.text = "\(difference.second) SEC AGO"
}
if difference.minute > 0 && difference.hour == 0 {
cell.dateLabel.text = "\(difference.minute) MIN AGO"
}
if difference.hour > 0 && difference.day == 0 {
cell.dateLabel.text = "\(difference.hour) HR AGO"
}
if difference.day > 0 && difference.weekOfMonth == 0 {
cell.dateLabel.text = "\(difference.day) DAY AGO"
}
if difference.weekOfMonth > 0 {
cell.dateLabel.text = "\(difference.weekOfMonth) WEEK AGO"
}
//
//
// manipulate like button depending on did user like it or not
let didLike = PFQuery(className: "likes")
didLike.whereKey("by", equalTo: PFUser.currentUser()!.username!)
didLike.whereKey("to", equalTo: cell.uuidLabel.text!)
didLike.countObjectsInBackgroundWithBlock({(count:Int32, error:NSError?) -> Void in
//if no any likes are found, else found likes
if count==0 {
cell.likeBtn.setTitle("unlike", forState: .Normal)
cell.likeBtn.setBackgroundImage(UIImage(named:"heartBtn"), forState: .Normal)
}else{
cell.likeBtn.setTitle("like", forState: .Normal)
cell.likeBtn.setBackgroundImage(UIImage(named: "heartTapBtn"), forState: .Normal)
}
})
//count total likes of shown post
let countLikes = PFQuery(className: "likes")
countLikes.whereKey("to", equalTo: cell.uuidLabel.text!)
countLikes.countObjectsInBackgroundWithBlock({(count:Int32, error:NSError?) -> Void in
cell.likesLabel.text="\(count) likes"
})
//asign index
cell.userNameBtn.layer.setValue(indexPath, forKey: "index")
cell.commentBtn.layer.setValue(indexPath, forKey: "index")
cell.moreBtn.layer.setValue(indexPath, forKey: "index")
// #mention is tapped
cell.descriptionLabel.userHandleLinkTapHandler = { label, handle, rang in
var mention = handle
mention = String(mention.characters.dropFirst())
if mention.lowercaseString == PFUser.currentUser()?.username {
let home = self.storyboard?.instantiateViewControllerWithIdentifier("MyShopCollectionVC") as! MyShopCollectionVC
self.navigationController?.pushViewController(home, animated: true)
} else {
guestname.append(mention.lowercaseString)
let guest = self.storyboard?.instantiateViewControllerWithIdentifier("GuestShopCollectionVC") as! GuestShopCollectionVC
self.navigationController?.pushViewController(guest, animated: true)
}
}
// #Hashtag is tapped
cell.descriptionLabel.hashtagLinkTapHandler = {label, handle, range in
var mention = handle
mention = String(mention.characters.dropFirst())
hashtag.append(mention.lowercaseString)
let hashvc = self.storyboard?.instantiateViewControllerWithIdentifier("HashTagsCollectionVC") as! HashTagsCollectionVC
self.navigationController?.pushViewController(hashvc, animated: true)
}
// cell.layoutIfNeeded()
return cell
}
////////
#IBAction func userNameBtnTapped(sender: AnyObject) {
//call index of button
let i = sender.layer.valueForKey("index") as! NSIndexPath
//call cell to call further cell data
let cell = tableView.cellForRowAtIndexPath(i) as! ShopDetailCell
//if user tapped on himeself go home, else go guest
if cell.userNameBtn.titleLabel?.text == PFUser.currentUser()?.username {
let home = self.storyboard?.instantiateViewControllerWithIdentifier("MyShopCollectionVC") as! MyShopCollectionVC
self.navigationController?.pushViewController(home, animated: true)
}else {
guestname.append(cell.userNameBtn.titleLabel!.text!)
let guest = self.storyboard?.instantiateViewControllerWithIdentifier("GuestShopCollectionVC") as! GuestShopCollectionVC
self.navigationController?.pushViewController(guest, animated: true)
}
}
#IBAction func commentBtnTapped(sender: AnyObject) {
print("commentTapped")
// call index of button
let i = sender.layer.valueForKey("index") as! NSIndexPath
// call cell to call further cell data
let cell = tableView.cellForRowAtIndexPath(i) as! ShopDetailCell
//send related data to global variables
commentUUID.append(cell.uuidLabel.text!)
// commentOwner.append(cell.userNameLabel.titleLabel!.text!)
commentOwner.append(cell.userNameBtn.titleLabel!.text!)
let comment = self.storyboard?.instantiateViewControllerWithIdentifier("CommentVC") as! CommentVC
self.navigationController?.pushViewController(comment, animated: true)
}
#IBAction func moreBtnTapped(sender: AnyObject) {
let i = sender.layer.valueForKey("index") as! NSIndexPath
//Call cell to call further cell date
let cell = tableView.cellForRowAtIndexPath(i) as! ShopDetailCell
//Delete Action
let delete = UIAlertAction(title: "Delete", style: .Default) { (UIAlertAction) -> Void in
//STEP 1. Delete row from tablevIEW
self.usernameArray.removeAtIndex(i.row)
self.profileArray.removeAtIndex(i.row)
self.dateArray.removeAtIndex(i.row)
self.postArray.removeAtIndex(i.row)
self.descriptionArray.removeAtIndex(i.row)
self.uuidArray.removeAtIndex(i.row)
//STEP 2. Delete post from server
let postQuery = PFQuery(className: "posts")
postQuery.whereKey("uuid", equalTo: cell.uuidLabel.text!)
postQuery.findObjectsInBackgroundWithBlock({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
for object in objects! {
object.deleteInBackgroundWithBlock({ (success:Bool, error:NSError?) -> Void in
if success {
//send notification to rootViewController to update shown posts
NSNotificationCenter.defaultCenter().postNotificationName("uploaded", object: nil)
//push back
self.navigationController?.popViewControllerAnimated(true)
} else {
print(error?.localizedDescription)
}
})
}
} else {
print(error?.localizedDescription)
}
})
//STEP 2. Delete likes of post from server
let likeQuery = PFQuery(className: "likes")
likeQuery.whereKey("to", equalTo: cell.uuidLabel.text!)
likeQuery.findObjectsInBackgroundWithBlock({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
for object in objects! {
object.deleteEventually()
}
}
})
//STEP 3. Delete comments of post from server
let commentQuery = PFQuery(className: "comments")
commentQuery.whereKey("to", equalTo: cell.uuidLabel.text!)
commentQuery.findObjectsInBackgroundWithBlock({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
for object in objects! {
object.deleteEventually()
}
}
})
//STEP 4. Delete hashtags of post from server
let hashtagQuery = PFQuery(className: "hashtags")
hashtagQuery.whereKey("to", equalTo: cell.uuidLabel.text!)
hashtagQuery.findObjectsInBackgroundWithBlock({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
for object in objects! {
object.deleteEventually()
}
}
})
}
//Complain Action
let complain = UIAlertAction(title: "Complain", style: .Default) { (UIAlertAction) -> Void in
//send complain to server
let complainObj = PFObject(className: "complain")
complainObj["by"] = PFUser.currentUser()?.username
complainObj["to"] = cell.uuidLabel.text
complainObj["owner"] = cell.userNameBtn.titleLabel?.text
complainObj.saveInBackgroundWithBlock({ (success:Bool, error:NSError?) -> Void in
if success {
self.alert("Complain has been made successfully", message: "Thank You! We will consider your complain")
}else {
self.alert("ERROR", message: error!.localizedDescription)
}
})
}
//Cancel ACTION
let cancel = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
//create menu controller
let menu = UIAlertController(title: "Menu", message: nil, preferredStyle: .ActionSheet)
//if post belongs to user
if cell.userNameBtn.titleLabel?.text == PFUser.currentUser()?.username {
menu.addAction(delete)
menu.addAction(cancel)
} else {
menu.addAction(complain)
menu.addAction(cancel)
}
//show menu
self.presentViewController(menu, animated: true, completion: nil)
}
//alert action
func alert(title: String, message:String){
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
let ok = UIAlertAction(title: "OK", style: .Cancel, handler: nil)
alert.addAction(ok)
presentViewController(alert, animated: true, completion: nil)
}
}
Ok My problem is ...If UILabel's string is nil or "" then It's height should be set to zero. Also Table cell's height is smaller than original height.
UILabel has no strings but It still has height.
Seems like this is the issue in the KILabel library, and the solution is (link) to create custom label class, inherit from KILabel and override this method:
- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines {
if (self.text.length == 0) {
return CGRectZero;
}
return [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines];
}
Declare your UILabel height constraint like this:-
#IBOutlet weak var likeLabelHeightConstraint: NSLayoutConstraint!
And set your height like this
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let height : CGFloat = 50 //Default cell Height
if likeLabel.text == nil || likeLabel.text == ""{
height = height - likeLabelHeightConstraint.constant
likeLabelHeightConstraint.constant = 0
}else{
//Set default scenario
}
return height
}
If you are retrieving data asynchronously then make sure you reload your data once your DataSource is updated....