MultilineHow much bigger, if you could measure for instance Xcode icon and yours. Some icons are transparent on some parts of their borders, making them look smaller. In my case, the Launchpad icon is 256*256
Xcode is the same size but looks like 230*230 Hi Claude.
Thank you for the reply.
I think it will be easier just to look at it: Screenshot - https://www.icloud.com/iclouddrive/05iQDEyZvyOaQWN0GRUc9-RJg#CleanShot_2021-01-18_at_15.57.
Possibly because I have a canvas with 1024px and the icon size is 1024px as well. But how much smaller I should make an icon on the canvas to fix that?
Post
Replies
Boosts
Views
Activity
Claude, and thank you again.
Look at the bigger Screenshot - https://www.icloud.com/iclouddrive/0wnlQIuFKVyq9l0uKgc1TEv5A#CleanShot_2021-01-18_at_17.15: from this point you should mention that all icons in Big Sur style have the same size and only Ace Link stands out from them...
Here is a solution worked for me:
let request: NSFetchRequest<Currency> = Currency.fetchRequest()
request.predicate = NSPredicate(format: "id = %@", id)
do {
let fetchResult = try context.fetch(request)
if fetchResult.count > 0 {
for doubledData in fetchResult {
context.delete(doubledData)
}
}
What is the log ? Is it this print: print(currency.numberOfObjects)
Attach the log: LOG
So, why 13 or 14 values printed ?
Can't understand too. At the start the table is empty... Why there is always 13 numbers and not 1,5,6 etc...
Which func is called when you click a cell in VC2 ?
It's
let cell = tableView.cellForRow(at: indexPath) as! PickCurrencyTableViewCell
for currency in currencyArray {
if currency.shortName == cell.shortName.text {
currency.isPicked = !currency.isPicked
coreDataManager.save()
}
}
}
There on VC2 it sorts the array of items and if shortName (EUR) equals to the shortName of pickedCell then it change it isPicked CoreData attribute from false to true. And if I was able to click again then from true to false. And save it to database after. The NSFetchedResultController is setup to filter and show in VC1 tableView only the state isPicked = true.
Is it what you expect ?
Not quite sure, because I expect behaviour like I pressed on cell in VC2 and VC1 should load that currency I picked based on isPicked state...
Database already filled with data. I receive 33 objects and they all successfully loads with NSFetchedResultsController in VC2
VC1:
VC1
VC2:
VC2
Hi Claude, thank you for the answer!
What is cell ?
Here is the full code for my cell. tableView shows items from NSFetchedResultsController based on predicate "isForConverter" = YES, which I set in another VC.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "converterCell", for: indexPath) as! ConverterTableViewCell
let currency = fetchedResultsController.object(at: indexPath)
cell.shortName.text = currency.shortName
cell.fullName.text = currency.fullName
cell.numberTextField.delegate = self
return cell
}
Then, when you change in one cell,
I tried to create a global variable, then in textFieldDidEndEditing() assign that variable to a string from textField.text, then assign that variable in cellForRowAt() as cell.numberTextField.text = number and reload a tableView. As a result a received all cells display number just when tableView first loads and I can't edit any number.
Also, why do you reset to "0" when editing ends ?
Base textField.text string for my cell is 0, so when I click on cell I should be able to reset it to "", edit number and if I want to switch to edit another cell, I want that first cell to be 0 again. This is why I set it to 0. Take a look at the video: https://cln.sh/O3wGJE
What I want:
I need to be able to edit any cell's textField, type a number and all other cells as soon as I type the number, change their textField.text accordingly after calculation (for example the number I type in edited cell should be multiplied by 2 and displayed in all other cells. And I should be able to pick another cell, type number etc.
take a look at the video: https://cln.sh/xjw5Od. Here if I pick any available cell, type number, then all other cells recalculate it's value based on what I typed in editable cell like live.
Thank you very much for your time spent on my question! Appreciate!
You do not set the content of cell.numberTextField in cellForRowAt. Why ?
This is because I want the content to be set by func which multiplies by 2 any number that was typed in currently active cell. And I don't know how I can separate active cell from all others each time I click on a new cell...
Imagine I have 1, 2, 3 in 3 cells. Do you mean that when typing 5 in cell 3, cell 0 should become 2, cell 2 become 4 and cell 3 : 5 ? 8 ? 10 ? Then you type 20 in cell 0, what should be the result ?
When typing 5 in cell 3 I want to receive 5x2 = 10 as an output in any other cells (cell 1 and cell 2) which is currently on the screen. Perform simple calculation (any number typed from active cell, multiple it by 2 and put the result in all other cells which is not active in the tableView as soon as I typed that number. Calculation should be displayed in a real time, not when I typed number and clicked done or closed the keyboard on active cell.
you do not segregate between different cells. Why ?
In this methods I just put some basic code and it should define behaviour for:
textField.text = ""
textField.textColor = UIColor.systemBlue
as I click on cell, it becomes active, textField clears itself (by default it displays number 0) and color of active cell turns blue to distinguish which of the cell is active now.
textField.text = "0"
textField.textColor = UIColor.black
As soon as I click on another cell to make it textField editable I turn the cell I was just editing into default 0 and text for black as for all non-editable cells
What I would do:
What would you do if your tableView was populated with Core Data from NSFetchedResultsController? Should I create from FRC an additional array for dataSource or I can use the one I receive from FRC? I define a dataSource I receive from FRC in my tableView cell as:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "converterCell", for: indexPath) as! ConverterTableViewCell
let currency = fetchedResultsController.object(at: indexPath)
cell.shortName.text = currency.shortName
cell.fullName.text = currency.fullName
cell.numberTextField.delegate = self
return cell
}
what are the initial values in cells (from FRC ?)
My FRC has a custom type called Currency. Currency is a CoreData entity which has attributes: shortName ("USD"), fullName ("American Dollar"), isPickedForConverterScreen (Bool, true), currentValue (Double: 75,44), and so on for other currencies.
My tableView shows the Currency object only when isPickedForConverterScreen == true. tableView cell have 2 labels: for displaying shortName and fullName and a textField. Here is how I define it:
let cell = tableView.dequeueReusableCell(withIdentifier: "converterCell", for: indexPath) as! ConverterTableViewCell
let currency = fetchedResultsController.object(at: indexPath)
cell.shortName.text = currency.shortName
cell.fullName.text = currency.fullName
return cell
}
You type something in a cell
let's assume I have 2 cells in my tableView: USD, RUB.
I click on USD cell - type number - RUB cell recalculate its textField.text as: number I typed in USD cell x RUB.CurrentValue. For example I typed 2, then 2 x 75,44 = 150,88 to display in RUB cell. Calculation should be performed live, not when I end editing USD cell
What do you then get in all cells ?
The thing is I need to perform a calculation for all cells based on number I typed in active cell x currentValue number stored for each Currency object. And I should be able to pick another cell with currency and calculate all other currencies based on value I typed + their currentValue
So am I understood correct that my dataSource is the array of Currencies which I can receive as:
let array: [Currencies] = fetchedResultsController.fetchedObjects
I don't define it anywhere in my VC for now. Only when defying cell in cellForRow:
let currency = fetchedResultsController.object(at: indexPath)
Thank you very much, Claude!
After playing with the code I found that this version is good for me:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let formatter = NumberFormatter()
formatter.usesGroupingSeparator = true
formatter.numberStyle = .decimal
formatter.decimalSeparator = "."
formatter.groupingSeparator = " "
let completeString = textField.text!.replacingOccurrences(of: formatter.groupingSeparator, with: "") + string
guard let value = Double(completeString) else { return false }
numberFromTextField = value
let formattedNumber = formatter.string(from: NSNumber(value: value)) ?? ""
textField.text = formattedNumber
if string.isEmpty {
return true
}
return string == formatter.decimalSeparator
}
But I have one problem:
while pressing backspace on keyboard the first press doesn't remove the last character in string, the second and the next presses do. I think the problem is in my if string.isEmpty { return true } line as I found out when you press the backspace it returns an empty string... Short gif with problem: https://cln.sh/OZOslI
Any thoughts what's the problem might be?
Where do you do it ?
Nowhere except at FRC delegate method didChange I showed in the initial post...
Could you also show cellForRowAt delegate func ?
Sure, there it is:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "converterCell", for: indexPath) as! ConverterTableViewCell
let currency = fetchedResultsController.object(at: indexPath)
cell.flag.image = currencyManager.showCurrencyFlag(currency.shortName ?? "notFound")
cell.shortName.text = currency.shortName
cell.fullName.text = currency.fullName
cell.numberTextField.tag = indexPath.row
cell.numberTextField.delegate = self
if let number = numberFromTextField, let pickedCurrency = pickedCurrency {
cell.numberTextField.text = currencyManager.performCalculation(with: number, pickedCurrency, currency)
}
return cell
}
Also show you the method where I reload all rows except one in editing mode:
func textFieldDidChangeSelection(_ textField: UITextField) {
let activeTextFieldIndexPath = IndexPath(row: textField.tag, section: 0)
pickedCurrency = fetchedResultsController.object(at: activeTextFieldIndexPath)
guard let currencyObjects = fetchedResultsController.fetchedObjects?.count else {return}
var nonActiveIndexPaths = [IndexPath]()
for object in 0..<currencyObjects where object != textField.tag {
nonActiveIndexPaths.append(IndexPath(row: object, section: 0))
}
tableView.reloadRows(at: nonActiveIndexPaths, with: .none)
}
Then, after, you may call reloadData() once datasource is updated
I found out that if I use reloadData() + 0.2 seconds after deletion, everything works good. But FRC should call reloadData automatically, I shouldn't use it manually...
case .delete:
if let indexPath = indexPath {
tableView.deleteRows(at: [indexPath], with: .none)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
self.tableView.reloadData()
}
}
Sure. It's just:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fetchedResultsController.sections![section].numberOfObjects
}
But difficult to say what to write exactly without the complete code of the class.
Attached is the complete class code:
Complete Code
Usually, this is handled by doing the call (to self.tableView.reloadData()) in a completion handler of the calling
and I can call just tableView.reloadData() in the completion hander, everything works perfect too, except the cell deletion animation lost its smoothness, it became fast and ugly. And if I use +0.2 seconds the animation saves the smoothness like it was.
Also this error happens only when I delete a lot of cells one after another (> 10 cells) like on the GIF from initial post. If I will delete 1-2 cells - there won't be any error and no need to call tableView.reloadData().
Could you show code with reloadData() in completion handler, in case we can find a way to improve smoothness.
Sure. I just add reloadData() to .delete case. Check the GIF with animation in that case: https://cln.sh/F551dX
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch type {
case .update:
if let indexPath = indexPath {
tableView.reloadRows(at: [indexPath], with: .none)
}
case .move:
if let indexPath = indexPath, let newIndexPath = newIndexPath {
tableView.moveRow(at: indexPath, to: newIndexPath)
}
case .delete:
if let indexPath = indexPath {
tableView.deleteRows(at: [indexPath], with: .none)
tableView.reloadData()
}
case .insert:
if let newIndexPath = newIndexPath {
tableView.insertRows(at: [newIndexPath], with: .none)
}
default:
tableView.reloadData()
}
}
Then version with asyncAfter .now + 0.5. Check the GIF with animation: https://cln.sh/WK6F8r
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch type {
case .update:
if let indexPath = indexPath {
tableView.reloadRows(at: [indexPath], with: .none)
}
case .move:
if let indexPath = indexPath, let newIndexPath = newIndexPath {
tableView.moveRow(at: indexPath, to: newIndexPath)
}
case .delete:
if let indexPath = indexPath {
tableView.deleteRows(at: [indexPath], with: .none)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.tableView.reloadData()
}
}
case .insert:
if let newIndexPath = newIndexPath {
tableView.insertRows(at: [newIndexPath], with: .none)
}
default:
tableView.reloadData()
}
}
Can't you set a var fetchedCompleted that would be set true after fetch
But where is the fetch ends? Where to call that var?
Claude, it seems I found out what the reason of that crash was. This is what my print() tryings gave: https://cln.sh/jpB5tG
What is a pickedCurrency: this is a global variable of custom type Currency which I created to receive its attribute currentValue (Double, 87.88). I need that value only from the picked to edit cell. After I use that value for calculation in cellForRowAt() and result of the calculation fills all other cells which is not in edit now.
I define pickedCurrency in textFieldDidBeginEditing() because there I receive the exact row of Currency I picked to edit:
func textFieldDidBeginEditing(_ textField: UITextField) {
pickedCurrency = fetchedResultsController.object(at: IndexPath(row: textField.tag, section: 0))
numberFromTextField = 0
textField.textColor = UIColor(named: "BlueColor")
textField.placeholder = "0"
textField.text = ""
}
And then use it's value in cellForRowAt to calculate all other cells values based on pickedCell value:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "converterCell", for: indexPath) as! ConverterTableViewCell
let currency = fetchedResultsController.object(at: indexPath)
cell.flag.image = currencyManager.showCurrencyFlag(currency.shortName ?? "notFound")
cell.shortName.text = currency.shortName
cell.fullName.text = currency.fullName
cell.numberTextField.tag = indexPath.row
cell.numberTextField.delegate = self
if let number = numberFromTextField, let pickedCurrency = pickedCurrency {
cell.numberTextField.text = currencyManager.performCalculation(with: number, pickedCurrency, currency)
}
return cell
}
It seems when I delete a lot of cells and then click on random cell to edit it's not updates its IndexPath(row: textField.tag, section: 0)...
And this is why when I call reloadData() it refreshes pickedCurrency.
Maybe there is a way to receive Currency object I picked for editing in cellForRowAt()?
Also I have one more related problem I can't fix there.
My prototype cell has a numberTextField (0 by default). When I entering the edit mode I want it to be hidden and back to visible when edit mode is off.
Here is the code for that behaviour in cellForRowAt():
cell.numberTextField.isHidden = tableView.isEditing ? true : false
return cell
But the textField is still visible when I entering the edit mode: https://cln.sh/0hXOKg
Any solutions comes in mind?
I tried to initialise cell as:
let cell = tableView.dequeueReusableCell(withIdentifier: "converterCell") as! ConverterTableViewCell
and assess its textfield property within turnEditing() but no luck.