TableView is not updating properly after logout and log in - ios

I have a ProfileView controller where I display the email of the user that is logged in. When I sign out and sign in again the email is updated but the tableview is not updated when new info. Even if it is done the reloading is just appending duplicating rows to the view. Below is my code. Can someone check what I may be doing wrong
import UIKit
import FirebaseAuth
import SDWebImage
import FirebaseDatabase
final class ProfileViewController: UIViewController {
#IBOutlet var tableView: UITableView!
var data = [ProfileViewModel]()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard let email = Auth.auth().currentUser?.email! else {
return
}
tableView.register(ProfileTableViewCell.self,
forCellReuseIdentifier: ProfileTableViewCell.identifier)
data.append(ProfileViewModel(viewModelType: .info,
title: "Email: \(email ?? "No Email")",
handler: nil))
tableView.register(UITableViewCell.self,
forCellReuseIdentifier: "cell")
tableView.delegate = self
tableView.dataSource = self
tableView.tableHeaderView = createTableHeader()
}
func createTableHeader() -> UIView? {
guard let email = UserDefaults.standard.value(forKey: "email") as? String else {
return nil
}
let safeEmail = DatabaseManager.safeEmail(emailAddress: email)
let filename = safeEmail + "_profile_picture.png"
let path = "images/"+filename
let headerView = UIView(frame: CGRect(x: 0,
y: 0,
width: self.view.width,
height: 300))
headerView.backgroundColor = .link
let imageView = UIImageView(frame: CGRect(x: (headerView.width-150) / 2,
y: 75,
width: 150,
height: 150))
imageView.contentMode = .scaleAspectFill
imageView.backgroundColor = .white
imageView.layer.borderColor = UIColor.white.cgColor
imageView.layer.borderWidth = 3
imageView.layer.masksToBounds = true
imageView.layer.cornerRadius = imageView.width/2
headerView.addSubview(imageView)
StorageManager.shared.downloadURL(for: path, completion: { result in
switch result {
case .success(let url):
imageView.sd_setImage(with: url, completed: nil)
case .failure(let error):
print("Failed to get download url: \(error)")
}
})
return headerView
}
}
extension ProfileViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let viewModel = data[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: ProfileTableViewCell.identifier,
for: indexPath) as! ProfileTableViewCell
cell.setUp(with: viewModel)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
data[indexPath.row].handler?()
}
}
class ProfileTableViewCell: UITableViewCell {
static let identifier = "ProfileTableViewCell"
public func setUp(with viewModel: ProfileViewModel) {
self.textLabel?.text = viewModel.title
switch viewModel.viewModelType {
case .info:
textLabel?.textAlignment = .center
selectionStyle = .none
}
}
}

I think you need to empty data array before appending new object into that array.
just write
data.removeAll() before
data.append(ProfileViewModel(viewModelType: .info, title: "Email: \(email ?? "No Email")", handler: nil)).
I think this will resolve your issue.

Related

why Xcode do not execute the codes in func tableView?

