reloadData in UITableView on uibutton click - swift - swift

I've been playing around with the UITableView in swift.
Firstly, my goal is to append a cell with array data on click of the UIButton.
I've managed to do this with the following action
#IBAction func Option1Click(sender: UIButton) {
arrayOfQuestions.append(QuestionMark(Label:"Grocery List", option1:"yes", option2:"no")) }
But the issue is i cannot get to reload the tableView, because the tableView.reloadData() isn't inherited.
Secondly, i want to apply a timer. So that the appending of the cell would take a specific time interval.
I've managed to find a function on the forums
var timer = NSTimer.scheduledTimerWithTimeInterval(3, target: self,
selector: Selector("Option1Click"), userInfo: nil, repeats: true)
But i don't know where exactly to place this code to work.
Would appreciate any insights greatly!
Thank you.

You should get a reference to your tableview as an outlet and name it whatever you like.
After you can use the reference of the tableview and call the reload method
like this:
nameofyourreference.reloadData()

Related

Table view not updating when called from another View Controller using NotificationCenter

I have a table view in one view controller. I want to update the table view from another VC. I'm doing this using NotificationCenter like this:
In the table view VC:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(self.updateTableView), name: NSNotification.Name(rawValue: "updateTableView"), object: nil)
}
#objc func updateTableView() {
print("in func")
DispatchQueue.main.async {
self.listTV.reloadData()
}
}
In the opened VC:
func reloadTV() {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "updateTableView"), object: nil)
}
The print works, but the table view doesn't reload. I can only see it changing if I dismiss the VC with the table view and open it again.
I've followed the suggestions of other answers which is to use DispatchQueue, but that didn't make a difference. What am I missing?
Many thanks!
I would consider doing this by protocol and delegate instead of notifications...
This is how I do it.
When you call tableView.reloadData(). It has no effect if the tableView is hidden (isHidden == true). I believe the behavior is also the same when the tableView is effectively hidden by another ViewController (so effectively hidden).
Solution: A suggestion is to reload the tableView when the view is shown again. Few ways to do that.
one is in viewDidAppear (depends on how you transitioned between ViewControllers),
or
you can keep a reference to the tableView and after you dismiss the second ViewController (in which you were sending the notification) you provide the callback to reload the tableView. Roughly like the snippet, with self being the secondViewController you transitioned to. Dismiss that view
self.dismiss(animated: true, completion: {
self.tableView.reloadData()
}
or you can still use your notification and setup a flag and when the viewDidAppear, you then reloadData() inside viewDidAppear. However for this to work, you need to ensure that viewDidAppear is always called when the view is shown again (this will depend on how you transitioned between views).Simply override that method and print to verify.
There are other ways but the bottom line is tableView.reloadData() will be ignored if it is called when the tableView is not visible on the screen. My guess is it's an optimization made by Apple (no need to reload if no table is showing) or maybe a bug. I think they'll say it's a feature 😄
I suggest instead of using NotificationCenter, to instead set a Bool, tableViewNeedsUpdate, and check for the value of that Bool when the view with the UITableView is presented, and the UITableView is visible and able to accept reloadData() calls. After the reload is complete, set the variable back to false.

Variables are not updated in timer completion block

Here is the scenario:
I want to scroll(or shake) a horizontal collectionView after a page showing up so user could see it scrolling...
I do it with no problem 3 sec after page pops up but I don't want it to do the dance when user reach the collectionView before 2 sec & scrolls it itself.
So here is my solution for it:
var collectionDidScroll = false
func scrollViewDidScroll(_ scrollView: UIScrollView) {
collectionDidScroll = true
}
override func awakeFromNib() {
super.awakeFromNib()
Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(showScrollTutorial), userInfo: nil, repeats: false)
}
#objc func showScrollTutorial() {
if !collectionDidScroll {
collectionView.shakeCells()
}
}
The Problem:
The "collectionDidScroll" is update just fine in class, but in timer completion its always false!
It means "collectionDidScroll" is not updating in completion & it has its launch time value.
Notice:
My class is a subclass of UICollectionViewCell
I even tried dispatchQueue with timer & timer with completion block but the results are the same
The comments above answered your question, but to help you tackle similar problems in the future yourself:
Whenever you have problems like this, you should try littering your code (especially scrollViewDidScroll and showScrollTutorial) with print-statements to see if they get called at all and which values they contain. Or you can set breakpoints!
Problem Solved!
I placed 'showScrollTutorial()' function contents inside a 'DispatchQueue' to force it to run in main thread, now it works like a charm!
Thanks for everyone.

