Why my table view disappears after scrolling to the bottom? - ios

I don't know why my table view disappears after I reach the bottom of my table view.
here is the gif file of my problem: http://g.recordit.co/4hizPCyctM.gif
here is my code in my view controller
class CheckoutVC: UIViewController {
#IBOutlet weak var orderButton: DesignableButton!
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var floatingView: UIView!
#IBOutlet weak var totalPriceLabel: UILabel!
private let realm = RealmService.shared.realm
private var products = [Product]()
private var userOrder : Order?
private var productSelected : Product?
private var cartIsEmpty = false
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
RealmService.shared.observerRealmErrors() { (error) in
self.showAlert(alertTitle: "Sorry", alertMessage: error?.localizedDescription ?? "", actionTitle: "OK")
}
userOrder = Order.getOrderFromRealmDatabase()
guard let userOrder = userOrder else {return}
products = Array(userOrder.products)
tableView.reloadData()
totalPriceLabel.text = "Total: \(userOrder.getTotalPriceFormattedWithSeparator())"
updateUI()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
RealmService.shared.stopObservingErrors(in: self)
}
private func updateUI() {
guard let userOrder = userOrder else {return}
if userOrder.products.isEmpty {
tableView.isHidden = true
cartIsEmpty = true
orderButton.setTitle("Pilih Barang", for: .normal)
} else {
tableView.isHidden = false
cartIsEmpty = false
orderButton.setTitle("Pesan Barang", for: .normal)
}
}
}
//MARK: - Table View Delegate & Datasource
extension CheckoutVC : UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return userOrder?.products.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: CheckOutStoryboardData.TableViewIdentifiers.checkOutCell.rawValue, for: indexPath) as? CheckOutCell else {return UITableViewCell()}
guard let userOrderInRealm = userOrder else {return UITableViewCell()}
let products = userOrderInRealm.products
cell.productData = products[indexPath.row]
cell.indexPath = indexPath
cell.delegate = self
let stepperValue = Double(products[indexPath.row].quantity)
cell.stepperValue = stepperValue
return cell
}
}
and here is my code in the table view cell
class CheckOutCell: UITableViewCell {
var indexPath: IndexPath?
var delegate: CheckOutCellDelegate?
#IBOutlet weak var stepperGM: GMStepper!
#IBOutlet weak var productImageView: UIImageView!
#IBOutlet weak var productNameLabel: UILabel!
#IBOutlet weak var subCategoryNameLabel: UILabel!
#IBOutlet weak var pricePerUnitLabel: UILabel!
#IBOutlet weak var priceTotalPerItemLabel: UILabel!
var productData : Product? {
didSet {
updateUI()
}
}
var stepperValue : Double? {
didSet {
setStepper()
}
}
#IBAction func deleteButtonDidPressed(_ sender: Any) {
// send data to CheckoutVC
guard let indexPath = self.indexPath else {return}
self.delegate?.deleteButtonDidTapped(at: indexPath)
}
#IBAction func seeProductButtonDidPressed(_ sender: Any) {
// send data to CheckoutVC
guard let indexPath = self.indexPath else {return}
self.delegate?.viewProductButtonDidTapped(at: indexPath)
}
#IBAction func GMStepperDidTapped(_ sender: GMStepper) {
guard let indexPath = self.indexPath else {return}
let stepperValue = Int(sender.value)
self.delegate?.incrementOrDecrementButtonDidTapped(at: indexPath, counterValue: stepperValue)
}
func setStepper() {
guard let stepperValue = stepperValue else {return}
stepperGM.value = stepperValue
}
func updateUI() {
guard let productData = productData else {return}
// update UI
productNameLabel.text = productData.name
pricePerUnitLabel.text = productData.getFormattedUnitPriceWithSeparator()
priceTotalPerItemLabel.text = productData.getFormattedTotalPriceWithSeparator()
//set image
if let imagePath = productData.imagePaths.first {
guard let encodedImagePath = imagePath.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) else {return}
guard let url = URL(string: encodedImagePath) else {return}
productImageView.kf.indicatorType = .activity //loading indicator
productImageView.kf.setImage(with: url, options: [.transition(.fade(0.2))])
}
}
}
and here is the code to get the data from realm database, I get the data from realm database synchronously.
static func getOrderFromRealmDatabase() -> Order {
let userID = "1"
let realmService = RealmService.shared.realm
let allOrder = realmService.objects(Order.self)
let theOrder = allOrder.filter("userID CONTAINS[cd] %#", userID).first
if let userOrder = theOrder {
return userOrder
} else {
// Order never setted up before in Realm database container
// then create Order in realm database
let newOrder = Order()
newOrder.userID = userID
newOrder.products = List<Product>()
RealmService.shared.save(object: newOrder)
return newOrder
}
}
what went wrong in here, I don't understand :(

