swift alamofire show viewcontroller after remote data has loaded - ios

I wonder how I can show a VC after the remote data has loaded. I am not using a tableView but a normal VC.
My code look like this:
viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
loadItemData(id)
}
func loadItemData(aId: Int) {
Service.getItem(aId) { (JSON) -> () in
self.iData = JSON
self.configureData(self.iData)
}
}
func configureData(iData: JSON) {
if let type = iData["item_type"].int {
if let == 1 {
someButton.hidden = true
}
}
if let title = iData["item_title"].string {
titleLabel.text = title
}
}
What happens is that my VC first loads with the button visible and with my text label containing "dummy text" from storyboard, then when the data has loaded the button will hide and the text label will change.
So my question now is how I can hide my VC or show some loading indicator until the data has loaded.
Also worth saying this is the 2nd view. My apps start with a tableView and when you click on a cell you end up in this VC. So I could also load the data when the cell gets clicked then pass it to this VC.

Using the activity indicator is better, here's how to do it
First make sure you add Activity Indicator in your VC
override func viewDidLoad() {
super.viewDidLoad()
self.myActivityIndicator.startAnimating()
loadItemData(id)
}
func loadItemData(aId: Int) {
Service.getItem(aId) { (JSON) -> () in
self.iData = JSON
self.configureData(self.iData)
self.myActivityIndicator.stopAnimating()
}
}
Rather than try to hide the VC (try to load the data and pass it), it will makes the apps feel not responsive, because you have to wait the data loaded and then the VC will show.

Related

What is the correct way to reload a tableView from inside a nib?

I have a tableview which shows a custom cell.
Inside the cell is a button.
Once the button is clicked, a network call is made and the tableview should reload.
I tried this, but I get Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value at vc.reloadData().
#IBAction func acceptRequestPressed(_ sender: UIButton) {
DatabaseManager.shared.AnswerFriendRequest(emailFriend: friendNameLabel.text!, answer: true) { success in
if success {
let vc = FriendRequestViewController()
vc.reloadData()
}else {
print ("error at answer")
}
}
}
The problem is this line:
let vc = FriendRequestViewController()
After that, vc is the wrong view controller — it is just some view controller living off emptily in thoughtspace, whereas the view controller you want is the already existing view controller that's already in the view controller hierarchy (the "interface").
Few pointers:
You can have a closure upon the data call completion in your class that has the table view.
Eg:
// Custom Table Cell Class
class CustomCellClass: UITableViewCell {
let button = UIButton()
// All other UI set up
// Create a closure that your tableView class can use to set the logic for reloading the tableView
public let buttonCompletion: () -> ()
#IBAction func acceptRequestPressed(_ sender: UIButton) {
DatabaseManager.shared.AnswerFriendRequest(emailFriend: friendNameLabel.text!, answer: true) { [weak self] success in
if success {
// Whatever logic is provided in cellForRow will be executed here. That is, tableView.reloadData()
self?.buttonCompletion()
}else {
print ("error at answer")
}
}
}
}
// Class that has tableView:
class SomeViewController: UIViewController {
private let tableView = UITableView()
.
.
// All other set up, delegate, data source
func cellForRow(..) {
let cell = tableView.dequeueTableViewCell(for: "Cell") as! CustomCellClass
cell.buttonCompletion = {[weak self] in
tableView.reloadData()
}
}

How to show FullScreenSlideshowViewController on ViewDidLoad

I am new to iOS development, I have created android app where app gets sets of images (sometimes over 100 images) from urls and loads into imageView with zoomEnabled Inside ViewPager.
Now I want to create same app for iOS, I have found this lib ImageSliderShow. Problem with this is it shows fullscreen ONLY when user did tap on selected image. I have been struggling to presentFullScreenController on viewDidLoad with no lock.
I only want image to be shown in fullScreen, example:
Select Category A From CategoryVC -> Loads ImageSlideVC, gets set of images from server, show in FullScreenView.
How can i achieve this? Adding this:
slideshow.presentFullScreenController(from: self)
on viewDidLoad didn't work:
#IBOutlet var slideshow: ImageSlideshow!
let kingfisherSource = [KingfisherSource(urlString: "https://images.unsplash.com/photo-1447746249824-4be4e1b76d66?w=1080")!,
KingfisherSource(urlString: "https://images.unsplash.com/photo-1447746249824-4be4e1b76d66?w=1080")!,
KingfisherSource(urlString: "https://images.unsplash.com/photo-1463595373836-6e0b0a8ee322?w=1080")!]
override func viewDidLoad() {
super.viewDidLoad()
slideshow.setImageInputs(kingfisherSource)
slideshow.presentFullScreenController(from: self)
}
I dont get any error, output is same as before (shows slideshow in smallview with no zoom)
Please help
EDIT
by doing in viewDidAppear, after split second view is loaded its loads into fullscreen. First its smallview then shows in fullscreen. I think i have to do something inside setImageInputs
this is what its looks like :
open func setImageInputs(_ inputs: [InputSource]) {
self.images = inputs
self.pageControl.numberOfPages = inputs.count
// in circular mode we add dummy first and last image to enable smooth scrolling
if circular && images.count > 1 {
var scImages = [InputSource]()
if let last = images.last {
scImages.append(last)
}
scImages += images
if let first = images.first {
scImages.append(first)
}
self.scrollViewImages = scImages
} else {
self.scrollViewImages = images
}
reloadScrollView()
layoutScrollView()
layoutPageControl()
setTimerIfNeeded()
}
try to do it in viewDidAppear
#IBOutlet var slideshow: ImageSlideshow!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
slideshow.setImageInputs(kingfisherSource)
slideshow.presentFullScreenController(from: self)
}
Presenting viewController in ViewDidLoad is a bad practice.