How to detect values from UIPickerView while is rolling?

I'm trying to read data from a UIPickerView while is rolling.
Didselectedrow is giving you back row value only when UIPicker is not moving. How can I catch values from UIPickerView while is rolling?
I need to know exactly the passing data over the center row, get them and update other objects into UIView accordingly.
I tried to call a reading function using a timer, but didselectedrow does not update himself while rolling, see code below:
// define the timer
let cycleTimer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(self.readUIPicker), userInfo: nil, repeats: true)
as timer was defined it call reading func every 0.1s
// read UIPicker
func readUIPicker() {
let selectedRow = myPicker.selectedRow(inComponent: 0)
// Do something here based on selectedRow value
print("SelectedRow = \(selectedRow)")
}
The problem is that selectedRow will update only as soon as the rolling motion is stopped. No way to have control over passing elements.
While there is no API to get the picker's value while scrolling, the picker view will be calling your data source and delegate methods to get the title or view for a given row so it can be displayed as the user scrolls the picker view. So the best you can do is make use of the fact that the picker view just asked for the title or view of some row. But that row isn't necessarily the current center row.

Force refresh on another ViewController component with swift

I'm trying to pass a trigger between 2 view controller but i can't find something that works ...
I have the main controller with a NSTableView, source linked, View Base.
main Controller class :
class ViewController: NSViewController {
I have an array defined in Global variables.
on the viewDidLoad i add 2 elements in my array, then i use setDelegate and setDataSource.
It works fine.
myLib.myCoins = fillCoinsTable()
print ("My lib has \(myLib.myCoins.count) objects ")
mainCoinTable.setDelegate(self)
mainCoinTable.setDataSource(self)
I have a segue from the WINDOWS CONTROLLER to my second view Controller.
(It's a ToolBar button). The segue is "Sheet" kind.
This second controller allows me to add an element in my global variable arrays, with a button "Save" .
Code on the second controller
#IBAction func addCoinButton(sender: AnyObject) {
//We add the coin
let newCoin:coin = coin(n: textName.stringValue)
newCoin.Year = Int.init(textYear.stringValue)
myLib.myCoins.append(newCoin)
self.dismissController(self)
}
If i add a button on the main controller, to reloadData on the TableView, it works fine. The third element is added.
but i would like that to be automatic ....
I tried segue, but mine is not between view controller but with the windows controller.
Can you please help ?
Thanks,
Nicolas
I think, you want to add data from oneViewController and without pressing button, you want after navigation or pressing back button, you want to reload automatically tableview to show updated results, right.
If I'm not wrong then, this solution will work for you.
Follow this below steps:
Step 1 :
Add this code in your view controller, from which you want to add data in array or in database, instead of button click.
override func viewDidLoad()
{
super.viewDidLoad()
let backItem = UIBarButtonItem(title: "Back", style: .Plain, target: self, action: "goBack")
self.navigationItem.leftBarButtonItem = backItem
}
func goBack()
{
NSNotificationCenter.defaultCenter().postNotificationName("load", object: nil)
self.navigationController?.popViewControllerAnimated(true)
}
Step 2:
Now its final step.
Now add this below code, to your result view controller, where you want to automatically update the result.
func loadList(notification: NSNotification){
self.TableView.reloadData()
}
override func viewWillAppear(animated: Bool) {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "loadList:",name:"load", object: nil)
}
Now implement this code-stuff in your coding. Hope it works for you.
If you want the table to reload automatically when the View appears add this to viewWillAppear
self.tableView.performSelectorOnMainThread(#selector(UITableView.reloadData), withObject: nil, waitUntilDone: true)

How to loop the CollectionViewCell

I have a set of collectionviewcell in UICollectionView and i am using function NSTimer.scheduledTimerWithTimeInterval to command each cell to show up and move to the left in every 4 second. Currently, they are not in loop and it ends up blank on the screen once the last cell shows up. How can I create the loop for these cells and make them to move continuously? Please advise.
func timeSlide() {
var timeslide = NSTimer.scheduledTimerWithTimeInterval(4, target: self, selector: Selector("onTime"), userInfo: nil, repeats: true)
}
func onTime(){
collection.contentOffset = CGPointMake(collection.contentOffset.x+375, 0)
}
You need to know how many items are there in the collection view, and when it gets to the end you need to set the contentOffset back to the beginning.