Remove optional handling in numberOfRowsInSection because products count never 0. and tableview hidden code is never excuted.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return userOrder?.products.count
}

Related

Passing data from Table view cell using button delegate

I want to pass the data from one view controller to another view controller when the user clicked the button . I am using button with delegate to pass the table view cell values into different view controller view . In second view controller I have two labels and one image to display the fields but the problem is when I clicked the button it is empty.
Here is the cell code .
import UIKit
protocol CellSubclassDelegate: AnyObject {
func buttonTapped(cell: MovieViewCell)
}
class MovieViewCell: UITableViewCell {
weak var delegate:CellSubclassDelegate?
static let identifier = "MovieViewCell"
#IBOutlet weak var movieImage: UIImageView!
#IBOutlet weak var movieTitle: UILabel!
#IBOutlet weak var movieOverview: UILabel!
#IBOutlet weak var someButton: UIButton!
#IBAction func someButtonTapped(_ sender: UIButton) {
self.delegate?.buttonTapped(cell: self)
}
override func prepareForReuse() {
super.prepareForReuse()
self.delegate = nil
}
func configureCell(title: String?, overview: String?, data: Data?) {
movieTitle.text = title
movieOverview.text = overview
if let imageData = data{
movieImage.image = UIImage(data: imageData)
// movieImage.image = nil
}
}
}
Here is the first view controller code .
import UIKit
class MovieViewController: UIViewController, UISearchBarDelegate {
#IBOutlet weak var userName: UILabel!
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
private var presenter: MoviePresenter!
var finalname = ""
var movieTitle = ""
var movieOverview = ""
var movieImage : UIImage?
override func viewDidLoad() {
super.viewDidLoad()
userName.text = "Hello: " + finalname
setUpUI()
presenter = MoviePresenter(view: self)
searchBarText()
}
private func setUpUI() {
tableView.dataSource = self
tableView.delegate = self
}
private func searchBarText() {
searchBar.delegate = self
}
#IBAction func selectSegment(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 0{
setUpUI()
presenter = MoviePresenter(view: self)
presenter.getMovies()
}
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchText == ""{
presenter.getMovies()
}
else {
presenter.movies = presenter.movies.filter({ movies in
let originalTitle = movies.originalTitle.lowercased().range(of: searchText.lowercased())
let overview = movies.overview.lowercased().range(of: searchText.lowercased())
let posterPath = movies.posterPath.lowercased().range(of: searchText.lowercased())
return (originalTitle != nil) == true || (overview != nil) == true || (posterPath != nil) == true}
)
}
tableView.reloadData()
}
}
extension MovieViewController: MovieViewProtocol {
func resfreshTableView() {
tableView.reloadData()
}
func displayError(_ message: String) {
let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
let doneButton = UIAlertAction(title: "Done", style: .default, handler: nil)
alert.addAction(doneButton)
present(alert, animated: true, completion: nil)
}
}
extension MovieViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
presenter.rows
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: MovieViewCell.identifier, for: indexPath) as! MovieViewCell
let row = indexPath.row
let title = presenter.getTitle(by: row)
let overview = presenter.getOverview(by: row)
let data = presenter.getImageData(by: row)
cell.delegate = self
cell.configureCell(title: title, overview: overview, data: data)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let dc = storyboard?.instantiateViewController(withIdentifier: "MovieDeatilsViewController") as! MovieDeatilsViewController
let row = indexPath.row
dc.titlemovie = presenter.getTitle(by: row) ?? ""
dc.overview = presenter.getOverview(by: row) ?? ""
dc.imagemovie = UIImage(data: presenter.getImageData(by: row)!)
self.navigationController?.pushViewController(dc, animated: true)
}
}
extension MovieViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
}
extension MovieViewController : CellSubclassDelegate{
func buttonTapped(cell: MovieViewCell) {
guard (self.tableView.indexPath(for: cell) != nil) else {return}
let customViewController = storyboard?.instantiateViewController(withIdentifier: "MovieDeatilsViewController") as? MovieDeatilsViewController
customViewController?.titlemovie = movieTitle
customViewController?.imagemovie = movieImage
customViewController?.overview = movieOverview
self.navigationController?.pushViewController(customViewController!, animated: true)
}
}
Here is the details view controller code .
class MovieDeatilsViewController: UIViewController {
#IBOutlet weak var movieImage: UIImageView!
#IBOutlet weak var movieTitle: UILabel!
#IBOutlet weak var movieOverview: UILabel!
var titlemovie = ""
var overview = ""
var imagemovie :UIImage?
override func viewDidLoad() {
super.viewDidLoad()
movieTitle.text = titlemovie
movieOverview.text = overview
movieImage.image = imagemovie
}
}
Here is the result when I clicked the button .
The problem is you don't update you're global properties when selecting each of you're row,
If you pass data over cell delegate and pass you're cell through delegate, you can pass data from cell like:
customViewController?.titlemovie = cell.movieTitle.text ?? ""
customViewController?.imagemovie = cell.movieImage.image
customViewController?.overview = cell.movieOverview.text ?? ""
of course it would be better to pass you're data model to you're cell. and then share that through you're delegate not share you're cell, like:
protocol CellSubclassDelegate: AnyObject {
func buttonTapped(cell: MovieModel)
}

