in swift UIKit
Error about making Table View from String and model
Could not cast value of type 'CloudApp.addCatogrey' (0x104948470) to 'Swift.String' (0x1052195b8).
An error occurs when I press send
I want to display the data for one of the sections through the model (addCatogrey)
view control file
import UIKit
class ViewController: UIViewController {
//MARK: arry data
let sectionMenu = ["all", "Fav", "Delete"]
var arrS1 : [addCatogrey] = []
var arrS2 = ["favorite"]
var arrS3 = ["delete other"]
var sectionData : [Int: [Any]] = [:]
//MARK: Outlet
#IBOutlet weak var addNewCatogery: UIBarButtonItem!
#IBOutlet var tableCatogery: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
sectionData = [0 : arrS1 , 1 : arrS2, 2 : arrS3]
self.arrS1 = helperCora().getCatog()
}
#IBAction func addMenuNew(_ sender: Any) {
let alert = UIAlertController(title: "Create an album", message: "", preferredStyle: .alert)
alert.addTextField(configurationHandler: nil)
alert.textFields![0].placeholder = "name album"
alert.textFields![0].textAlignment = .right
alert.addAction(UIAlertAction(title: "cancel", style: .cancel, handler: nil))
alert.addAction(UIAlertAction(title: "save", style: .default, handler: { ـ in
if let textFileds = alert.textFields {
let links = textFileds[0].text
self.arrS1.append(addCatogrey(nameCatog: links!))
helperCora().storeCatog(name: addCatogrey(nameCatog: links!))
self.sectionData = [0 : self.arrS1 , 1 : self.arrS2, 2 : self.arrS3]
self.tableCatogery.reloadData()
}
}))
self.present(alert, animated: true, completion: nil)
}
}
extension ViewController : UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return sectionData.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (sectionData[section]?.count)!
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sectionMenu[section]
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CellMenu
cell.textMenu.text = sectionData[indexPath.section]![indexPath.row] as! String
return cell
}
}
model file
struct addCatogrey {
var nameCatog : String
}
Coradata file [SAVE and GET]
import UIKit
import CoreData
class helperCora : ViewController {
//MARK: Data For Menu --------- 1
func storeCatog (name : addCatogrey) {
guard let AppDelegate = UIApplication.shared.delegate as? AppDelegate else {return}
let mangeContext = AppDelegate.persistentContainer.viewContext
guard let myEntity = NSEntityDescription.entity(forEntityName: "Entity", in: mangeContext) else { return }
let nameCat = NSManagedObject.init(entity: myEntity, insertInto: mangeContext)
nameCat.setValue(name.nameCatog, forKey: "nameCat")
do {
try mangeContext.save()
print("========== Secsess =========")
}catch {
print("========== Error =========")
}
}
//MARK: Data For Menu --------- 2
func getCatog () -> [addCatogrey] {
var catog : [addCatogrey] = []
guard let AppDelegate = UIApplication.shared.delegate as? AppDelegate else {return []}
let context = AppDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Entity")
do {
let reselt = try context.fetch(fetchRequest) as! [NSManagedObject]
for mangeCatoj in reselt {
let title = mangeCatoj.value(forKey: "nameCat") as! String
let Catogery = addCatogrey(nameCatog: title)
catog.append(Catogery)
}
print("====== secsecc ========")
}catch {
print("====== error ========")
}
return catog
}
}
Related
I am trying to build a simple To Do app with Core Data.
In CoreData Model, I have created an Entity named "ToDoCoreData". It has one attribute "newToDoItem" type of String.
In CellForRowAt method I'm receiving the following error
Thread 1: EXC_BAD_ACCESS (code=1, address=0x6b49dedf6a0) - but everytime I rerun the app the newly added ToDo appeares in row.
The code is below. Would be glad if someone could help, please.
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var toDoList:[ToDoCoreData] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
override func viewWillAppear(_ animated: Bool) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let fetchRequest: NSFetchRequest<ToDoCoreData> = ToDoCoreData.fetchRequest()
do {
toDoList = try context.fetch(fetchRequest)
} catch {
print(error.localizedDescription)
}
}
#IBAction func addNewToDo(_ sender: UIBarButtonItem) {
let ac = UIAlertController(title: "Add Task", message: "add New Task", preferredStyle: .alert)
let ok = UIAlertAction(title: "Add", style: .default) { (action) in
let textField = ac.textFields?[0]
// self.toDoList.insert((textField?.text)!, at: 0)
self.saveToDo(newToDoItem: (textField?.text)!)
self.tableView.reloadData()
}
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
ac.addTextField { textfield in
}
ac.addAction(ok)
ac.addAction(cancel)
present(ac, animated: true, completion: nil)
}
func saveToDo(newToDoItem: String) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "ToDoCoreData", in: context)
let taskObject = NSManagedObject(entity: entity!, insertInto: context) as! ToDoCoreData
taskObject.newToDoItem = newToDoItem
do {
try context.save()
toDoList.append(taskObject)
print("Success!")
} catch {
print(error.localizedDescription)
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
toDoList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell
let toDo = toDoList[indexPath.row]
cell.rowLabel.text = toDo.newToDoItem
return cell
}
}
I am trying to filter the data from API. The is successful loaded into view controller with table view cell . This is a movie applications . I am trying to filter the data based on the user type into the text box . I mentioned in the code filter my the title of the movie but The code is only able to filter the title and overview of the movie but the Image fields remain unfiltered such as image , overview etc. Here is the struct model .
import Foundation
struct Movie: Decodable {
let originalTitle: String
let overview: String
let posterPath: String
enum CodingKeys: String, CodingKey {
case originalTitle = "original_title"
case overview
case posterPath = "poster_path"
}
}
Here is the protocol class code .
import Foundation
class MoviePresenter: MoviePresenterProtocol {
private let view: MovieViewProtocol
private let networkManager: NetworkManager
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 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 = ""
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 == 1{
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
return movies.originalTitle.lowercased().contains(searchText.lowercased())
})
}
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.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
}
}
Here is the screenshot of the result .
Caching image in tableview is a little bit tricky, and you may get problem when the cell changes or reusing itself,
that's cause you see same image when texts are different.
there are 2 famous package you can use it for you're problem and it's easy to use with a lot of options.
1- Kingfisher
2- SDWebImage
Here I Try MVVM pattern to achieve TableView but for showing alert I face problems , it compiles successfully but not showing alert.
[Result] on the tapped on profile pic which is in tableview cell, I want to show alert
TableViewCell
import Foundation
import UIKit
class ParentsImageCell : UITableViewCell {
weak var myVC : ProfileOfParentsDetailsViewController?
var parentProfileVC = ProfileOfParentsDetailsViewController()
#IBOutlet weak var imageProfile : UIImageView!
var items : ParentProfileViewModelItem? {
didSet {
guard let items = items as? ParentProfileViewModelProfileItem else {
return
}
imageProfile?.image = UIImage(named: items.profileImg)
}
}
static var nib:UINib {
return UINib(nibName: identifier, bundle: nil)
}
static var identifier: String {
return String(describing: self)
}
override func awakeFromNib() {
super.awakeFromNib()
imageProfile?.layer.cornerRadius = 62
imageProfile?.clipsToBounds = true
imageProfile?.contentMode = .scaleAspectFill
imageProfile?.backgroundColor = UIColor.lightGray
//Add Tapped Gesture
imageProfile.isUserInteractionEnabled = true
let gesture = UITapGestureRecognizer(
target: self,
action: #selector(didTappedChangeProfilePic))
gesture.numberOfTapsRequired = 1
gesture.numberOfTouchesRequired = 1
imageProfile.addGestureRecognizer(gesture)
}
#objc private func didTappedChangeProfilePic(){
print("tapped on imageView")
presentPhotoActionSheet()
}
override func prepareForReuse() {
super.prepareForReuse()
imageProfile?.image = nil
}
}
extension ParentsImageCell : UIImagePickerControllerDelegate ,UINavigationControllerDelegate {
func presentPhotoActionSheet(){
let actionSheet = UIAlertController(title: "Profile Picture", message: "How would you write to select a picture", preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: "cancel", style: .cancel, handler: nil))
actionSheet.addAction(UIAlertAction(title: "Take Photo", style: .default, handler: {[weak self] _ in
self?.presentCamera()
}))
actionSheet.addAction(UIAlertAction(title: "Choose Photo", style: .default, handler: { [weak self]_ in
self?.presentPhotoPicker()
}))
myVC?.present(actionSheet , animated: true)
}
func presentCamera(){
let vc = UIImagePickerController()
vc.sourceType = .camera
vc.delegate = self
vc.allowsEditing = true
myVC?.present(vc , animated: true)
}
func presentPhotoPicker(){
let vc = UIImagePickerController()
vc.sourceType = .photoLibrary
vc.delegate = self
vc.allowsEditing = true
myVC?.present(vc , animated: true)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info:
[UIImagePickerController.InfoKey : Any]) {
guard let selectedImage = info[UIImagePickerController.InfoKey.editedImage] as? UIImage else {
return
}
self.imageProfile.image = selectedImage
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
}
ViewModel
class ParentProfileViewModel: NSObject {
var items = [ParentProfileViewModelItem]()
var reloadSections: ((_ section: Int) -> Void)?
override init() {
super.init()
guard let data = dataFromFile("ServerData"),
let profile = Profile(data: data) else {
return
}
// initialization code will go here
if let profile = profile.pictureUrl {
let profileItem = ParentProfileViewModelProfileItem(profileImg: profile)
items.append(profileItem)
}
if let name = profile.fullName {
let nameItem = ParentProfileViewModelNameItem(name: name)
items.append(nameItem)
}
if let email = profile.email {
let emailItem = ParentProfileViewModelEmailItem(email: email)
items.append(emailItem)
}
let coach = profile.coach
if !coach.isEmpty {
let coachItem = ParentProfileViewModelCoachItem(coach: coach)
items.append(coachItem)
}
let candidate = profile.candidate
if !candidate.isEmpty {
let candidateItem = ParentProfileViewModelCandidateItem(candidate: candidate)
items.append(candidateItem)
}
}
}
//MARK:- TableviewDatasource & Delegates
extension ParentProfileViewModel: UITableViewDataSource {
//Number of section
func numberOfSections(in tableView: UITableView) -> Int {
return items.count
}
//Number of RowInSection
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let item = items[section]
guard item.isCollapsible else {
return item.rowCount
}
if item.isCollapsed {
return 0
} else {
return item.rowCount
}
}
//Cell for row at indexpath
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// we will configure the cells here
let item = items[indexPath.section]
switch item.type {
case .profileImg:
let vc = ProfileOfParentsDetailsViewController()
if let cell = tableView.dequeueReusableCell(withIdentifier: ParentsImageCell.identifier, for: indexPath) as? ParentsImageCell {
cell.items = item
cell.myVC = vc
return cell
}
case .fullName:
if let cell = tableView.dequeueReusableCell(withIdentifier: ParentsFulNameCell.identifier, for: indexPath) as? ParentsFulNameCell {
cell.items = item
return cell
}
case .email:
if let cell = tableView.dequeueReusableCell(withIdentifier: ParentsEmailCell.identifier, for: indexPath) as? ParentsEmailCell {
cell.items = item
return cell
}
case .candidate:
if let item = item as? ParentProfileViewModelCandidateItem, let cell = tableView.dequeueReusableCell(withIdentifier: CandidatCell.identifier, for: indexPath) as? CandidatCell {
let candidate = item.candidate[indexPath.row]
cell.item = candidate
return cell
}
case .coach:
if let item = item as? ParentProfileViewModelCoachItem, let cell = tableView.dequeueReusableCell(withIdentifier: ParentCoachCell.identifier, for: indexPath) as? ParentCoachCell {
cell.item = item.coach[indexPath.row]
return cell
}
}
return UITableViewCell()
}
}
ViewController
import Foundation
import UIKit
class ProfileOfParentsDetailsViewController: UIViewController {
let viewModel = ParentProfileViewModel()
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
viewModel.reloadSections = { [weak self] (section: Int) in
self?.tableView?.beginUpdates()
self?.tableView?.reloadSections([section], with: .fade)
self?.tableView?.endUpdates()
}
tableView?.dataSource = viewModel
tableView.delegate = viewModel
tableView?.estimatedRowHeight = 250
tableView?.rowHeight = UITableView.automaticDimension
tableView?.register(ParentsImageCell.nib, forCellReuseIdentifier: ParentsImageCell.identifier)
tableView?.register(ParentsEmailCell.nib, forCellReuseIdentifier: ParentsEmailCell.identifier)
tableView?.register(ParentsFulNameCell.nib, forCellReuseIdentifier: ParentsFulNameCell.identifier)
tableView?.register(CandidatCell.nib, forCellReuseIdentifier: CandidatCell.identifier)
tableView?.register(ParentCoachCell.nib, forCellReuseIdentifier: ParentCoachCell.identifier)
tableView?.register(ParentsHeaderView.nib, forHeaderFooterViewReuseIdentifier: ParentsHeaderView.identifier)
}
I try to get called alert Sheet , but I Failed and also comment about my approach towards MVVM
I try to called the tableview data source and delegate in VM
I try to get called alert Sheet , but I Failed and also comment about my approach towards MVVM
I try to called the tableview data source and delegate in VM
I'm new to Swift and need your help.
I have two View Controllers with a tableview and two Entities called Groups and Singlegroups with an one to many relationship.The Entity Singlegroups has an attribute from type Date.
In View Controller 1 (MasterViewController) I show all Groups in my TableView and in the second View Controller (DetailViewController) I show all Singlegroups related to the Group of the selected row.
Now I want to load the SingleGroups on second View Controller only from current month but I can't get it to work, because I have no FetchRequest in the second View Controller. I transfer the Single Groups for the selected row in the prepareForSegue method.
I tried to call a fetchRequest manually in thousands different ways but nothing happend.
Hope you understand my problem and can help me.
MasterViewController ViewWillAppear:
import UIKit
import CoreData
class MasterViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var groups: [Groups] = []
#IBOutlet weak var groupsTableView: UITableView!
var groupsTextField: UITextField?
override func viewDidLoad() {
super.viewDidLoad()
groupsTableView.delegate = self
groupsTableView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewWillAppear(_ animated: Bool) {
// Core date initialization
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest: NSFetchRequest<Groups> = Groups.fetchRequest()
do {
groups = try managedContext.fetch(fetchRequest)
groupsTableView.reloadData()
} catch {
// TODO: error handling
print("Could not fetch groups")
}
}
PrepareForSegue in MasterViewController:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetailViewController" {
guard let destination = segue.destination as? DetailViewController,
let selectedRow = self.groupsTableView.indexPathForSelectedRow?.row else {
return
}
destination.group = groups[selectedRow]
destination.title = groups[selectedRow].groupTitle
}
DetailViewController ViewWillAppear:
import UIKit
import CoreData
class DetailViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, NSFetchedResultsControllerDelegate {
var singleGroupDate: UILabel!
var singleGroupName: UILabel!
var singleGroupAmount: UILabel!
#IBOutlet weak var dateLabelTextField: UITextField!
#IBOutlet weak var singleGroupSum: UILabel!
#IBOutlet weak var singleGroupTableView: UITableView!
var groups: [Groups] = []
var group: Groups?
override func viewDidLoad() {
super.viewDidLoad()
singleGroupTableView.delegate = self
singleGroupTableView.dataSource = self
}
override func viewWillAppear(_ animated: Bool) {
// Core date initialization
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
// create alert
let alert = UIAlertController(
title: "Could not get app delegate",
message: "Could not get app delegate, unexpected error occured. Try again later.",
preferredStyle: .alert)
// add OK action
alert.addAction(UIAlertAction(title: "OK", style: .default))
// show alert
self.present(alert, animated: true)
return
}
let managedContext = appDelegate.persistentContainer.viewContext
singleGroupTableView.reloadData()
DetailViewController TableView:
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return group?.singleGroups?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = singleGroupTableView.dequeueReusableCell(withIdentifier: "SingleGroupsTableViewCell", for: indexPath) as! SingleGroupsTableViewCell
let currencyFormatter = NumberFormatter()
currencyFormatter.usesGroupingSeparator = true
currencyFormatter.numberStyle = .currency
currencyFormatter.locale = Locale.current
currencyFormatter.positivePrefix = currencyFormatter.plusSign
currencyFormatter.negativePrefix = currencyFormatter.minusSign
if let singleGroup = group?.singleGroups?[indexPath.row] {
cell.singleGroupNameLabel?.text = singleGroup.singleGroupName
cell.singleGroupAmountLabel?.text = currencyFormatter.string(from: singleGroup.singleGroupAmount as NSNumber)
cell.singleGroupAmountLabel.textColor = UIColor.red
cell.singleGroupDateLabel?.text = DateHelper.convertDate(date: singleGroup.singleGroupTimeStamp)
}
return cell
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
deleteSingleGroup(at: indexPath)
}
}
UPDATE:
I solved it myself by writing a new fetch request for the SingleGroups Entity and changing the numbersOfRowsInSection method of my tableview.
func orderFetchRequest() -> NSFetchRequest<NSFetchRequestResult> {
let startDateFetch = Date().startOfMonth()
let endDateFetch = Date().endOfMonth()
self.startDate = startDateFetch!
self.endDate = endDateFetch!
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "SingleGroups")
let sortDescriptor = NSSortDescriptor(key: "singleGroupTimeStamp", ascending: false)
let predicate1 = NSPredicate(format: "group == %#", group!)
let predicate2 = NSPredicate(format: "singleGroupTimeStamp >= %# AND singleGroupTimeStamp <= %#", startDate as CVarArg, endDate as CVarArg)
let compound = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate1, predicate2])
fetchRequest.sortDescriptors = [sortDescriptor]
fetchRequest.predicate = compound
return fetchRequest
}
func fetchData() {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest = orderFetchRequest()
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedContext, sectionNameKeyPath:nil, cacheName: nil)
do {
try fetchedResultsController.performFetch()
singleGroupTableView.reloadData()
}
catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fetchedResultsController.fetchedObjects?.count ?? 0
I have added this to my code:
let userID = Auth.auth().currentUser!.uid
ref = Database.database().reference().child(userID);
Thinking this would work and give me the results I needed, as my rules are right, however the app just comes up with a blank table instead of it filled in with the details. Which is really weird!
Firstly here are my firebase rules:
{
"rules": {
"jobs": {
"$uid": {
".read": "auth.uid === $uid"
}
}
}
}
Here is my firebase database:
FirebaseDatabase
Here is the Firebase Auth with the UID
FirebaseAuth
Here is my code:
ViewController for Login Page:
import UIKit
import Firebase
import FirebaseAuth
class LoginViewController: UIViewController {
var ref: DatabaseReference!
static var isAlreadyLaunchedOnce = false
#IBOutlet weak var txtemail: UITextField!
#IBOutlet weak var txtpass: UITextField!
var isSignin:Bool = true
override func viewDidLoad() {
super.viewDidLoad()
if FirebaseApp.app() == nil {
FirebaseApp.configure()
}
}
#IBAction func submit(_ sender: UIButton) {
if let email = txtemail.text, let passowrd = txtpass.text
{ Auth.auth().signIn(withEmail: email, password: passowrd) { (user, error) in
if user != nil {
self.performSegue(withIdentifier: "goto", sender : self)
}
else {
let alert = UIAlertController(title: "Username or Password Incorrect", message: nil, preferredStyle: .alert)
let okButton = UIAlertAction(title: "Ok", style: .default, handler: nil)
alert.addAction(okButton)
self.present(alert, animated: true, completion: nil)
}
}
}
}
}
View controller for Logged in Page
import UIKit
import Firebase
class LoggedInViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var loginlbl: UILabel!
#IBOutlet weak var tbl: UITableView!
var ref: DatabaseReference!
var jobList = [JobModel]()
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let job = jobList[indexPath.row]
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ViewControllerTableViewCell
let job: JobModel
job = jobList[indexPath.row]
cell.lblCol.text = job.collection
cell.lblDel.text = job.delivery
cell.lblShip.text = job.shipper
cell.lblCon.text = job.consignee
cell.lblEmai.text = job.email
cell.lblRef.text = job.reference
cell.lblFreight.text = job.freight
cell.collected.text = job.collected
cell.delivered.text = job.delievered
return cell }
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return jobList.count
}
override func viewDidLoad() {
super.viewDidLoad()
if FirebaseApp.app() == nil {
FirebaseApp.configure() }
ref = Database.database().reference().child("jobs");
ref.observe(DataEventType.value) { (snapshot) in
if snapshot.childrenCount>0 {
self.jobList.removeAll()
for jobs in snapshot.children.allObjects as! [DataSnapshot]{
let jobObject = jobs.value as? [String: AnyObject]
let jobId = jobObject?["id"]
let jobShipper = jobObject?["shipper"]
let jobConsignee = jobObject?["consignee"]
let jobEmail = jobObject?["email"]
let jobReference = jobObject?["reference"]
let jobFreight = jobObject?["freight"]
let jobCollection = jobObject?["collection date"]
let jobDelivery = jobObject?["delivery date"]
let jobPod = jobObject?["pod"]
let jobCollected = jobObject?["collected"]
let jobDelivered = jobObject?["delivered"]
let job = JobModel(id: jobId as! String?,
shipper: jobShipper as! String?,
consignee: jobConsignee as! String?,
email: jobEmail as! String?,
reference: jobReference as! String?,
freight: jobFreight as! String?,
collection: jobCollection as! String?,
delivery: jobDelivery as! String?,
pod: jobPod as! String?,
collected: jobCollected as! String?,
delivered: jobDelivered as! String?)
self.jobList.append(job)
}
self.tbl.reloadData()
} } }
override func viewDidAppear(_ animated: Bool) {
Auth.auth().currentUser != nil; do {
self.loginlbl.text = "Hello " + (Auth.auth().currentUser?.email)!
}}
}
Your rules let you access to the children node of jobs. like jobs/user_id_1
So you have to listen to the child instead of the whole jobs node
Database.database().reference().child("jobs");
to
Database.database().reference().child("jobs\loggedInUserID");