question:
I set several breakpoints inside the function of tableView. However the Xcode didn't execute the code inside the tableView. please tell me how to fix these.
I'm new to learn about IOS development and I'm trying to write a demo of Tweeter show page. Looking forward for responses!
Here is code of extension UITablewViewDataSource:
extension WechatMomentViewController: UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.tweetList?.count ?? 0;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let tweetCell = tableView.dequeueReusableCell(withIdentifier: "WechatMomentListCell", for: indexPath) as? WechatMomentListCell else {
fatalError("there is no WechatMomentList")
}
let tweet = viewModel.tweetList?[indexPath.row]
for i in tweet?.images ?? [] {
let flagImage = UIImageView()
flagImage.sd_setImage(with: URL(string: i.url))
tweetCell.Images.append(flagImage)
}
for i in tweet?.comments ?? [] {
let flagComment = UILabel()
flagComment.text = "\(i.sender) : \(i.content)"
tweetCell.comments.append(flagComment)
}
tweetCell.senderNick.text = tweet?.sender?.nick
tweetCell.senderAvatar.sd_setImage(with: URL(string: tweet?.sender?.avatar ?? ""), placeholderImage: UIImage(named: "placeholder.png"))
tweetCell.content.text = tweet?.content
return tweetCell
}
}
and here is the code of all ViewController:
import UIKit
import SnapKit
import SDWebImage
import Alamofire
//
class WechatMomentViewController: UIViewController {
let viewModel = WechatMomentViewModel()
var userAvatar = UIImageView()
var userProfileImage = UIImageView()
var userNick = UIButton()
var TweetCell = UITableViewCell()
override func viewDidLoad() {
super.viewDidLoad()
viewModel.delegate = self
getUserProfile()
getTweet()
}
fileprivate func getUserProfile() {
viewModel.getUserProfile()
view.addSubview(userProfileImage)
userAvatar.backgroundColor = UIColor.black
view.addSubview(userAvatar)
userAvatar.snp.makeConstraints{ (make) in
make.height.equalTo(80)
make.width.equalTo(80)
make.right.equalToSuperview().offset(-10)
make.centerY.equalToSuperview()
}
userAvatar.clipsToBounds = true;
userAvatar.layer.cornerRadius = 10;
view.addSubview(userNick)
userNick.snp.makeConstraints{ (make) in
make.width.equalTo(90)
make.height.equalTo(20)
make.trailing.equalTo(userAvatar.snp.leading)
make.centerY.equalTo(userAvatar)
}
userProfileImage.frame = CGRect(x: 0, y: 0, width: 414, height: 448)
}
fileprivate func getTweet() {
viewModel.getTweet()
}
}
extension WechatMomentViewController: WechatMomentVCProtocol {
func refreshUI() {
if let user = viewModel.user,
let avatar = user.avatar,
let profileImage = user.profileImage {
userAvatar.sd_setImage(with: URL(string: avatar))
userProfileImage.sd_setImage(with: URL(string: profileImage))
userNick.setTitle(user.nick, for: .normal)
}
}
}
extension WechatMomentViewController: UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.tweetList?.count ?? 0;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let tweetCell = tableView.dequeueReusableCell(withIdentifier: "WechatMomentListCell", for: indexPath) as? WechatMomentListCell else {
fatalError("there is no WechatMomentList")
}
let tweet = viewModel.tweetList?[indexPath.row]
for i in tweet?.images ?? [] {
let flagImage = UIImageView()
flagImage.sd_setImage(with: URL(string: i.url))
tweetCell.Images.append(flagImage)
}
for i in tweet?.comments ?? [] {
let flagComment = UILabel()
flagComment.text = "\(i.sender) : \(i.content)"
tweetCell.comments.append(flagComment)
}
tweetCell.senderNick.text = tweet?.sender?.nick
tweetCell.senderAvatar.sd_setImage(with: URL(string: tweet?.sender?.avatar ?? ""), placeholderImage: UIImage(named: "placeholder.png"))
tweetCell.content.text = tweet?.content
return tweetCell
}
}
and here is identifire code of WechatMomentListCell:
import Foundation
import UIKit
class WechatMomentListCell: UITableViewCell{
var content = UILabel()
var senderAvatar = UIImageView()
var senderNick = UILabel()
var Images = [UIImageView()]
var comments = [UILabel()]
}
your class should extend UITableViewController not UIViewController . Also you must register you cell.
class WechatMomentViewController: UITableViewController {
let kCellIdentifier = "CellIdentifier"
override func viewDidLoad() {
super.viewDidLoad()
self.tableView?.register(WechatMomentListCell, forCellReuseIdentifier: kCellIdentifier)
}
}
Add something like:
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self // if you are...
tableView.datasource = self
...
}
The problem ist that you will most likely (you didn't show) have a regular UIViewController and not a UITableViewController. Therefore the tableview does not have a delegate nor a datasource. Alternatively, if you are using a storyboard or a xib, you can right click from the tableview to the controller and assign those values there.
The problem is:
firstly, I don't have TableView(). So I create a new instance of TableView.
Secondly, use
view.addSubivew(tableview)
Then, member to reloadData from your View Model.
and... try clean build(it is really helpful)

UISearchController cancel button dismisses UITabBarController when tapped multiple times in a row

I use a custom search controller that has a tableView for showing the results,
the problem is when tapping the cancel button multiple times it dismisses the tabBarController.
But if i press it normally it acts as it should be.
class UICustomSearchController: UISearchController {
private var suggestedTableView: UITableView!
weak var suggestionDelegate: SearchSuggestionsDelegate?
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
suggestedTableView = UITableView(frame: CGRect(x: 0, y: searchBar.frame.maxY,
width: view.frame.width,
height: view.frame.height - 70))
suggestedTableView.backgroundColor = UIColor.clear
suggestedTableView.tableFooterView = UIView()
view.subviews.forEach {
if $0.isKind(of: UITableView.self) {
$0.removeFromSuperview()
}
}
view.addSubview(suggestedTableView)
suggestedTableView.dataSource = self
suggestedTableView.delegate = self
suggestedTableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
let tap = UITapGestureRecognizer(target: self, action: #selector(tableTapped))
suggestedTableView.addGestureRecognizer(tap)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
suggestedTableView.removeFromSuperview()
suggestedTableView = nil
dismiss(animated: false, completion: nil)
}
func reloadSuggestions() {
suggestedTableView.reloadData()
}
private func dismissView() {
searchBar.text = ""
suggestedTableView.removeFromSuperview()
dismiss(animated: false, completion: nil)
suggestionDelegate?.didDismissed()
}
// MARK: - Actions
#objc func tableTapped(tap:UITapGestureRecognizer) {
suggestedTableView.removeGestureRecognizer(tap)
let location = tap.location(in: suggestedTableView)
let path = suggestedTableView.indexPathForRow(at: location)
if let indexPathForRow = path {
tableView(suggestedTableView, didSelectRowAt: indexPathForRow)
} else {
dismissView()
}
}
}
extension UICustomSearchController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return suggestionDelegate?.suggestions().count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let list = suggestionDelegate?.suggestions() ?? []
cell.textLabel?.text = list[indexPath.row]
cell.textLabel?.textColor = UIColor.color(from: .blueTabBar)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let list = suggestionDelegate?.suggestions() ?? []
searchBar.text = list[indexPath.row]
searchBar.becomeFirstResponder()
suggestionDelegate?.didSelect(suggestion: list[indexPath.row])
}
}
And in the viewController that has search:
func initSearchViews() {
// Create the search controller and specify that it should present its results in this same view
searchController = UICustomSearchController(searchResultsController: nil)
searchController.hidesNavigationBarDuringPresentation = false
searchController.searchBar.barTintColor = UIColor.white
searchController.searchBar.tintColor = UIColor.color(from: .blueTabBar)
searchController.searchBar.setValue(Strings.cancel.localized, forKey:"_cancelButtonText")
searchController.suggestionDelegate = self
if let searchTextField = searchController!.searchBar.value(forKey: "searchField") as? UITextField {
searchTextField.placeholder = Strings.search.localized
}
// Make this class the delegate and present the search
searchController.searchBar.delegate = self
}
I tried putting this line in viewController but nothing happened:
definesPresentationContext = true