Swift Image conversion failed from one view controller to another controller

I am trying to send the data in including image from one view controller to another . The data is fetching from API . The data is successfully loaded into first view controller including image but when I try to reuse same code with didSelectRow function I am getting following errors . Cannot assign value of type 'Data?' to type 'UIImage' . The error on this line dc.imagemovie = presenter.getImageData(by: row). Here is the code to fetch the data from API.
class MoviePresenter: MoviePresenterProtocol {
private let view: MovieViewProtocol
private let networkManager: NetworkManager
private var movies = [Movie]()
private var cache = [Int: Data]()
var rows: Int {
return movies.count
}
init(view: MovieViewProtocol, networkManager: NetworkManager = NetworkManager()) {
self.view = view
self.networkManager = networkManager
}
func getMovies() {
let url = "https://api.themoviedb.org/3/movie/popular?language=en-US&page=3&api_key=6622998c4ceac172a976a1136b204df4"
networkManager.getMovies(from: url) { [weak self] result in
switch result {
case .success(let response):
self?.movies = response.results
self?.downloadImages()
DispatchQueue.main.async {
self?.view.resfreshTableView()
}
case .failure(let error):
DispatchQueue.main.async {
self?.view.displayError(error.localizedDescription)
}
}
}
}
func getTitle(by row: Int) -> String? {
return movies[row].originalTitle
}
func getOverview(by row: Int) -> String? {
return movies[row].overview
}
func getImageData(by row: Int) -> Data? {
return cache[row]
}
private func downloadImages() {
let baseImageURL = "https://image.tmdb.org/t/p/w500"
let posterArray = movies.map { "\(baseImageURL)\($0.posterPath)" }
let group = DispatchGroup()
group.enter()
for (index, url) in posterArray.enumerated() {
networkManager.getImageData(from: url) { [weak self] data in
if let data = data {
self?.cache[index] = data
}
}
}
group.leave()
group.notify(queue: .main) { [weak self] in
self?.view.resfreshTableView()
}
}
}
Here is the code in view controller to display the data into table view cell .
class MovieViewController: UIViewController {
#IBOutlet weak var userName: UILabel!
#IBOutlet weak var tableView: UITableView!
private var presenter: MoviePresenter!
var finalname = ""
override func viewDidLoad() {
super.viewDidLoad()
userName.text = "Hello: " + finalname
setUpUI()
// configure presenter
presenter = MoviePresenter(view: self)
presenter.getMovies()
}
private func setUpUI() {
tableView.dataSource = self
tableView.delegate = self
}
#IBAction func selectSegment(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 0{
setUpUI()
presenter = MoviePresenter(view: self)
presenter.getMovies()
}
}
}
extension MovieViewController: MovieViewProtocol {
func resfreshTableView() {
tableView.reloadData()
}
func displayError(_ message: String) {
let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
let doneButton = UIAlertAction(title: "Done", style: .default, handler: nil)
alert.addAction(doneButton)
present(alert, animated: true, completion: nil)
}
}
extension MovieViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
presenter.rows
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: MovieViewCell.identifier, for: indexPath) as! MovieViewCell
let row = indexPath.row
let title = presenter.getTitle(by: row)
let overview = presenter.getOverview(by: row)
let data = presenter.getImageData(by: row)
cell.configureCell(title: title, overview: overview, data: data)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let dc = storyboard?.instantiateViewController(withIdentifier: "MovieDeatilsViewController") as! MovieDeatilsViewController
let row = indexPath.row
dc.titlemovie = presenter.getTitle(by: row) ?? ""
dc.overview = presenter.getOverview(by: row) ?? ""
**dc.imagemovie = presenter.getImageData(by: row) // Error on this line**
self.navigationController?.pushViewController(dc, animated: true)
}
}
/*
var titlemoview = ""
var overview = ""
var imagemovie = UIImage()
*/
extension MovieViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
}
Here is the code for display the data .
class MovieDeatilsViewController: UIViewController {
#IBOutlet weak var movieImage: UIImageView!
#IBOutlet weak var movieTitle: UILabel!
#IBOutlet weak var movieOverview: UILabel!
var titlemovie = ""
var overview = ""
var imagemovie = UIImage()
override func viewDidLoad() {
super.viewDidLoad()
movieTitle.text = titlemovie
movieOverview.text = overview
movieImage.image = imagemovie
}
}
Get UIImage from data in configureCell(:, : , :) function by UIImage(data:yourdata) and assign to your imageview
let image = UIImage(data:yourdata)
imageview.image = image