UISegmentedControl reload certain page

I'm using a third party library for my UISegmentedControl. The pages are initialised as following:
func carbonTabSwipeNavigation(carbonTabSwipeNavigation: CarbonTabSwipeNavigation, viewControllerAtIndex index: UInt) -> UIViewController {
switch index {
case 0:
return self.storyboard!.instantiateViewControllerWithIdentifier("FolderOverviewController") as! FolderOverviewController
case 1:
return self.storyboard!.instantiateViewControllerWithIdentifier("TopFoldersTab") as! TopFoldersTab
case 2:
return self.storyboard!.instantiateViewControllerWithIdentifier("CategoriesFolderTab") as! CategoriesFolderTab
default:
return self.storyboard!.instantiateViewControllerWithIdentifier("CategoriesFolderTab") as! CategoriesFolderTab
}
}
When I press the third segment, the user can go further down to see more details (via subviews on the same page). I would like the page to reload, every time I select the third segment again. (go back to the original CategoriesFolderTab page) . Currently I'm doing this with a ViewDidLoad(), but this is slowing down the app when you do it multiple times.
Is there a more correct way to do this? Thanks in advance
I think that calling viewDidLoad() is not the right approach for achieving this, instead, implement a new function that should contains code responsible for loading data in the UI components, for example:
override func viewDidLoad() {
super.viewDidLoad()
reloadUI()
}
func reloadUI() {
// filling UI components with desired data, such as:
// myLabel.text = "Hello World"
}
And somewhere in your code (where you want to reload), instead of calling viewDidLoad(), you should call reloadUI() method.
Hope this helped.
try this
Let folderOverVC = self.storyboard!.instantiateViewControllerWithIdentifier("FolderOverviewController") as! FolderOverviewController
Let topFoldersTab = self.storyboard!.instantiateViewControllerWithIdentifier("TopFoldersTab") as! TopFoldersTab
Let categoriesFolderTab = self.storyboard!.instantiateViewControllerWithIdentifier("CategoriesFolderTab") as! CategoriesFolderTab
func carbonTabSwipeNavigation(carbonTabSwipeNavigation: CarbonTabSwipeNavigation, viewControllerAtIndex index: UInt) -> UIViewController {
switch index {
case 0:
return folderOverVC
case 1:
return topFoldersTab
case 2:
return categoriesFolderTab
default:
return categoriesFolderTab
}
}
this initializes the view controllers once, so their respective viewDidLoad methods get called once initialized, not every time you tap a tab item