Swift Xcode 13 Programmatic UITableViewController nil delegate

The Delegated function fires but crashes as its nil, the objects in the items array is populated by CoreData, this var model: CoreDataModel = CoreDataModel(CoreDataController.shared) has to be instantiated rather than as expected in the viewDidLoad to prevent a nil error for the table view row count (model.items.count)
On startup the items array is the complete Sqlite DB, on search its the subset of the table and printing to the console proves the array is changed and only has the subset of Albums.
BaseViewController
import UIKit
import CoreData
protocol UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
}
protocol MasterModel {
var client: LastFMClient { get }
func searchFeed(with userSearchTerm: String?, completion: #escaping (Bool) -> Void)
}
protocol DataReloadTableViewDelegate: class {
func reloadAlbumsTable()
}
class BaseViewController: UITableViewController, MasterModel {
let cellId = "sdlfjowieurewfn3489844224947824dslaksjfs;ad"
let logoContainer = UIView(frame: CGRect(x: 0, y: 0, width: 44, height: 44))
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 44, height: 44))
let image = UIImage(named: "lastFMRedBlack")
let searchBar = UISearchBar()
let client = LastFMClient()
var model: CoreDataModel = CoreDataModel(CoreDataController.shared)
private var searchResults: Root?
override func viewDidLoad() {
super.viewDidLoad()
setupSearchController()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellId)
tableView.register(SubtitleTableViewCell.self, forCellReuseIdentifier: cellId)
tableView.tableFooterView = UIView(frame: CGRect.zero)
tableView.separatorColor = UIColor(red: 72.5/255, green: 0/255, blue: 0/255, alpha: 1)
imageView.contentMode = .scaleAspectFit
imageView.image = image
logoContainer.addSubview(imageView)
navigationItem.titleView = logoContainer
print(FileManager.default.urls(for: .documentDirectory, in: .userDomainMask))
model.delegate = self
model.fetchAllAlbums()
}
// MARK - SearchBar
private func setupSearchController() {
searchBar.sizeToFit()
searchBar.placeholder = "Search for Album"
searchBar.delegate = self
showSearchBarButton(shouldShow: true)
}
func showSearchBarButton (shouldShow: Bool) {
if shouldShow {
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .search, target: self, action: #selector(handleShowSearchBar))
} else {
searchBar.showsCancelButton = true
navigationItem.rightBarButtonItem = nil
}
}
func search(shouldShow: Bool) {
showSearchBarButton(shouldShow: !shouldShow)
navigationItem.titleView = shouldShow ? searchBar : logoContainer
}
#objc func handleShowSearchBar(){
search(shouldShow: true)
searchBar.becomeFirstResponder()
}
// MARK - API Request
func searchFeed(with userSearchTerm: String?, completion: #escaping (Bool) -> Void) {
// Use the API to get data
client.getFeed(from: LastFMRequest.albumSearch(userSearchTerm: userSearchTerm) ) { result in
switch result {
case .success(let data):
do {
let data = try DataParser.parse(data, type: RootNode.self)
self.searchResults = data.results
completion(true)
} catch {
print(error.localizedDescription)
completion(false)
}
case .failure(let error):
print(error.localizedDescription)
completion(false)
}
}
}
}
extension BaseViewController: UISearchBarDelegate {
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
searchBar.text = nil
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
search(shouldShow: false)
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
guard let searchTextString = searchBar.text else { return }
searchFeed(with: searchTextString.replacingOccurrences(of: " ", with: "+").lowercased(), completion: {_ in
if self.searchResults!.albumMatches.album.count == 0 {
DispatchQueue.main.async {
let alertController = UIAlertController(title: "No Albums Found", message: "Try Another Keyword(s)", preferredStyle: .alert)
let OKAction = UIAlertAction(title: "OK", style: .default) { action in
print("Pressed OK")
}
alertController.addAction(OKAction)
self.present(alertController, animated: true, completion: nil)
}
} else {
let dataManager = DataManager(data: self.searchResults!)
do {
try dataManager.saveData()
} catch {
print(error)
}
}
})
search(shouldShow: false)
searchBar.resignFirstResponder()
}
}
class SubtitleTableViewCell: UITableViewCell {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: .subtitle, reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension BaseViewController: UITableViewDataSource {
var numberOrSections: Int { return 1 }
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard section >= 0 && section < numberOrSections else { return 0 }
return model.items.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
let albumItem = model.items[indexPath.row]
cell.textLabel?.text = albumItem.value(forKeyPath: "name") as? String
cell.detailTextLabel?.text = albumItem.value(forKeyPath: "artist") as? String
cell.accessoryType = .disclosureIndicator
// Populate the cell from the object
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = DetailViewController()
let albumItem = model.items[indexPath.row]
vc.iamgeURL = albumItem.value(forKeyPath: "imageUrl") as? String
vc.albumName = albumItem.value(forKeyPath: "name") as? String
navigationController?.pushViewController(vc, animated: true)
}
}
extension BaseViewController: DataReloadTableViewDelegate {
func reloadAlbumsTable(){
DispatchQueue.main.async {
print(self.model.items.count)
self.tableView.reloadData()
}
}
}
CoreDataModel
import Foundation
import CoreData
class CoreDataModel {
weak var delegate: DataReloadTableViewDelegate?
let coreDataController: CoreDataController
var items:[Albums] = []
init(_ coreDataController: CoreDataController) {
self.coreDataController = coreDataController
self.coreDataController.mainContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
}
internal func saveSearchAlbums(responseData: Root) throws {
let newSearch = Searches(context: coreDataController.mainContext)
newSearch.searchQuery = responseData.attr.forField
for (_, element) in responseData.albumMatches.album.enumerated() {
let newAlbum = Albums(context: coreDataController.mainContext)
let artistName = element.artist
let albumName = element.name
let imageUrlTwo = element.image[2].text
let imageUrlZero = element.image[0].text
let imageUrlOne = element.image[1].text
var imageUrl: String = ""
if !JustLetters.blank(text: imageUrlTwo) {
imageUrl = imageUrlTwo
}
if !JustLetters.blank(text: imageUrlZero) {
imageUrl = imageUrlZero
}
if !JustLetters.blank(text: imageUrlOne) {
imageUrl = imageUrlOne
}
if !JustLetters.blank(text: artistName) && !JustLetters.blank(text: albumName) && !JustLetters.blank(text: imageUrl) {
newAlbum.searches = newSearch
newAlbum.artist = artistName
newAlbum.name = albumName
newAlbum.imageUrl = imageUrl
newSearch.addToAlbums(newAlbum)
}
}
// Save context
coreDataController.saveContext()
fetchAlbumsByKeyword(searchTerm: responseData.attr.forField)
}
internal func fetchAlbumsByKeyword(searchTerm: String) {
// Create Fetch Request
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Albums")
// Add Sort Descriptor
let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
// Add Predicate
let predicate = NSPredicate(format: "name CONTAINS[c] %#", searchTerm)
fetchRequest.predicate = predicate
do {
items = try coreDataController.mainContext.fetch(fetchRequest) as! [Albums]
} catch {
print(error)
}
delegate!.reloadAlbumsTable()
}
internal func fetchAllAlbums() {
// Create the FetchRequest for all searches
let allAlbums: NSFetchRequest = Albums.fetchRequest()
do {
items = try coreDataController.mainContext.fetch(allAlbums)
} catch {
print(error)
}
}
}
Delegate is assigned/set on the class name and not on any instance identifier so a delegate can only be set on a class with one instance
I am unable to show specific proof, I rely on cause and effect of a single change to make the above statement.
I had more than one instance of CoreDataModel, I set the delegate on the first instance in the viewDidLoad, the second instance is set on the search click. I refactored out the DataManager Class which itself creates and instance of CoreDataModel.
The final result is the delegate is not nil and performs as expected. Repo 'show_album_search_results' branch

