Where should I load a UISwitch's state? - ios

I am currently trying to load the UISwitch's state from NSUserDefaults in my view. These UISwitch's are in custom tableview cells that are loaded in the cellforrowatindexpath. If I put my code to load the switches states in the cellforrow method wouldn't that cause the view to lag a bit on startup since that method is getting called a few times and since I only need this code to be executed once?
Currently, I am loading it after the cellforrowatindexpath delegate method has been done doing its stuff which for me is in the viewdidload method. But the thing is, it doesn't look so nice because the switches are snapping into place while the user can see the switches which I do not want. If I put the code into the viewwillappear method, it causes the switches all to be off since they are not created yet.
So in what place should I load the switches state from NSUserDefaults so that it looks nice and is still efficient?
Thanks!

You can load the data for NSUserDefaults in the previous view (if it is there), and than just give this parameters through NSArray (f.e.), and set them after configuring the cell.

Related

Swift: UICollectionView invalidateLayout not getting triggered

I have a collection view with a datasource and a layout class. The class is linked to the collection view in the Attributes Inspector.
By tapping buttons I need to retrieve data for the collection and this can mean different numbers of section/items. Therefore I need to restructure the layout each time. However this never seems to occur.
At the moment I have the following in the Success function for the data retrieval request.
listingsView.reloadData()
listingsView.collectionViewLayout.invalidateLayout()
listingsView.collectionViewLayout.prepareLayout()
I'm not sure that the prepareLayout is needed but tried it anyway. The datasource updates fine but the prepareLayout is never triggered by any of the lines.
Do I need some special settings or a different location for the invalidateLayout request?
Thanks.
Sorry - ignore this. Had a Boolean variable on layout that wasn't getting altered due to a forced return.
Just listingsView.collectionViewLayout.invalidateLayout() works fine.

Changing my tableview data source every time the view appears. Where should I do it?