UITableView header view covering first cell

I'm trying to wrap my head around what could be causing an error I'm seeing. Here's how the general flow looks: when we first hit this feature, we set our tableHeaderView to a custom segmentedcontrol view, then make a service call to fetch some data, when that is complete, we reload the table. This data is all cached, so when the user leaves and comes back, no service call is made, is simply returns back the cached data. However, when coming back, it doesn't seem to recognize that a header view is on the table, and instead places the tableView at the same origin as its header view, so the first cell is covered by the headerView. Here's some relevant methods:
override func viewDidLoad() {
super.viewDidLoad()
self.useAdaptableFeedbackFooter = true
self.tableView.registerReusableCell(DCManagePaymentsTransactionCell.self)
self.tableView.tableHeaderView = self.segmentedControlView
self.segmentedControlView.selectedSegmentIndex = self.selectedSegment.rawValue
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// TODO: Remove once we have other segments implemented
makeServiceCall()
}
private lazy var segmentedControlView: DMSegmentedControlTableHeaderView = {
let view = DMSegmentedControlTableHeaderView.loadableViewFromNib()
let segmentTitles = [DCManagePaymentsString.Summary.localized, DCManagePaymentsString.History.localized, DCManagePaymentsString.Pending.localized]
view.segmentTitles = segmentTitles
view.delegate = self
return view
}()
private func makeServiceCall() {
self.businessService.getData {
(result: DMServiceResult<DCPendingPayments>) -> Void in
switch result {
case .Success (let data):
if data.isHAMode {
self.data.payment = data.pendingPayments.first
self.tableView.dataSource = self.HADataSource
self.tableView.delegate = self.HADataSource
} else {
self.data.pendingPayments = data.pendingPayments
self.tableView.dataSource = self.dataSource
self.tableView.delegate = self.dataSource
}
self.tableView.reloadData()
case .Failure(let errorInfo):
self.navigationController?.handleError(errorInfo, withCompletion: nil)
}
}
}
The only difference I can see is how quickly we eventually call reloadData(). When I set an explicit reloadData() call in viewDidAppear it sets the tableView up correctly, but there's a jerky animation to that.
It seems that I may be setting my table up too fast for it to recognize that there's a header view? Although it doesn't make sense that that's what's causing this. Any ideas or suggestions? I can post more code if necessary.
Edit: I've added two screenshots, first is what the header looks like on first load, second is after you return and it just gets cached data (the Pending Payments is my first cell, and it gets completely covered by the header segmented control in the cached data load):

how to wait until firstResponder of text label is false in swift

I'm new to swift. My app uses photos people upload to the web and showing the photos in a table view.
It is reloading whenever some user uploads a new photo.
I have a UITextField that when you press it the keyboard goes up. My problem is that it goes down whenever reloadView is happening (when a new photo arrives)
What i'm trying to do is to check if the UITextField is first recogniser and if so I want to wait with the reload until it not first recogniser.
func refreshView()
{
dispatch_async(dispatch_get_main_queue()) { () -> Void in
while (self.dataSource.writeSomethingTextLabel.isFirstResponder()) {
//need to wait somehow for notification that it is not first responder anymore
}
self.tableView.reloadData()
}
}
So with this code the keyboard is not going down of course but the wile loop runs and everything is stuck. my question is how can I wait until the user finishes using the text label (first responder is false).
thanks
You can conditionally reload tableView on two places: when new data arrives and when textField ends editing:
#class YourViewController: UIViewController, UITextFieldDelegate {
var needsToReloadTableView = false;
func reloadTableViewIfNeeded() {
if needsToReloadTableView {
self.tableView.reloadData()
needsToReloadTableView = false
}
}
func gotNewData() {
needsToReloadTableView = true
if !self.textField.isFirstResponder {
reloadTableViewIfNeeded()
}
}
func textFieldDidEndEditing(textField:UITextField) {
reloadTableViewIfNeeded()
}
}
#IBAction func viewTapped(sender : AnyObject) {
totalTextField.resignFirstResponder()
}

Resources