tableview in tabbar not reloading

I have a TabBar with various Tabs in my RestaurantApp, When I click the addToCart and goes to the CartViewContorller, the added item don't show I have to relaunch the App to see the item there. I have seen similar questions with various answer on this question here but non of the solutions seems to work in my case I don't really know whats wrong. Below is my code for the CartViewContorller I want to reload tableview anytime it is loaded. Thanks all for your help
import UIKit
import Alamofire
import os.log
class CartViewController: UITableViewController {
var cartData = [CartResponse.Cart]()
override func viewDidLoad() {
super.viewDidLoad()
cart()
tableView.delegate = self
tableView.dataSource = self
let nib = UINib(nibName: "viewCartCell", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "cartCustomCell")
let footerView = UIView()
footerView.backgroundColor = UIColor.red
footerView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 60)
tableView.tableFooterView = footerView
}
override func viewDidAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tableView.reloadData()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cartData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell: CartTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "cartCustomCell", for: indexPath) as? CartTableViewCell else {
os_log("Dequeue cell isn't an instance of CustomTableCell", log: .default, type: .debug)
fatalError()
}
cell.recipeNameLbl?.text = cartData[indexPath.row].recipeName
cell.restaurantNameLbl?.text = cartData[indexPath.row].restaurantName
cell.addtionalNoteLbl?.text = cartData[indexPath.row].additionalNote
cell.quantityLbl?.text = cartData[indexPath.row].recipeQuantity
cell.totalLbl?.text = cartData[indexPath.row].recipePrice
cell.totalCostLbl?.text = cartData[indexPath.row].totalCost
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
guard editingStyle == .delete else {return}
//getting userId from defaults
let CartId = cartData[indexPath.row].cartId
let cartId = CartId
//creating parameters for the post request
let parameters: Parameters=[
"cartId":Int(cartId)
]
//Constant that holds the URL for web service
let URL_SELECT_FROM_CART = "http://localhost:8888/restaurant/deleteFromCart.php?"
Alamofire.request(URL_SELECT_FROM_CART, method: .post, parameters: parameters).responseJSON {
response in
//printing response
print(response)
}
cartData.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .automatic)
}
//Fetching from Cart Method
func cart(){
//getting userId from defaults
let defaultValues = UserDefaults.standard
let userId = defaultValues.string(forKey: "userid")
//creating parameters for the post request
let parameters: Parameters=[
"userId":Int(userId!)!
]
//Constant that holds the URL for web service
let URL_SELECT_FROM_CART = "http://localhost:8888/restaurant/cart.php?"
Alamofire.request(URL_SELECT_FROM_CART, method: .post, parameters: parameters).responseJSON {
(response) in
let result = response.data
do{
let decoder = JSONDecoder()
let downloadedCart = try decoder.decode(CartResponse.self, from: result!)
self.cartData = downloadedCart.cartItem
DispatchQueue.main.async {
self.tableView.reloadData()
}
}catch {
print(error)
}
}.resume()
}
}
You can use :
import UserNotifications
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "loadCart"), object: nil)
see more in this answer
You have to call cart() this method in viewWillAppear instead of calling viewDidload
override func viewWillAppear(_ animated: Bool) {
self.cart()
}