Displaying the Image From API using DidSelectRow

I am trying to send the data in including image from one view controller to another . The data is fetching from API . The data is successfully loaded into first view controller including image but when I try to reuse same code with didSelectRow function I am getting following errors . Cannot assign value of type 'Data?' to type 'UIImage' . The error on this line dc.imagemovie = presenter.getImageData(by: row). Here is the code to fetch the data from API.
class MoviePresenter: MoviePresenterProtocol {
private let view: MovieViewProtocol
private let networkManager: NetworkManager
private var movies = [Movie]()
private var cache = [Int: Data]()
var rows: Int {
return movies.count
}
init(view: MovieViewProtocol, networkManager: NetworkManager = NetworkManager()) {
self.view = view
self.networkManager = networkManager
}
func getMovies() {
let url = "https://api.themoviedb.org/3/movie/popular?language=en-US&page=3&api_key=6622998c4ceac172a976a1136b204df4"
networkManager.getMovies(from: url) { [weak self] result in
switch result {
case .success(let response):
self?.movies = response.results
self?.downloadImages()
DispatchQueue.main.async {
self?.view.resfreshTableView()
}
case .failure(let error):
DispatchQueue.main.async {
self?.view.displayError(error.localizedDescription)
}
}
}
}
func getTitle(by row: Int) -> String? {
return movies[row].originalTitle
}
func getOverview(by row: Int) -> String? {
return movies[row].overview
}
func getImageData(by row: Int) -> Data? {
return cache[row]
}
private func downloadImages() {
let baseImageURL = "https://image.tmdb.org/t/p/w500"
let posterArray = movies.map { "\(baseImageURL)\($0.posterPath)" }
let group = DispatchGroup()
group.enter()
for (index, url) in posterArray.enumerated() {
networkManager.getImageData(from: url) { [weak self] data in
if let data = data {
self?.cache[index] = data
}
}
}
group.leave()
group.notify(queue: .main) { [weak self] in
self?.view.resfreshTableView()
}
}
}
Here is the code in view controller to display the data into table view cell .
class MovieViewController: UIViewController {
#IBOutlet weak var userName: UILabel!
#IBOutlet weak var tableView: UITableView!
private var presenter: MoviePresenter!
var finalname = ""
override func viewDidLoad() {
super.viewDidLoad()
userName.text = "Hello: " + finalname
setUpUI()
// configure presenter
presenter = MoviePresenter(view: self)
presenter.getMovies()
}
private func setUpUI() {
tableView.dataSource = self
tableView.delegate = self
}
#IBAction func selectSegment(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 0{
setUpUI()
presenter = MoviePresenter(view: self)
presenter.getMovies()
}
}
}
extension MovieViewController: MovieViewProtocol {
func resfreshTableView() {
tableView.reloadData()
}
func displayError(_ message: String) {
let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
let doneButton = UIAlertAction(title: "Done", style: .default, handler: nil)
alert.addAction(doneButton)
present(alert, animated: true, completion: nil)
}
}
extension MovieViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
presenter.rows
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: MovieViewCell.identifier, for: indexPath) as! MovieViewCell
let row = indexPath.row
let title = presenter.getTitle(by: row)
let overview = presenter.getOverview(by: row)
let data = presenter.getImageData(by: row)
cell.configureCell(title: title, overview: overview, data: data)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let dc = storyboard?.instantiateViewController(withIdentifier: "MovieDeatilsViewController") as! MovieDeatilsViewController
let row = indexPath.row
dc.titlemovie = presenter.getTitle(by: row) ?? ""
dc.overview = presenter.getOverview(by: row) ?? ""
**dc.imagemovie = presenter.getImageData(by: row)**
self.navigationController?.pushViewController(dc, animated: true)
}
}
extension MovieViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
}
Here is the code for display the data .
class MovieDeatilsViewController: UIViewController {
#IBOutlet weak var movieImage: UIImageView!
#IBOutlet weak var movieTitle: UILabel!
#IBOutlet weak var movieOverview: UILabel!
var titlemovie = ""
var overview = ""
var imagemovie = UIImage()
override func viewDidLoad() {
super.viewDidLoad()
movieTitle.text = titlemovie
movieOverview.text = overview
movieImage.image = imagemovie
}
}
You need to return UIImage :
class MoviePresenter: MoviePresenterProtocol {
...
// Convert data to UIImage
func getImageData(by row: Int) -> UIImage? {
return UIImage(data: cache[row])
}
You need yo use UIImage and UIImage view to configure cell :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: MovieViewCell.identifier, for: indexPath) as! MovieViewCell
let row = indexPath.row
let title = presenter.getTitle(by: row)
let overview = presenter.getOverview(by: row)
let image = presenter.getImageData(by: row)
// cell is now configured with an image
cell.configureCell(title: title, overview: overview, image: image)
return cell
}
You need to modify cell.configureCell to handle UIImage? instead of data.
When selecting a cell you must use UIImage to init VC :
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let dc = storyboard?.instantiateViewController(withIdentifier: "MovieDeatilsViewController") as! MovieDeatilsViewController
let row = indexPath.row
dc.titlemovie = presenter.getTitle(by: row) ?? ""
dc.overview = presenter.getOverview(by: row) ?? ""
dc.imagemovie = presenter.getImageData(by: row)// now an image
self.navigationController?.pushViewController(dc, animated: true)
}
Use UIImage to initialise image movie in detail vc :
class MovieDeatilsViewController: UIViewController {
#IBOutlet weak var movieImageView: UIImageView! // Image view here
#IBOutlet weak var movieTitle: UILabel!
#IBOutlet weak var movieOverview: UILabel!
var titlemovie = ""
var overview = ""
var imagemovie : UIImage?
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated: animated)
movieTitle.text = titlemovie
movieOverview.text = overview
// here you could also display a default image
// if image is not set
if let image = imagemovie {
movieImageView.image = image
}
}
}

