Apologies
You must be signed in to watch this lesson.
Employee Type Enumeration Grouping
Intermediate Training Core Data
With the employee type now persisted in our Core Data database, we can now apply filtering based on employee.type. Once we get this fix in, we'll be able to insert a new employee whenever we create one inside our application. As a bonus, I'll talk about Enumeration and why it's useful to use them inside our programs.

Comments (19)
Christopher Lee
6 years ago
Really enjoyed this episode! The concepts I learnt are super valuable. Thanks Brian!
Brian Voong
6 years ago
Thanh Minh
6 years ago
Imagine that I have 3 yrs experiences in only 20 minutes after see what you refactor in this episode. Great thanks, Brian!
mohitnandwani
6 years ago
Wish I could give this comment a like :) Brian, you are awesome! :)
Ashim Dahal
6 years ago
Thank you for such a wonderful teaching. I wonder if you could make stock app for your next iOS tutorial using open source api, like yql or yahoo finance.
Brian Voong
6 years ago
iHobbit
6 years ago
Would it be more natural to make the employeeTypes array a static let as part of the enum definition?
Nick Vaughn Kang
6 years ago
Hi Brian, First, I want to say I'm learning a lot from your videos. Watched the Stanford iOS programming series and they mentioned using predicates to fetch data. Would that be the preferred method over looping through the "allEmployees" array multiple times? Thanks, Nick
Nick Vaughn Kang
6 years ago
edit: I mean "companyEmployees" instead of "allEmployees"
Dejan Ribnikar
6 years ago
Hi Brian, I tried to implement editing and deleting employees as well, but only partially succeeded. Deleting works fine, but when editing, If I change the employee type (section), it won't work. Editing name and birthday works fine, as long as I don't touch segmented control. How can I get it to edit the section as well? Thanks!
Dejan Ribnikar
6 years ago
Actually it does work too, just won't reload tableView.
Dejan Ribnikar
6 years ago
func handleEdit() { let context = CoreDataManager.shared.persistentContainer.viewContext employee?.name = nameTextField.text let dateFormatter = DateFormatter() let format = "dd/mm/yyyy" dateFormatter.dateFormat = format employee?.employeeInfo?.birthday = dateFormatter.date(from: birthdayTextField.text!) employee?.type = employeeTypeSegmentedControl.titleForSegment(at: employeeTypeSegmentedControl.selectedSegmentIndex) do { try context.save() dismiss(animated: true, completion: { self.delegate?.didEditEmployee(employee: self.employee!) }) } catch let error { print("\(error)") } } func didEditEmployee(employee: Employee) { self.tableView.reloadData() }
Dejan Ribnikar
6 years ago
needed to add fetchEmployees() :)
jdfrys
5 years ago
Hey, what was your code to delete employees?
magic
6 years ago
Thank you a lot for this great tutorial!!!
Raph
5 years ago
Hi Brian, I am trying to apply what we did for the companies to the employees. So edit and delete. I am getting several bugs and I was wandering if you could provide a few solutions. The first bug is that we I go to edit, the segment control is not at the right place. I couldn't find a way to save the employee as a staff for example, and having it stay there... If I decide to change the place of the segment control in Editing mode, the element doesn't change section in my table view, unless I quit the app and come back ... I would rally appreciate it if you could provide a few solutions.... Thanks!
Tube
5 years ago
Why wouldn't we use a predicate to fetch only the records we want instead of filtering all records just to pull out what we want?
Brian Voong
5 years ago
Tube
5 years ago
I think the way we used enum here is little different than using an array of string.
Brian Voong
5 years ago
kazu
5 years ago
Ok, for anyone who wonders how to implement the edit on the sections. Here is my solution, however i did it on the main view (company) not (employees) extension PatientController: CreatePatientControllerDelegate { func didEditPatient(patient: Patient, priority: Int) { let oldsection = priority guard let section = patientType.index(of: patient.priority!) else { return} let row = allPatients[section].count - 1 let newrow = allPatients[section].count let oldrow = allPatients[oldsection].count - 1 let reloadIndexpath = IndexPath(row: row, section: section) let insertionIndexPath = IndexPath(row: newrow, section: section) let deleteIndexPath = IndexPath(row: oldrow, section: oldsection) if section == priority { tableView.reloadRows(at: [reloadIndexpath], with: .middle) print("reloadIndexPath:", reloadIndexpath) } else { allPatients[section].append(patient) tableView.insertRows(at: [insertionIndexPath], with: .fade) allPatients[oldsection].remove(at: oldrow) tableView.deleteRows(at: [deleteIndexPath], with: .fade) } } func didAddPatient(patient: Patient) { guard let section = patientType.index(of: patient.priority!) else {return} let row = allPatients[section].count let insertionIndexPath = IndexPath(row: row, section: section) print("ADD - insertionIndexPath:", insertionIndexPath) allPatients[section].append(patient) tableView.insertRows(at: [insertionIndexPath], with: .middle) } } and in your CreateCompanyController file you need to change: protocol CreatePatientControllerDelegate { func didAddPatient(patient: Patient) func didEditPatient(patient: Patient, priority: Int) } and pass the old value: dismiss(animated: true) { self.delegate?.didEditPatient(patient: self.patient!, priority: self.oldpriority) } the reason for this is because the tableview gets the section from what already is in the CoreData, so you need to pass the value you are filtering on BEFORE you save the new values. this is the problem when updating the values from the buttons (executive, staff member, intern) I could not find a way to "move" the employee to another section, so i did it this way with insert and delete. im not sure this is the best solution, but its what worked for me.
ga
4 years ago
Good solution.
jamakaca
5 years ago
Brian, Is there a way to hide empty sections? As in, if the Executive section has no employees, can this section be hidden on the tableView until it is populated with an item? I have tried a few different methods that I read about on various websites, but I can't seem to make this work. Just wondering if this is possible. Have a good evening!
Brian Voong
5 years ago
jamakaca
5 years ago
Brian, Thank you very much for the quick response. I must be missing a step some place. I tried variants of what you have above using the various arrays defined in EmployeesController.swift but I can't produce the result that I am looking for. Using what you provided above, I get an error - use of unresolved identifier 'executives' I have tried the below options as well allEmployees.count < 0 ? 50 : 0 (no sections visible) allEmployees.count > 0 ? 50 : 0 (all sections visible) employeeTypes.count < 0 ? 50 : 0 (no sections visible) employeeTypes.count > 0 ? 50 : 0 (all sections visible) employees.count < 0 ? 50 : 0 (no sections visible) employees.count > 0 ? 50 : 0 (no sections visible) Thanks
Brian Voong
5 years ago
jamakaca
5 years ago
Yes Sir. That worked! Thank you very much. By the way, this course has been extremely helpful for me. I am fairly new at programming but your instruction throughout this course has clarified many points that were not quite clicking for me. Thanks.
xuhua
5 years ago
老师好,这个guard let section = employeeTypes.index(of: employee.type!) else { return } 里的index(of: )好像不存在了,请问在4.2里应该是什么呢?谢谢。
Brian Voong
5 years ago
xuhua
5 years ago
老师,貌似4.2版本里还是employeeTypes.index(of: employee.type!) else { return },还发现个问题,这个可能是我的问题,就是下载了源代码之后,您的coredata里的那些company之类的都显示出错,就是按CMD点击也说没有这个东西,这样就不能build了,无法运行您的程序啊。
xuhua
5 years ago
老师,抱歉,现在都成功运行了,解决了!谢谢!
G123
5 years ago
Hey Brian, I really need help implementing how to delete employees from the tableview section and coredata. I keep getting a crash that says Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of sections. The number of sections contained in the table view after the update (0) must be equal to the number of sections contained in the table view before the update (4), plus or minus the number of sections inserted or deleted (0 inserted, 0 deleted).' *** First throw call stack: Here is my EmployeeController code... import UIKit import CoreData // lets create a UILabel subclass for custom text drawing class IndentedLabel: UILabel { } class EmployeesController: UITableViewController, CreateEmployeeControllerDelegate { func didAddEmployee(employee: Employee) { guard let section = employeeTypes.index(of: employee.type!) else { return } // what is my row? let row = allEmployees[section].count let insertionIndexPath = IndexPath(row: row, section: section) allEmployees[section].append(employee) tableView.insertRows(at: [insertionIndexPath], with: .middle) } func didEditEmployee(employee: Employee) { // update my tableview somehow guard let section = employeeTypes.index(of: employee.type!) else { return } let row = allEmployees[section].count allEmployees[section].append(employee) let reloadIndexPath = IndexPath(row: row, section: 4) tableView.reloadRows(at: [reloadIndexPath], with: .middle) } var company: Company? override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) navigationItem.title = company?.name } override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let label = IndentedLabel() if section == 0 { label.text = EmployeeType.Intern.rawValue } else if section == 1 { label.text = EmployeeType.Executive.rawValue } else { label.text = EmployeeType.SeniorManagement.rawValue } label.text = employeeTypes[section] label.backgroundColor = UIColor.white label.textColor = UIColor.darkBlue label.font = UIFont.boldSystemFont(ofSize: 16) return label } override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return 50 } var allEmployees = [[Employee]]() var employeeTypes = [ EmployeeType.Intern.rawValue, EmployeeType.Executive.rawValue, EmployeeType.SeniorManagement.rawValue, EmployeeType.Staff.rawValue, ] override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? { let deleteAction = UITableViewRowAction(style: .destructive, title: "Delete") { (_,indexPath) in self.allEmployees = [self.allEmployees[indexPath.row]] //let company = self.companies[indexPath.row] self.allEmployees.remove(at: indexPath.row) self.tableView.deleteRows(at: [indexPath], with: .automatic) } let editAction = UITableViewRowAction(style: .normal, title: "Edit") { (_,indexPath) in print("Editing company...") } return [deleteAction, editAction] } private func fetchEmployees() { guard let companyEmployees = company?.employees?.allObjects as? [Employee] else { return } allEmployees = [] // let's use my array and loop to filter instead employeeTypes.forEach { (employeeType) in // somehow construct my allEmployees array allEmployees.append( companyEmployees.filter { $0.type == employeeType } ) } override func numberOfSections(in tableView: UITableView) -> Int { return allEmployees.count } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return allEmployees[section].count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) let employee = allEmployees[indexPath.section][indexPath.row] cell.textLabel?.text = employee.name if let birthday = employee.employeeInformation?.birthday { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "MMM dd, yyyy" cell.textLabel?.text = "\(employee.name ?? "") \(dateFormatter.string(from: birthday))" } cell.backgroundColor = UIColor.tealColor cell.textLabel?.textColor = .white cell.textLabel?.font = UIFont.boldSystemFont(ofSize: 15) return cell } let cellId = "cellllllllllllId" override func viewDidLoad() { super.viewDidLoad() fetchEmployees() tableView.backgroundColor = UIColor.darkBlue tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellId) setupPlusButtonInNavBar(selector: #selector(handleAdd)) } @objc private func handleAdd() { print("Trying to add an employee..") let createEmployeeController = CreateEmployeeController() createEmployeeController.delegate = self createEmployeeController.company = company let navController = UINavigationController(rootViewController: createEmployeeController) present(navController, animated: true, completion: nil) } @objc private func handleEdit() { print("Trying to add an employee..") let createEmployeeController = CreateEmployeeController() createEmployeeController.delegate = self createEmployeeController.company = company let navController = UINavigationController(rootViewController: createEmployeeController) present(navController, animated: true, completion: nil) } }
Brian Voong
5 years ago
G123
5 years ago
Got it, thank you! sorry for the long post
iHobbit
4 years ago
Hey Brian, I have a general question relating to the way view controllers are done in the app. I am trying to build something similar where I use a customized navigation controller to present a UIViewController. That view controller is a simple controller that either shows an image wrapped in a UIScrollView or a PDF displayed in a webView. My question is that in both cases, the entire view scrolls up and down when I scroll the content of the view. If I pull the image down, the title bar from the navigation view will shrink to a small size, and gray will bounce underneath the image if I scroll the other way. Is there a clean way to prevent this behavior? There is no "scrollEnabled" property for the UIViewController itself or the navigationController it is embedded in. Thanks!
Brian Voong
4 years ago
jdhindsa
4 years ago
Hi Brian, I'm running the app that I downloaded from section 23 and nothing seems to be saving or showing in the table views. I see this message in the debugger: 0 0 2 Trying to add an employee.. 2019-05-28 15:37:38.974657-0400 IntermediateTraining[16737:247669] [MC] System group container for systemgroup.com.apple.configurationprofiles path is /Users/jasondhindsa/Library/Developer/CoreSimulator/Devices/2091988E-9B09-40C6-83D4-32D2D3C8D69E/data/Containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles 2019-05-28 15:37:38.975027-0400 IntermediateTraining[16737:247669] [MC] Reading from private effective user settings.
jdhindsa
4 years ago
After erasing all the content and data from the simulator and trying again, I'm getting this message now: 2019-05-28 16:06:46.091636-0400 IntermediateTraining[19157:279796] [Common] _BSMachError: port 13f13; (os/kern) invalid capability (0x14) "Unable to insert COPY_SEND"
Cinquain
4 years ago
This video was straight up beast mode
Matt Le Fleur
4 years ago
If you want to make sure that you capture every value of an enum (e.g. executive, senior management etc.), I like making the enum iterable. To do this we can simply add the caseIterable protocol to take care of it. Then when we are setting up the employee types array, we could use something like: for type in EmployeeType.allCases { employeeTypes.append(type.rawValue) } We could also add: employeeTypes = [] Just to make doubly sure that we don't do this multiple times! You can obviously choose not to do this if you don't want to show everything in your tables or segmented controls :) Anyway, that's just my two cents. Thanks for the course Brian, it's been great so far!
mitchbaum
3 years ago
This is the first video where i was so lost i felt like i was on mars. as a new programmer, this enumeration concept is beyond me lol
HELP & SUPPORT