I have 2 Controllers: TableViewController and ViewController. TableViewController is responsible for displaying all data, View Controller is responsible for creating new data.
Now I want to make it possible to edit the current data also in ViewController. When we click on data, we need to switch to the ViewController and replace all default values with the current values. When we change and click save, we go back to TableViewController, where we already see the change.
class OperationsViewController: UITableViewController {
// MARK: - Stored Properties
var transactions: Results<Transaction>!
var sections = [(date: Date, items: Results<Transaction>)]()
// MARK: - UITableViewController Methods
override func viewDidLoad() {
super.viewDidLoad()
transactions = realm.objects(Transaction.self)
}
override func viewWillAppear(_ animated: Bool) {
super .viewWillAppear(animated)
assembleGroupedTransactions()
tableView.reloadData()
}
}
// MARK: - Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let indexPath = tableView.indexPathForSelectedRow {
let section = sections[indexPath.section]
let item = section.items[indexPath.row]
print(item)
if segue.identifier == "editOrDeleteOperationCell" {
let addTableViewController = segue.destination as! AddTableViewController
addTableViewController.defaultTransaction = item
}
}
}
}
// MARK: - User Interface
extension OperationsViewController {
@discardableResult private func assembleGroupedTransactions() -> Array<Any> {
// fetch all Items sorted by date
let results = realm.objects(Transaction.self).sorted(byKeyPath: "date", ascending: false)
sections = results
.map { item in
// get start of a day
return Calendar.current.startOfDay(for: item.date)
}
.reduce([]) { dates, date in
// unique sorted array of dates
return dates.last == date ? dates : dates + [date]
}
.compactMap { startDate -> (date: Date, items: Results<Transaction>) in
// create the end of current day
let endDate = Calendar.current.date(byAdding: .day, value: 1, to: startDate)!
// filter sorted results by a predicate matching current day
let items = results.filter("(date >= %@) AND (date < %@)", startDate, endDate)
// return a section only if current day is non-empty
return (date: startDate, items: items)
}
return sections
}
But when I trying to send current data to next ViewController I get error:
*** Terminating app due to uncaught exception 'RLMException', reason: 'Attempting to modify object outside of a write transaction - call beginWriteTransaction on an RLMRealm instance first.'
I guess that I have problem with Category. Look on my model:
class Transaction: Object {
@objc dynamic var controlStatus = 0
@objc dynamic private var privateCategory: String = Category.consumption.rawValue
var category: Category {
get { return Category(rawValue: privateCategory)! }
set { privateCategory = newValue.rawValue }
}
@objc dynamic var amount = "0"
@objc dynamic var date = Date()
@objc dynamic var note = ""
}
controlStatus needs for monitors the status of the transaction that will be needed in the future. Where 0 is the expense, 1 is the income.
The big problem I suppose is that I created categories by enum.
I need to change the arrays with categories depending on the controlStatus.
Now is this my model of Category:
indirect enum Category: String {
case income = "+"
case consumption = "-"
case salary = "salary"
case billingInterest = "billingInterest"
case partTimeJob = "partTimeJob"
etc.
}
extension Category: RawRepresentable {
typealias RawValue = String
init?(rawValue: RawValue) {
switch rawValue {
case "+": self = .income
case "-": self = .consumption
case "salary": self = .salary
case "billingInterest": self = .billingInterest
case "partTimeJob: self = .partTimeJob
case "pleasantFinds": self = .pleasantFinds
case "debtRepayment": self = .debtRepayment
case "noCategories": self = .noCategories
case "food": self = .food
etc.
default:
return nil
}
}
var rawValue: RawValue {
switch self {
case .salary:
return "salary"
case .billingInterest:
return "billingInterest"
case .partTimeJob:
return "partTimeJob"
case .pleasantFinds:
return "pleasantFinds"
case .debtRepayment:
return "debtRepayment"
case .noCategories:
return "noCategories"
case .food:
return "food"
case .cafesAndRestaurants:
return "cafesAndRestaurants"
etc.
}
}
}
realm.write { ... }- MadProgrammeraddTableViewController.defaultTransaction = itemto pass the item to the second VC which is fine, but this is now uneditable in the VC outside ofrealm.writeblock. I suspect the crash is caused by some editing code that isn't included above - what other code is inAddTableViewController? It may be inviewDidLoador you may edit thedefaultTransactionsomewhere else - which you can't do. How iseditDatacalled? - Chris Shawcategories, theitemis passed. Most likely I have a problem with the transferCategory. Can you help me with this? - Mikhail Tseitlin