Error while selecting two files from dropdown to display on UITableView in swift

I have two tableview in my viewcontroller, and two dropdown menu from which i select a csv files for each tableview to display its contents.
I am getting an error of index out of reach. After debugging i came to know if both files have equal number of rows it doesn't show any errors.
How can i resolve this error because i have many csv files which may not contain equal amount of data.
import UIKit
import DropDown
class CompareFilesViewController: UIViewController,UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var DropDownView: UIView!
#IBOutlet weak var DropDownView2: UIView!
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var tableView2: UITableView!
#IBOutlet weak var selectedFile_lbl: UILabel!
#IBOutlet weak var selectedFile_lbl2: UILabel!
var filesDropDown = DropDown()
var filesDropDown2 = DropDown()
var files1 = [String]()
var files2 = [String]()
var files1Data = [String]()
var files2Data = [String]()
var refreshControl: UIRefreshControl?
var dropDownFlag = false
var dropDownFlag1 = false
var filename: String?
var filename1: String?
override func viewDidLoad() {
super.viewDidLoad()
var files = [String]()
files1Data.append("Select Files from drop down")
files2Data.append("Select Files from drop down")
// Do any additional setup after loading the view.
let fm = FileManager.default
let path = getDocumentsDirectory()
do{
let items = try fm.contentsOfDirectory(at: path, includingPropertiesForKeys: nil)
let onlyFileNames = items.filter{ !$0.hasDirectoryPath }
let onlyFileNamesStr = onlyFileNames.map { $0.lastPathComponent }
files.append(contentsOf: onlyFileNamesStr)
//getting different file names
for index in 0..<files.count{
if files[0].components(separatedBy: "_")[0] == files[index].components(separatedBy: "_")[0]{
print(true)
files1.insert(files[index], at: 0)
}
else{
print(false)
files2.insert(files[index], at: 0)
}
}
print("file names\(onlyFileNamesStr)")
}
catch
{
print(error)
}
setDropDown1()
setDropDown2()
tableView.delegate = self
tableView.dataSource = self
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
tableView2.delegate = self
tableView2.dataSource = self
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell2")
}
#IBAction func DropDownViewTapped(_ sender: Any) {
filesDropDown.show()
}
#IBAction func DropDownView2Tapped(_ sender: Any) {
filesDropDown2.show()
}
#IBAction func compareFiles(_ sender: Any) {
files2Data.removeAll()
files1Data.removeAll()
files2Data.insert(contentsOf: self.getSelectedFileContent(fileName: filename1!), at: 0)
files1Data.insert(contentsOf: self.getSelectedFileContent(fileName: filename!), at: 0)
tableView.reloadData()
tableView2.reloadData()
}
//for right dropdown
func setDropDown1() {
filesDropDown.textFont = UIFont.systemFont(ofSize: 10)
filesDropDown.textColor = .blue
filesDropDown.dataSource = files1
filesDropDown.anchorView = DropDownView2
filesDropDown.selectionAction = { index, title in
self.dropDownFlag = true
print("index: \(index), title: \(title)")
self.filename = title
self.selectedFile_lbl2.text = self.filename
// self.files1Data.insert(contentsOf: self.getSelectedFileContent(fileName: title), at: 0)
//self.tableView2.reloadData()
}
}
//for left drop down
func setDropDown2(){
filesDropDown2.textFont = UIFont.systemFont(ofSize: 10)
filesDropDown2.dataSource = files2
filesDropDown2.anchorView = DropDownView
filesDropDown2.selectionAction = { index, title in
self.dropDownFlag1 = true
print("index: \(index), title: \(title)")
self.filename1 = title
self.selectedFile_lbl.text = self.filename1
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var count: Int?
if tableView == self.tableView{
count = files1Data.count
print(count as Any)
}
if tableView == self.tableView2{
count = files2Data.count
print(count as Any)
}
print(count as Any)
return count!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell:UITableViewCell?
if tableView == self.tableView{
cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell!.textLabel?.text = files2Data[indexPath.row]//error: index out of range
cell!.textLabel!.numberOfLines = 0
// cell!.textLabel?.adjustsFontSizeToFitWidth = true
cell!.textLabel?.font = UIFont(name: "Arial", size: 10.0)
}
if tableView == self.tableView2{
cell = tableView.dequeueReusableCell(withIdentifier: "Cell2", for: indexPath)
cell!.textLabel?.text = files1Data[indexPath.row]//error: index out of range
cell!.textLabel!.numberOfLines = 0
// cell!.textLabel?.adjustsFontSizeToFitWidth = true
cell!.textLabel?.font = UIFont(name: "Arial", size: 10.0)
}
return cell!
}
func getSelectedFileContent(fileName: String) -> [String] {
var contentsArray = [String]()
let fm = FileManager.default
let destURL = getDocumentsDirectory().appendingPathComponent(fileName)
do {
if fm.fileExists(atPath: destURL.path) {
let contents = try String(contentsOf: destURL)
contentsArray = contents.components(separatedBy: "\n")
print(contents)
}
} catch {
print("File copy failed.")
}
return contentsArray
}
}
I have tried to add refreshcontroll but this doesnt work.
For dropDown i have used AssistoLab library https://github.com/AssistoLab/DropDown.git
What i really want is to select csv files and display it to tableviews for comparison when button is clicked
is there any better solution which i can used?
You can modify your condition as below :
if tableView == self.tableView {
if files2Data.count <= indexPath.row {
// Your code
}else{
return UITableViewCell()
}
}
Same logic for the other table.
I dont know why, but after refactoring my code it works like i wanted to be. i just added two buttons for both files to be displayed after selecting from dropdown menu.
import UIKit
import DropDown
class DemoViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var topDropDownView: UIView!
#IBOutlet weak var bottomDropDownView: UIView!
#IBOutlet weak var selectFile_lbl1: UILabel!
#IBOutlet weak var selectFile_lbl2: UILabel!
#IBOutlet weak var tableView1: UITableView!
#IBOutlet weak var tableView2: UITableView!
var data1 = [String]()
var data2 = [String]()
var topDropDown = DropDown()
var bottomDropDown = DropDown()
var files1 = [String]()
var files2 = [String]()
var filename1 = ""
var filename2 = ""
override func viewDidLoad() {
super.viewDidLoad()
getFileNames()
setDropDown1()
setDropDown2()
tableView1.delegate = self
tableView2.delegate = self
tableView1.dataSource = self
tableView2.dataSource = self
tableView1.register(UITableViewCell.self, forCellReuseIdentifier: "cell1")
tableView2.register(UITableViewCell.self, forCellReuseIdentifier: "cell2")
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
#IBAction func button1(_ sender: Any) {
data1.removeAll()
data1.append(contentsOf: getSelectedFileContent(fileName: filename1))
tableView1.reloadData()
}
#IBAction func button2(_ sender: Any) {
data2.removeAll()
data2.append(contentsOf: getSelectedFileContent(fileName: filename2))
tableView2.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var count: Int?
if tableView == self.tableView1{
count = data1.count
print(count as Any)
}
if tableView == self.tableView2{
count = data2.count
print(count as Any)
}
print(count as Any)
return count!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell:UITableViewCell?
if tableView == self.tableView1{
cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath)
cell!.textLabel?.text = data1[indexPath.row]
cell!.textLabel!.numberOfLines = 0
// cell!.textLabel?.adjustsFontSizeToFitWidth = true
cell!.textLabel?.font = UIFont(name: "Arial", size: 10.0)
}
if tableView == self.tableView2{
cell = tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath)
cell!.textLabel?.text = data2[indexPath.row]
cell!.textLabel!.numberOfLines = 0
// cell!.textLabel?.adjustsFontSizeToFitWidth = true
cell!.textLabel?.font = UIFont(name: "Arial", size: 10.0)
}
return cell!
}
func getSelectedFileContent(fileName: String) -> [String] {
var contentsArray = [String]()
let fm = FileManager.default
let destURL = getDocumentsDirectory().appendingPathComponent(fileName)
do {
if fm.fileExists(atPath: destURL.path) {
let contents = try String(contentsOf: destURL)
contentsArray = contents.components(separatedBy: "\n")
print(contents)
}
} catch {
print("File copy failed.")
}
return contentsArray
}
#IBAction func topDropDownView_tapped(_ sender: Any) {
topDropDown.show()
}
#IBAction func bottomDropDownView_tapped(_ sender: Any) {
bottomDropDown.show()
}
func getFileNames(){
var files = [String]()
let fm = FileManager.default
let path = getDocumentsDirectory()
do{
let items = try fm.contentsOfDirectory(at: path, includingPropertiesForKeys: nil)
let onlyFileNames = items.filter{ !$0.hasDirectoryPath }
let onlyFileNamesStr = onlyFileNames.map { $0.lastPathComponent }
files.append(contentsOf: onlyFileNamesStr)
for index in 0..<files.count{
if files[0].components(separatedBy: "_")[0] == files[index].components(separatedBy: "_")[0]{
print(true)
files1.insert(files[index], at: 0)
}
else{
print(false)
files2.insert(files[index], at: 0)
}
}
print("file names\(onlyFileNamesStr)")
}
catch
{
print(error)
}
}
//for right dropdown
func setDropDown1() {
topDropDown.textFont = UIFont.systemFont(ofSize: 10)
topDropDown.textColor = .blue
topDropDown.dataSource = files1
topDropDown.anchorView = topDropDownView
topDropDown.selectionAction = { index, title in
print("index: \(index), title: \(title)")
self.filename1 = title
self.selectFile_lbl1.text = self.filename1
// self.files1Data.insert(contentsOf: self.getSelectedFileContent(fileName: title), at: 0)
//self.tableView2.reloadData()
}
}
//for left drop down
func setDropDown2(){
bottomDropDown.textFont = UIFont.systemFont(ofSize: 10)
bottomDropDown.dataSource = files2
bottomDropDown.anchorView = bottomDropDownView
bottomDropDown.selectionAction = { index, title in
print("index: \(index), title: \(title)")
self.filename2 = title
self.selectFile_lbl2.text = self.filename2
//self.files2Data.insert(contentsOf: self.getSelectedFileContent(fileName: title), at: 0)
// self.tableView2.reloadData()
}
}
}

