MBProgressHUD with Swift, Fabric & TwitterKit - ios

I'm using Fabric and TwitterKit to show a timeline at my Table View. At my code I'm using a dispatch_async function. I want to start the MBProgressHUD and after the timeline was loaded I want to disable the HUD. Unfortunately my HUD is appearing only for less than one second and the timeline is appearing about two seconds later. No matter how good or bad my internet connection is. I want to show the HUD as long as the timeline is loading.
This is my code:
override func viewDidLoad() {
super.viewDidLoad()
let ProgressHUD = MBProgressHUD.showHUDAddedTo(self.view, animated: true)
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None
let client = TWTRAPIClient()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)) {
self.dataSource = TWTRUserTimelineDataSource(screenName: "fabric", APIClient: client)
self.showTweetActions = true
//Dark Timeline Theme
TWTRTweetView.appearance().theme = .Dark
TWTRTweetView.appearance().linkTextColor = UIColor.redColor()
dispatch_async(dispatch_get_main_queue()) {
ProgressHUD.hide(true)
}
}
}

I've done the same as:
MBProgressHUD.showHUDAddedTo(self.view, animated: true) //for showing
MBProgressHUD.hideHUDForView(self.view, animated: true) //for hiding
No need of that ProgressHud variable.

Well, i changed the framework to JGProgressHUD. It's working perfectly. No more problem here! Thank you for your help –

Related

Slimming fat viewcontroller - Barcode scanner not working anymore

I have a button on my app that opens upp a barcode scanner, I can then scan an item and it prints the barcode etc.
My Viewcontroller was getting very full of codes, and i just wanted to create another class to seperate and make my code easier to read. So i put all of the barcodescanner code in the class "Partnyallen" and kept my button in class "NewViewController". I can open the barcode, but as soon as i scan an item or even if i press the "cancel" button inside, it just freezes. What could the problem be?
Thankful for any help!
import AVFoundation
import QRCodeReader
import Alamofire
class Partynallen: UIViewController, QRCodeReaderViewControllerDelegate {
lazy var readerVC: QRCodeReaderViewController = {
let builder = QRCodeReaderViewControllerBuilder {
//change object to scan and the initial position of the camera
$0.reader = QRCodeReader(metadataObjectTypes: [.qr, .ean13], captureDevicePosition: .back)
// Configure the view controller (optional)
$0.showTorchButton = true
$0.showSwitchCameraButton = false
$0.showCancelButton = true
$0.showOverlayView = true //shows the square area of the QRCode Scanner
$0.rectOfInterest = CGRect(x: 0, y: 0, width: 1, height: 1)
}
return QRCodeReaderViewController(builder: builder)
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
readerVC.delegate = self
}
func reader(_ reader: QRCodeReaderViewController, didScanResult result: QRCodeReaderResult) {
//code to be added
reader.stopScanning()
//print(result)
//print(result.value)
//barcode = result.value
//Apifetch(code: "URL")
dismiss(animated: true, completion: nil)
}
func readerDidCancel(_ reader: QRCodeReaderViewController) {
//code to be added
reader.stopScanning()
dismiss(animated: true, completion: nil)
}
}
class NewViewController: UIViewController {
var partynallen: Partynallen?
override func viewDidLoad() {
super.viewDidLoad()
partynallen = Partynallen() // DONT KNOW IF THIS IS CORRECT?
}
#IBAction func scan(_ sender: UIButton) {
partynallen.readerVC.modalPresentationStyle = .formSheet
present(partynallen.readerVC, animated: true)
}
}
You got 3 ViewControllers NewViewController, QRCodeReaderViewController and Partynallen. But actually you never present Partynallen and just use it as a delegate for the scanner, instead you only present the readerVC. So, when readerDidCancel(:) is called, you try to dismiss Partynallen, which isn’t presented.
Using a ViewController that only acts as the scanner-delegate seems to be a bit too much. You could maybe remove the UIViewController base-class (if it isn‘t required by the scanner-delegate-protocol). And because the delegate-functions, e.g readerDidCancel(:), provide the scanner-vc, you could just use that vc to dismiss itself.

PencilKit toolPicker is not showing up

I am trying to create an app using PencilKit. I have the following code in one of my ViewControllers.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
guard
let window = view.window,
let toolPicker = PKToolPicker.shared(for: window) else { return }
toolPicker.setVisible(true, forFirstResponder: canvasView)
toolPicker.addObserver(canvasView)
canvasView.becomeFirstResponder()
}
Although I am calling the setVisible function and making the canvasView the firstResponder, my toolPicker is not showing up, and printing toolPicker.isVisible is false.
Move your code to viewWillAppear(), this did it for me.
Apple is also doing it. I recommend to download and play with the Sample Code provided by Apple.

Keyboard is appearing and immediately disappearing when UISearchBar.becomeFirstResponder() is getting called

