I figured it out, it was my programming mistake and lack of proper sleep :). Another VC which was listening for notifications about the result of the same fetch was triggering a popup even though it was not visible, but was alive, embedded in a tab bar controller. So my "failure" popup was never executed properly. I figured it out after I updated the showModal method with the sender parameter and following that I have added a fix that requires the calling VC to be visible when it wants to present a popup:
func showModal(sender: UIViewController, title: String, msg: String, handler: ((UIAlertAction) -> Void)? = nil) {
let alert = UIAlertController(title: title, message: msg, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: handler))
DispatchQueue.main.async {
if sender.isVisible() {
self.present(alert, animated: true, completion: nil)
}
}
}
where isVisible():
extension UIViewController {
func isVisible() -> Bool {
return self.isViewLoaded && self.view.window != nil
}
}
Post
Replies
Boosts
Views
Activity
I have managed to achieve my goal by creating a Storyboard and assign it to my custom UIViewController class.
Make sure to set the Class and Storyboard ID:
The code to present and use the Storyboard from the the presenting ViewController:
let popup = UIStoryboard(name: "MyPopupVC", bundle: nil).instantiateViewController(withIdentifier: "myPopupUniqueID") as! MyPopupVC
if let sheet = popup.sheetPresentationController {
sheet.detents = [.large()]
sheet.prefersGrabberVisible = true
}
popup.set(account: account) //Transfer account object to popup VC
present(popup, animated: true)
Found the answer, pretty easy:
func textFieldDidChangeSelection(_ textField: UITextField) {
if textField == text1 {
print(textField.text) // this code should run only for text1 for example
}
}
I realized that didPullToRefresh does not need to be marked as async. Removing "async" from the function signature solves the problem
One more thing hopefully useful for anyone, I was unable to use isEnabled property of the button to create the desired effect even with reloadRows but I managed to update the appearance of the slider with the following trick:
cell.cellSlider.isUserInteractionEnabled = cellData[indexPath.row].sliderOn
cell.cellSlider.alpha = cellData[indexPath.row].sliderOn == true ? 1.0 : 0.5
All the best!
@Claude31, your solutions was correct. I did some debugging and noticed that I was not updating all the data in my cell like you suggested. Mainly I was not setting the UISLider value in cellForRowAt but in the custom UITableViewCell.
So now I know that reloadRows triggers cellForRowAt and I make sure that in cellForRowAt I always assign the cell contents: slider, labels, controls etc to a value from my array of myData structures containing the configurations/values of these elements.
Thanks again!
Thanks a lot for the reply Claude31 and for clarifying some aspects that were not very obvious for me.
I have tried implementing something along your line but I still have to press twice on my the SegmentedControl button to set the value of the button when I use myTableView.reloadRows(at: [index], with: .none) in func segmentControlSelected. Even so, the appeareance of the UISlider does not change.
If I comment out reloadRows(at:with:), the SegmentedControl buttons set their values on the first click. Do you know why this happens?
My cellForRowAt func contains the following:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: K.cellNibName, for: indexPath) as! AccountHoldingsCell
//Cell Delegate setup
cell.delegate = self
cell.cellIndexPath = indexPath
....
cell.cellSlider.isEnabled = myData[indexPath.row]
//Activity indicator
self.activityIndicatorView.stopAnimating()
return cell
}
Inside ViewControl class I have:
class ViewController: UIViewController {
....
var mergedBalance = ViewBalanceModel()
var tempMergedBalance = ViewBalanceModel()
var nbOfTableItems = 0
var myData : [Bool] = []
...
}
myData is initialized inside a custom protocol that decodes API data and constructs a model in func
extension ViewController: ViewBalanceProtocol {
func didUpdateBalanceTable(from manager: Manager, with accData: ViewBalanceModel) {
.... //Get Api data into tempMergedBalance struct
nbOfTableItems = tempMergedBalance.arrayOfItems.count
myData = Array(repeating: false, count: nbOfTableItems) //Array setting initial values as False for UISlider
DispatchQueue.main.async {
self.mergedBalance = self.tempMergedBalance
self.myTableView.refreshControl?.endRefreshing()
self.myTableView.reloadData()
}
}
And of course:
extension ViewController: AccountCellDelegate {
func segmentControlSelected(cell: UITableViewCell, at index: IndexPath, segmentValue: Int, slider: UISlider) {
myData[index.row] = (segmentValue != 0)
myTableView.reloadRows(at: [index], with: .none)
}