how to insert data from string to Sqlite in Swift3?

I have a problem that I have tried to insert string data to Sqlite. I want to do is in my Details ViewController if user press Like button, the word and meaning of string pass into Sqlite file that show in Favourite ViewController. Below is my DetailsVC code.
import UIKit
import AVFoundation
class DetailsVC: UIViewController, UITextViewDelegate {
#IBOutlet weak var wordLbl: UILabel!
#IBOutlet weak var meaningLbl: UITextView!
#IBOutlet weak var sysWordLbl: UILabel!
#IBOutlet weak var sysWordsLbl: UILabel!
#IBOutlet weak var anyWordsLbl: UILabel!
#IBOutlet weak var anyWordLbl: UILabel!
#IBOutlet weak var wordImg: UIImageView!
#IBOutlet weak var buSound: UIButton!
#IBOutlet weak var buLike: UIButton!
#IBOutlet weak var menuBtn: UIButton!
//Data from HomeVC
var data:Data?
var fdatas = [FData]()
var favouriteVC = FavouriteVC()
override func viewDidLoad() {
super.viewDidLoad()
meaningLbl.delegate = self
wordLbl.text = "\((data?._word.capitalized)!) \((data?._phonetic)!)"
self.meaningLbl.text = data?._meaning
self.sysWordsLbl.text = data?._meaning
self.anyWordsLbl.text = data?._meaning
self.sysWordLbl.text = "Synonym"
self.anyWordLbl.text = "Antonym"
meaningLbl.font = UIFont(name: FONT_REGULAR, size: 24.0)
}
#IBAction func buMenu(_ sender: Any) {
//menu
dismiss(animated: true, completion: nil)
}
#IBAction func buSound(_ sender: Any) {
//Todo: speak the word
if buSound.isEnabled == true{
buSound.setImage(UIImage(named: "volume-2.png"), for: .normal)
}else{
buSound.setImage(UIImage(named: "volume-un-2.png"), for: .normal)
}
let utTerance = AVSpeechUtterance(string: "\((data?._word)!)")
let synthesize = AVSpeechSynthesizer()
utTerance.voice = AVSpeechSynthesisVoice(language: "en-gb")
synthesize.speak(utTerance)
}
#IBAction func buLike(_ sender: Any) {
//Todo: Click Like
if buLike.isEnabled == true{
buLike.setImage(UIImage(named: "heart.png"), for: .normal)
//Save data to Database
let word = data?._word ?? ""
let meaning = data?._meaning ?? ""
do{
let favData = FData(word: word, meaning: meaning)
self.fdatas.append(favData)
print("\(word), \(meaning)")
}catch{
print(error)
}
}else{
buSound.setImage(UIImage(named: "heart-un.png"), for: .normal)
}
//FavouriteVC.insertRowsAtIndexPaths([NSIndexPath(forRow: fdatas.count-1, inSection: 0)], withRowAnimation: .Fade)
}
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
self.view.endEditing(true);
return false;
}
}
My FavouriteVC
import UIKit
import SwipeCellKit
import SQLite
class FavouriteVC: UIViewController,UITableViewDelegate,UITableViewDataSource, SwipeTableViewCellDelegate{
//TabelView
#IBOutlet weak var fTableView: UITableView!
//Variables
var fdata = [FData]()
override func viewDidLoad() {
super.viewDidLoad()
// FtableView
fTableView.delegate = self
fTableView.dataSource = self
//reload Data
fTableView.reloadData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fdata.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: FAVOURITE_CELL, for: indexPath) as? FavouriteCell{
cell.configureCell(fdata: fdata[indexPath.row])
//cell.delegate = self
return cell
}
return FavouriteCell()
}
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? {
guard orientation == .right else { return nil }
let deleteAction = SwipeAction(style: .destructive, title: "Delete") { action, indexPath in
// handle action by updating model with deletion
}
// customize the action appearance
deleteAction.image = UIImage(named: "delete")
return [deleteAction]
}
}
FData.swif
import Foundation
class FData {
//let id: Int64?
var word: String
var meaning: String
//var address: String
init(id: Int64) {
// self.id = id
word = ""
meaning = ""
//address = ""
}
init(word: String, meaning: String) {
// self.id = id
self.word = word
self.meaning = meaning
//self.address = address
}
}
FavouriteData Instance
import UIKit
import SQLite
class FavouriteData{
static let instance = FavouriteData()
private let db: Connection?
private let words = Table("words")
private let id = Expression<Int64>("id")
private let wordL = Expression<String?>("word")
private let meaningL = Expression<String?>("shanword_uni")
//private let address = Expression<String>("address")
private init() {
let path = NSSearchPathForDirectoriesInDomains(
.documentDirectory, .userDomainMask, true
).first!
do {
db = try Connection("\(path)/favourite.sqlite")
} catch {
db = nil
print ("Unable to open database")
}
createTable()
}
func createTable() {
do {
try db!.run(words.create(ifNotExists: true) { table in
table.column(id, primaryKey: true)
table.column(wordL)
//table.column(phone, unique: true)
table.column(meaningL)
})
} catch {
print("Unable to create table")
}
}
func addData(word: String, meaning: String) -> Int64? {
do {
let insert = words.insert(wordL <- word, meaningL <- meaning)
let id = try db!.run(insert)
print("Save: \(id)")
return id
} catch {
print("Insert failed")
return -1
}
}
func getData() -> [FData] {
var contacts = [FData]()
do {
for contact in try db!.prepare(self.words) {
contacts.append(FData(
// id: contact[id],
word: contact[wordL]!,
meaning: contact[meaningL]!))
}
} catch {
print("Select failed")
}
return contacts
}
func deleteData(index: Int64) -> Bool {
do {
let contact = words.filter(id == index)
try db!.run(contact.delete())
return true
} catch {
print("Delete failed")
}
return false
}
}
But, there is not cell of row in the FavouriteVC. How to fix this? Please help me.
Best,
Sai Tawng Pha
I have solved my problem by add one line of code. In my FavouriteVC class, just add it under ViewdidLoad function " fdata = FavouriteData.instance.getData() ".
Here is my complete code.
import UIKit
import SwipeCellKit
import SQLite
class FavouriteVC: UIViewController,UITableViewDelegate,UITableViewDataSource, SwipeTableViewCellDelegate{
//TabelView
#IBOutlet weak var fTableView: UITableView!
//Variables
var fdata = [FData]()
override func viewDidLoad() {
super.viewDidLoad()
// FtableView
fTableView.delegate = self
fTableView.dataSource = self
//reload Data
fTableView.reloadData()
//Get Data
fdata = FavouriteData.instance.getData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fdata.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: FAVOURITE_CELL, for: indexPath) as? FavouriteCell{
cell.configureCell(fdata: fdata[indexPath.row])
//cell.delegate = self
return cell
}
return FavouriteCell()
}
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? {
guard orientation == .right else { return nil }
let deleteAction = SwipeAction(style: .destructive, title: "Delete") { action, indexPath in
// handle action by updating model with deletion
}
// customize the action appearance
deleteAction.image = UIImage(named: "delete")
return [deleteAction]
}
}

Resources