How to navigate from UITableViewCell to UICollectionViewController programmatically in Swift 4

Here is what I want to achieve: When I tap a UITabViewCell (Picture 1), it will navigate to an UICollectionViewController (Picture 2). Just like the following two pictures showing:
I could navigate to an UIViewController when tap a UITableViewCell, but it doesn't work when I try to navigate to UICollectionView. Here are my codes:
import UIKit
class RealUserProfileController: UIViewController, UITableViewDelegate, UITableViewDataSource {
private let me = ["Vincent-St"]
private let followers = ["58 Followers"]
private let myPhotos = ["New Followers"]
private let others = ["My likes", "Notifications", "Clear Caches", "Drafts"]
private let settings = ["Settings"]
private let share = ["Share with friends"]
private let images = ["Hearts.png", "Footprint.png", "Notifications.png", "Trash-Empty.png"]
private let sections = ["me", "myPhotos", "others", "settings", "share"]
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.font: UIFont(name: "Arial", size: 18)!, NSAttributedStringKey.foregroundColor: UIColor.black]
navigationItem.title = "Profile"
let displayWidth: CGFloat = self.view.frame.width
let displayHeight: CGFloat = self.view.frame.height
let myTableView: UITableView = UITableView(frame: CGRect(x: 0, y: 0, width: displayWidth, height: displayHeight), style: .grouped)
myTableView.register(UITableViewCell.self, forCellReuseIdentifier: "MyCell")
myTableView.dataSource = self
myTableView.delegate = self
self.view.addSubview(myTableView)
view.backgroundColor = UIColor(white: 1, alpha: 0.95)
myTableView.translatesAutoresizingMaskIntoConstraints = false
myTableView.topAnchor.constraint(equalTo: view.topAnchor, constant: -20).isActive = true
myTableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
myTableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
myTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0 {
return 72
}
return tableView.rowHeight
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 0 {
let controller = UserProfileController()
self.navigationController?.pushViewController(controller, animated: true)
print("Value: \(me[indexPath.row])")
} else if indexPath.section == 1 {
print("Value: \(myPhotos[indexPath.row])")
} else if indexPath.section == 2 {
print("Value: \(others[indexPath.row])")
} else if indexPath.section == 3 {
let controller = ResultController()
navigationController?.pushViewController(controller, animated: true)
print("Value: \(settings[indexPath.row])")
} else if indexPath.section == 4 {
print("Value: \(share[indexPath.row])")
let shareText = "Share our app"
let shareImage = UIImage(named: "bell_unselected.png")
let activityViewController : UIActivityViewController = UIActivityViewController(activityItems: [shareText, shareImage as Any], applicationActivities: nil)
self.present(activityViewController, animated: true, completion: nil)
}
}
// return the number of cells each section.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return me.count
} else if section == 1 {
return myPhotos.count
} else if section == 2 {
return others.count
} else if section == 3 {
return settings.count
} else if section == 4 {
return share.count
} else {
return 0
}
}
// return cells
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: "MyCell")
if indexPath.section == 0 {
cell.textLabel?.text = "\(me[indexPath.row])"
cell.detailTextLabel?.text = "\(followers[indexPath.row])"
cell.imageView?.image = #imageLiteral(resourceName: "profile_image")
} else if indexPath.section == 1 {
cell.textLabel?.text = "\(myPhotos[indexPath.row])"
cell.imageView?.image = #imageLiteral(resourceName: "icon_friends")
} else if indexPath.section == 2 {
cell.textLabel?.text = "\(others[indexPath.row])"
cell.imageView?.image = UIImage.init(named: images[indexPath.row])
} else if indexPath.section == 3 {
cell.textLabel?.text = "\(settings[indexPath.row])"
cell.imageView?.image = #imageLiteral(resourceName: "Icon_Settings")
} else if indexPath.section == 4 {
cell.textLabel?.text = "\(share[indexPath.row])"
cell.imageView?.image = #imageLiteral(resourceName: "Share")
}
cell.accessoryType = .disclosureIndicator
return cell
}
}
The two lines of codes will crash the app:
let controller = UserProfileController()
self.navigationController?.pushViewController(controller, animated: true)
Here is the error message:
Cannot convert value of type 'UserProfileController.Type' to expected argument type 'UIViewController'
Here are the codes of the destination UICollectionViewController:
class UserProfileController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
}
After some research, I didn't find any useful information. Is there any way to make it happen? Or is there any way to implement the Picture 2 in another way, maybe: UIViewController, instead of UICollectionView?
Any suggestion would be appreciated.
I don't think the problem is with navigation, any subclass of UIViewController should be navigable.
I believe you need to initialize UICollectionViewController using init(collectionViewLayout: UICollectionViewLayout), collectionView has to have the layout set, otherwise the collectionView will crash if it gets presented.
Therefore instead of:
let controller = UserProfileController()
try using:
let controller = UserProfileController(collectionViewLayout: UICollectionViewFlowLayout())
Here I am assuming that the following code is your full implementation of UserProfileController, thus you directly inherit initializers from UICollectionViewController:
class UserProfileController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
}

Resources