I have UISearchController in the navigationItem.searchController and I want to make it focus when the user selects "Search" from the menu.
So shortly, when the user is tapping on the "Search" option in the menu (UITableViewCell) it's getting the view controller that have the searchController in it and calling:
guard let navigationVC = presentingViewController as? UINavigationController else { return }
guard let documentsVC = navigationVC.topViewController as? DocumentsViewController else { return }
documentsVC.searchController.searchBar.becomeFirstResponder()
Then, the UISearchBar is getting focus, the keyboard is appearing and then it's immediately disappearing, and I don't have any code that would make it disappear (like view.endEditing()).
1 GIF is worth more than 1,000 words:
So, after many tries I got some way to make it work, but I'm sure there is a much more elegant ways to do this, so if someone think that they have better way, please post it here and I may use it and mark your answer as the correct one.
Create the function focusOnSearchBar() in YourViewController:
func focusOnSearchBar() {
let searchBar = searchController.searchBar
if searchBar.canBecomeFirstResponder {
DispatchQueue.main.async {
searchBar.becomeFirstResponder()
}
} else {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.focusOnSearchBar()
}
}
}
What it actually do is use itself recursively and check (every 0.1 sec) if searchBar.canBecomeFirstResponder. This is the problematic/not elegant thing.
Then, add this to viewDidAppear():
if focusOnSearch {
searchController.isActive = true
}
Don't forget to add extension to your ViewController for UISearchControllerDelegate (and of course, set searchController.delegate = self) and implement didPresentSearchController (that will be invoke by setting searchController.isActive = true):
extension YourViewController: UISearchControllerDelegate {
func didPresentSearchController(_ searchController: UISearchController) {
if focusOnSearch {
focusOnSearchBar()
}
}
}
Now all you have to do is to set focusOnSearch = true in the prepare(for segue:sender:).
*Note: if you want to focusOnSearchBar while you are in the same viewController of the searchBar, just set:
focusOnSearch = true
searchController.isActive = true
And it will work by itself.
Make your searchbar first responder in the viewDidLoad method. That will make sure everything is ready before focusing the search bar.

UIActivityIndicatorView not disappearing when back page in Swift

My activity indicator seems not disappear after I go back page. For the first time, it's disappear. Then I go to second view controller then go back to the first view controller. The activity indicator supposedly not to showing up since all UIViews already appeared.
My code
var activityView : UIActivityIndicatorView = UIActivityIndicatorView(frame: CGRectMake(0,0, 50, 50)) as UIActivityIndicatorView
override func viewDidLoad() {
super.viewDidLoad()
Alamofire.request(.POST , "192.168.0.1/test", parameters: [])
.responseJSON { response in
if response.result.isSuccess {
var jsonObj = JSON(response.result.value!)
print(jsonObj)
self.activityView.stopAnimating()
}
}
}
override func viewDidAppear(animated: Bool) {
activityView.center = self.view.center
activityView.hidesWhenStopped = true
activityView.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray
view.addSubview(activityView)
activityView.startAnimating()
}
You are showing your activityIndicator in viewDidAppear. That is why it appears when you go back from second to first. Also have a look at view life cycle. viewDidLoad is only called once whenever view controller is initialized, but viewDidAppear will be called when ever the view controller is presented. (either back navigation or presented again)
So its better to add views in viewDidLoad and activity indicator should always be associated with its network call. Before starting the call show the activity indicator and hide or remove once its done.
Also, you have missed super calls. Be sure to always call super methods when overriding.
Ex:
override func viewDidLoad() {
super.viewDidLoad()
addActivityIndicator()
fetchRemoteData()
}
func addActivityIndicator() {
activityView.center = self.view.center
activityView.hidesWhenStopped = true
activityView.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray
view.addSubview(activityView)
}
func fetchRemoteData() {
activityView.startAnimating()
Alamofire.request(.POST , "192.168.0.1/test", parameters: [])
.responseJSON { response in
if response.result.isSuccess {
var jsonObj = JSON(response.result.value!)
print(jsonObj)
self.activityView.stopAnimating()
}
}
}
U want to hide and show your activity indicator when you want. And also make sure to set as bringSubviewToFront

UIRefreshControl not refreshing when triggered programmatically

I am trying to show a refresh control right when the view loads to show that I am getting getting data from Parse. The refresh control works as it should when the app is running, but I cannot get it to fire programmatically from anywhere in my app.
This is the code that does not appear to run:
override func viewDidAppear(animated: Bool) {
self.refresher.beginRefreshing()
}
Not only does this not run, but having the code in the app changes the attributes of the refresh control. When I have this code in the app, and show the refresher from user interaction, the refresh control does not have its attributed title as it usually does nor does it run the code that it should.
I needed to add a delay between setContentOffset and the self.refreshControl?.sendActions(for: .valueChanged) call. Without the delay, the refreshControl's attributedTitle would not render.
This works in iOS 10 (Swift 3):
self.tableView.setContentOffset(CGPoint(x:0, y:self.tableView.contentOffset.y - (self.refreshControl!.frame.size.height)), animated: true)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2, execute: {
self.refreshControl?.sendActions(for: .valueChanged)
})
Here's an extension working on 10.3:
extension UIRefreshControl {
func refreshManually() {
if let scrollView = superview as? UIScrollView {
scrollView.setContentOffset(CGPoint(x: 0, y: scrollView.contentOffset.y - frame.height), animated: false)
}
beginRefreshing()
sendActions(for: .valueChanged)
}
}

Resources