I declare an array at the beginning of my UITableViewController:
class ArchiveTableViewController: UITableViewController {
var dataSource: [[Book]]!
(…)
And then I have a function getDataSource() that updates the array from a database.
My first thought was to call it at viewWillAppear, but it seems that the table view loads before that, so it ends up not matching the array.
I could call the function from every single table view method, but that seems a little stupid. So where is the best place to do it? It must get called every time the view appears, so viewDidLoad won't work, but it must get called before the tableview methods, so viewWillAppear won't work either. It's like I need something in between. Or is there a better way to do what I want?
Thanks in advance,
Daniel
Edit: I should have added, that dataSource array is made up of other arrays, each representing a section in the table view. I get the number of sections and the number of rows in a section from the array too, so it must stay the same throughout the tableview methods or the app will crash, it might try to populate a row that shouldn't exist anymore, for instance.
Edit 4: Ah, ok, I got it! I'm sorry for wasting everyone's time looking for complicated answers. I just had to call getDataSource() from both viewDidLoad and viewWillAppear, and call tableView.reloadData() only in viewWillAppear.
I was trying all combinations of where to put things and with reloadData inside getDataSource() it would sometimes get called repeatedly forever until it crashed… or on other attempts I would call getDataSource() from viewWillAppear and not from viewDidLoad, and then it would crash the first time… anyway, I missed the most obvious combination and now I can't understand how I didn't see it before. Thank you all so much for your time.
Set it in override func loadView().
EDIT: As a general practice this is how you should go it:
Show loading overlay on screen while table data is being fetched.
Once data is available:
2.1. remove the loading overlay.
2.2. update data source model.
2.3. reload your table view so latest model could be picked.
Are you are showing other view controller and then going back to the one with tableView and that's why you want to update the tableView every time the view appears?
If so - it should just work the way you initially tried, if you put the getDataSource in viewWillAppear() and it calls tableView.reloadData() in the end (as you have it here in the source sample) then it will effectively show just what you have prepared for it (all the tableview methods will be called again after reloadData() even if they were already called before).
So I would advise debugging why it is not working when you call it from viewWillAppear(). Please add some screenshots or other data of how it is not correct with this method.
As a sidenote, if getDataSource() takes significant time, it may delay showing your view controller if you put it in viewWillAppear. In such case you'll need to do the way #Abhinav laid out for you (but you can start it from viewWillAppear).
Update: You're right, depending on how you've written numberOfSectionsInTableView() and tableView(_, numberOfRowsInSection) you may need to call getDataSource() also from viewDidLoad() or else you may crash because you're not handling empty datasets.
In that case you don't need tableView.reloadData() because table view methods will be called anyway, so as you noted, it's good to separate it from your getDataSource().
Regarding getDataSource() called repeatedly until crash - it probably happened when you added getDataSource() in one of UITableViewDataSource methods (like numberOfSectionsInTableView()) because reloadData() inside getDataSource() would trigger this method again.
Every function needs to access your var dataSource. So that's where the call to getDataSource must go: You create an optional variable that contains either dataSource or is nil, and then you give dataSource a getter which returns that optional variable unwrapped if not nil, and calls getDataSource otherwise.

iOS/Swift: in which function between viewDidLoad and viewWillAppear am I supposed to query a database?

In my app, being developed by Swift and XCode 6, I have to query a database and according to that answer then I'll modify and show some UI widgets which, in my case, are three colored buttons whose I have to change their text which consists in a number.
These buttons indicate the number of tasks assigned to an user and they have different colors according to the tasks' priority.
So, shall I query the database in viewDidLoad() function and then change the buttons' text in viewWillAppear according to the answer? Is that right?
Yes you can query in viewDidLoad and do UI modifications in viewDidAppear.
Actually it depends on your need.
If your result will change every time OR if you wanna refresh data every time your View's display then query and modify UI in viewWillAppear OR viewDidAppear as viewDidLoad will query only once at the time your View first loads.
You can query a database whenever you want.
ViewDidLoad will only get called once per instance of your view controller. It is typically used for initializing objects.
In view[Will/Did]Appear you typically update your UI to reflect the newest data you have by setting label text and image view images.
Your described approach is correct if you don't need to re-query the database every time a view appears.
yes you can query it in viewDidLoad but if you do it in viewWillAppear will be more good because viewDidLoad calls once when view loading first time and never called again until unless view will deloc but viewWillAppear call every time for example you have one view and it have navigation view inside and you navigate inside the other view so when you press back button viewDidLoad will not call but yes viewWillAppear will always call.

configure UICollectionView cell on initial lookup

I am getting cells for a UICollectionView by calling dequeueReusableCellWithReuseIdentifier:. I want to set some specific configuration information the first time my cell is returned from this method and not subsequently when it gets reused. Is there a hook somewhere where I can run "one time" code on collection view cells?
Obviously I could just set this information every time or use a boolean to keep track of whether or not the cell has been initialized, but I'd like to know if there's a cleaner way first.
This is easy enough to do from within a cell's implementation but there's no convenient way for a data source to differentiate newly created vs reused cells. If your configuration must be supplied by the data source then the data source probably need to check if the cell has been configured already.
The cells will be created once so you can use init or awakeFromNib to set some initial state. Cells will then have prepareForReuse called when being reused allowing you to perform any changes you need to make per-use.
The way I ended up solving this was to put my own view inside a generic UICollectionViewCell with a view tag. Then, when I go to deque my cell, I pull out the view using viewWithTag. If I get nil back, it's the first time this code has run, so I can init my view using my own constructor normally. This seemed slightly better than keeping track of a boolean in the cell implementation.

UITableView datasource / reload race condition

Issue:
I have a UITableView that is reloaded by a controller as soon as it receives an NSNotification. The data structure that the cellForRowAtIndexPath uses as the datasource may change while the table is refreshing.
Background:
Whenever the app's data model changes a NSNotification gets fired and my UITableViewController who handles the datasource of the UITableView gets notified to execute a "refreshReload" method. The "refreshReload" method retrieves the new data from the Model and then asks for [tableView reloadData]. This is classes MVC pattern where the model gets changed, the controller gets notified and the view gets updated. App crashes when there are quick Notifications back to back that change the data quickly. I feel that while the table is calling cellForRowAtIndexPath: the data structure that contains the data changes during the execution.
What would be a good pattern to follow to avoid this, is there a way to stop reloading of a table so that I can first perform the stop then change the datasource ?
If I understand your question correctly, I would use global flag to lock data changes.
e.g. use singleton pattern to hold your flag value. Check whether flag is locked or not. If flag is locked, do not call or disable data change methods. When UITableView is updating, lock flag until updating is finished.
The crash will be come if the data change very frequently i.e. at the time table is updating and table get another reload call.
To resolve crashes in your app:
First thing you can do is that avoid that much frequent calling of reload table. Maintain a Flag (in Notification observer method that you set for receiving notification) ,that flag tells that table need to reload now when user come to this tableview screen you create a timer that will call a method after (say) every one minute . In that method, check for flag , if it is YES then reload the table and Change Flag value to NO else there is nothing you need to do.
I hope that will resolve your problem for sure.

Resources