Activity indicator not stopping when webview has finished loading - ios

Anyone have an idea why my activity indicator is not stopping when the webview has finished loading? Web view is delegated, UIActivityIndicatorView start animating etc, is in my code... ?
This is the relevant code:
import UIKit
class ViewController: UIViewController, UIWebViewDelegate {
#IBOutlet weak var webview: UIWebView!
#IBOutlet weak var activity: UIActivityIndicatorView!
var url = "http://apple.com"
func loadURL () {
let requestURL = NSURL(string: url)
let request = NSURLRequest(URL: requestURL!)
webview.loadRequest(request)
}
override func viewDidLoad() {
super.viewDidLoad()
loadURL()
// Do any additional setup after loading the view, typically from a nib.
webview.delegate = self;
}
func webviewDidStartLoad(_ : UIWebView){
activity.startAnimating()
NSLog("The webview is starting to load")
}
func webviewDidFinishLoad(_ : UIWebView){
activity.stopAnimating()
activity.hidden=true;
NSLog("The webview is done loading")
}
Thanks!

Mind the functions names! It's webView..., camel case :)

Are you getting "The webview is done loading"?. If not, probably the request it's taking a very long time to complete it.
However, you should implement func webView(webView: UIWebView, didFailLoadWithError error: NSError?) to detect if there's any error and stop the activity.

Actually, the correct answer is a probably combination of DAN's and iGongora's, plus a possible third reason.
The immediate problem is that even in a happy path scenario (where the webview finishes successfully) is that it should be the following (pay attention to the case of the function names webViewDidStartLoad and webViewDidFinishLoad
func webViewDidStartLoad(webView: UIWebView) {
activity.startAnimating()
NSLog("The webview is starting to load")
}
func webViewDidFinishLoad(webView: UIWebView) {
activity.stopAnimating()
activity.hidden=true;
NSLog("The webview is done loading")
}
Additionally, if the UIWebView fails, you should also stop the spinner.
func webView(webView: UIWebView!, didFailLoadWithError error: NSError!) {
activity.stopAnimating()
activity.hidden=true;
print("Webview fail with error \(error)");
}
One other possible problem would be if you have not set the delegate properly. You can do it in the viewDidLoad, or in Interface Builder.
override func viewDidLoad() {
super.viewDidLoad()
...
self.webView.delegate = self;
...
}

Run this in main queue so this will stop other wise not the code for this swift 4 and swift 3 is
Dispatchqueue.main.async{
activity.stopAnimating()
}

Related

webViewDidFinishLoad() does not appear to be running in Swift

I have a view controller for a webview, setup through KINWebBrowser.
I've tried several ways to get these methods to execute:
func webViewDidStartLoad(webView: UIWebView) {
print("Strat Loading")
}
func webViewDidFinishLoad(webView: UIWebView) {
print("Finish Loading")
}
func webView(webView: UIWebView, didFailLoadWithError error: NSError?) {
print(error?.localizedDescription)
}
func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
return true
}
override func webViewDidFinishLoad(_ webView: UIWebView) {
super.webViewDidFinishLoad(webView)
print("Finish Loading 2")
}
But nothing seems to be working.
My class definition seems normal: class WebBrowserViewController: KINWebBrowserViewController, NavigationProtocol {
But no matter what I do - override func or not, no logger or print statement I put in these functions seems to be executed.
What am I doing wrong? I am trying to create an event that will listen to when all of the web content is loaded so I can stop having a loading spinner appear.
EDIT: Adding delegate information:
When I have tried to add a delegate to viewDidLoad():
webView.delegate = self
I have gotten the following error:
Ambiguous reference to member 'webView(_:decidePolicyFor:decisionHandler:)'
This is my viewDidLoad() without the delegate setting:
override func viewDidLoad() {
super.viewDidLoad()
pointsNavigationItem = addPointsButtonToNavigation()
self.showsURLInNavigationBar = false
self.showsPageTitleInNavigationBar = false;
self.tintColor = UIColor.navText
self.barTintColor = .navBackground
}
I'm not sure that KinWebBrowser does delegation the same way?
Added the KINWebBrowserDelegate to the class definition and added the following methods:
func webBrowser(_ webBrowser: KINWebBrowserViewController!, didFailToLoad URL: URL!, error: Error!) {
print("DEBUG 5")
}
func webBrowserViewControllerWillDismiss(_ viewController: KINWebBrowserViewController!) {
print("DEBUG 1")
}
func webBrowser(_ webBrowser: KINWebBrowserViewController!, didStartLoading URL: URL!) {
print("DEBUG 2")
}
func webBrowser(_ webBrowser: KINWebBrowserViewController!, didFinishLoading URL: URL!) {
print("DEBUG 3")
}
func didChangeValue<Value>(for keyPath: KeyPath<WebBrowserViewController, Value>) {
print("DEBUG 4")
}
None of the debugs are getting called in the log.
Those are the UIWebView delegate methods, however from the KINWebBrowser page you should probably be using the KINWebBrowserDelegate protocol
(void)webBrowser:(KINWebBrowserViewController *)webBrowser didStartLoadingURL:(NSURL *)URL;
(void)webBrowser:(KINWebBrowserViewController *)webBrowser didFinishLoadingURL:(NSURL *)URL;
(void)webBrowser:(KINWebBrowserViewController *)webBrowser didFailToLoadURL:(NSURL *)URL withError:(NSError *)error;

Retrieve WebVie URL Swift || Cannot assign value of type 'ViewController' to type 'UIWebViewDelegate?'

I would like to load a web page then be able to retrieve the current web page after the user has logged in and been redirected. I have achieved the loading of a webpage but am unable to retrieve the URL after the user has moved to a new page. The current code that I have is:
#IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
needlogin()
}
func needlogin(){
let url = URL(string: "https://www.instagram.com/oauth/authorize/?client_id="+clientid+"&redirect_uri="+redirecturl+"&response_type=token&scope=likes+comments+public_content+follower_list+relationships")
let urlrequest = URLRequest(url: url!)
webView.loadRequest(urlrequest)
self.webView.delegate = self
}
func webViewDidFinishLoad(_ webView: UIWebView){
}
The problem I have is with self.webView.delegate = self . I get the error message :
Cannot assign value of type 'ViewController' to type
'UIWebViewDelegate?'
Furthermore I have no clue how to retrieve the URL at all and would appreciate your help.
You would need to conform to UIWebviewDelegate protocol. So you would need to do something like
class ViewController: UIViewController, UIWebViewDelegate {
}
at the top of your class definition.
To retrieve the URL after the webview has finished loading, within your webViewDidFinishLoad method, you would need to do something like webView.request.URL.
Disclaimer: You should be using WKWebview rather than UIWebview for iOS + applications. The way to do it would be something like this for your example:
import UIKit
import WebKit
class WebviewController: UIViewController, WKNavigationDelegate {
var wkWebview : WKWebView?
override func viewDidLoad() {
super.viewDidLoad()
needsLogin()
}
func needsLogin() {
wkWebview = WKWebView.init(frame: self.view.bounds)
wkWebview?.navigationDelegate = self
self.view.addSubview(wkWebview!)
let url = URL(string: "https://www.instagram.com/oauth/authorize/? client_id="+clientid+"&redirect_uri="+redirecturl+"&response_type=token&scope=likes+comments+public_content+follower_list+relationships")
let urlRequest: URLRequest = URLRequest.init(url: url!)
wkWebview?.load(urlRequest)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
public func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
print("\(error.localizedDescription)")
}
public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
// This is the URL you need.
let url = webView.url
}
}

iOS Swift : can't Retrieve current url loaded in UIwebView

i am working in webview application iOS swift :
problem i am facing is i want to get each url which webview displays :
upon urls i have to perform some if else checks . but i could not get the urls which webview loads.
webview is displaying fine results and loading urls upon clicking . i want to fetch all urls which webview navigates on..
import Foundation
import UIKit
class seconVC: UIViewController {
var toPass:String!
var touser:String!
var toPassing:String!
#IBOutlet weak var webV: UIWebView!
#IBOutlet weak var L_back: UIBarButtonItem!
#IBOutlet weak var R_frwrd: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var domurl = toPass;
var username = touser;
var passwing = toPassing;
var sendurl = stringA+username+"/"+passwing;
//exchange login with auth/username/password
println(sendurl);
let url = NSURL (string: sendurl);
let requestObj = NSURLRequest(URL: url!);
webV.userInteractionEnabled = true
webV.loadRequest(requestObj);
}
#IBAction func L_back(sender: UIBarButtonItem) {
if (webV.canGoBack){
webV.goBack()
}
}
#IBAction func R_frwrd(sender: UIBarButtonItem) {
if (webV.canGoForward){
webV.goForward()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
all i want is to get string of current url and navigation buttons for webview :please help ? i referred all the internet no solution is working in my case .
There are couple of UIWebViewDelegate such as shouldStartLoadWithRequest or webViewDidStartLoad or webViewDidFinishLoad or didFailLoadWithError that help you to accomplish your goal. If you want to perform operation after view did finished then implement this delegate method
Swift 3
if let currentURL = webView.request?.url?.absoluteString{
print(currentURL)
}
as it mentioned here.
option-1
let currentURL = webV.request.URL.absoluteString
option-2
get URL in delegate method
func webViewDidFinishLoad(webView: UIWebView){
print(WebView.request?.mainDocumentURL)
}
option-3
func webViewDidFinishLoad(webView: UIWebView) {
let currentURL = webView.request().URL()
print("\(currentURL.description)")
}
or use like
func webViewDidFinishLoad(webView: UIWebView){
let currentURL = webView.request?.URL
}
option-4
func webViewDidFinishLoad(webView: UIWebView) {
let currentURL: = webView.stringByEvaluatingJavaScriptFromString("window.location.href")!
print("\(currentURL)")
}
option-5
func webView(webview: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
let currentURL = request.URL.absoluteString
print("\(currentURL)")
}
option-6
func webViewDidFinishLoad(WebVie: UIWebView) {
let currentURL = WebVie.request.mainDocumentURL
print("\(currentURL)")
}
First you have to define the delegate for WebView class. "WebView.delegate = self". Add this code beside one of the function above:
override func viewDidLoad() {
super.viewDidLoad()
myWebView.delegate = self }
and for exmaple:
func webViewDidFinishLoad(_ webView: UIWebView) {
if let currentURL = WebView.request?.url?.absoluteString{
print(currentURL)
}
}

Add A Callback To A Prebuilt Asynchronous Function Swift iOS

I'm messing around with pdfs at the moment. I'm attempting to load a PDF into the system and write out the same PDF to gain an understandings of the the whole procedure.
The problem I've got it is that I'm having to load the pdf from the web and because the WebViewUI.loadRequest is asynchronous, it isn't completed in time.
override func viewDidLoad() {
super.viewDidLoad()
let filePath = getDocumentsDirectory().stringByAppendingPathComponent("output.pdf")
let url : NSURL! = NSURL(string: "http://www.nhs.uk/NHSEngland/Healthcosts/Documents/2014/HC5(T)%20June%202014.pdf")
loadTemplate(url, completion: {(webView: UIWebView) -> Void in
print("callback started")
let pdf = self.toPDF(webView)
do {
pdf!.writeToFile(filePath, atomically: true)
} catch {
// failed to write file – bad permissions, bad filename, missing permissions, or more likely it can't be converted to the encoding
}
print("callback started")
})
print("Finished viewDidLoad")
}
func loadTemplate(url: NSURL, completion: (webView: UIWebView) -> Void) {
print("Start loadTemplate")
// do some crunching to create the SketchAnimation instance...
let webView = UIWebView(frame: CGRectMake(20, 100, 300, 40))
webView.loadRequest(NSURLRequest(URL: url))
self.view.addSubview(webView)
// invoke the completion callback
completion(webView: webView)
print("finished loadTemplate")
}
How do I add a callback to the loadRequest instead of loadTemplate?
You don't, exactly. You'd set up your view controller to be the web view's delegate and implement the webViewDidFinishLoad method. In that method you'd check to make sure the load that finished is the one you were after, and if so, then you'd invoked the code you want to run when the load is complete.
Here is a basic example of how to set that up:
//
// ViewController.swift
//
import UIKit
class ViewController: UIViewController, UIWebViewDelegate {
#IBOutlet var webView: UIWebView!
var url = NSURL(string: "http://google.com")
override func viewDidLoad() {
super.viewDidLoad()
//load initial URL
let req = NSURLRequest(URL : url!)
webView.delegate = self
webView.loadRequest(req)
}
func webViewDidStartLoad(webView : UIWebView) {
print("AA")
}
func webViewDidFinishLoad(webView : UIWebView) {
print("BB")
}
}

How to check if WkWebView finish loading in Objective-C?

I want to load HTML pages using WkWebView and I want to show the page just after it's finished loading. As long as it's loading I would like to show an activity indicator on an empty View.
I create two view a loadingView and a wkWebView. While the page is loading I add to VC as subview the loadingView and after I want to remove loadingView and add wkWebView. Here is my code:
[self addSubview:_loadingView];
_wkWebView = [[WKWebView alloc] initWithFrame:self.frame];
_wkWebView.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, self.frame.size.height);
//Send a request to wkUrlconnection
NSURL *wkUrl = [NSURL URLWithString:self.wkUrlString];
NSURLRequest *wkRequest = [NSURLRequest requestWithURL:wkUrl];
//Here I want to check if it's loaded and then remove loadingView and add wkWebView
[_wkWebView loadRequest:wkRequest];
[self.loadingView removeFromSuperview];
[self addSubview:_wkWebView];
Can someone show me how to check while it's loading and if finish refresh the VC? Thank you for your answers.
I think the WKNavigationDelegate's webView:didFinishNavigation: delegate callback is what you're looking for.
Configure and present your activity indicator when you start to load and then stop and remove it from view when the callback is called.
For anyone who is experiencing the issue of a webpage containing multiple frames and therefore doing multiple loads which interrups your load animation, I have implemented the following and it works for me in all the situations I have come across so far:
Swift:
var loadCount: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
startLoading()
webview.navigationDelegate = self
let request = URLRequest(url: url)
webview.load(request)
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
loadCount += 1
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
loadCount -= 1
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
if self?.loadCount == 0 {
self?.stopLoading()
}
}
}
The basic idea is to start your load animation before you request the url, then count each request being made and only stop the load animation when your request count == 0. This is done after a slight delay as I find that some frames queue up requests synchronously so the next load will begin before the 0.1 second delay has completed.
( ͡° ͜ʖ ͡°)
for swift 4.2:
func webView(_ webView: WKWebView,
didFinish navigation: WKNavigation!){
print("loaded")
}
be sure to set delegate for webView in didLoad (or similar)
webView.navigationDelegate = self
class WebViewVC: UIViewController {
// MARK: IBOutlets
#IBOutlet weak var webView: WKWebView!
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
// MARK: Life cycle
override func viewDidLoad() {
super.viewDidLoad()
webView.navigationDelegate = self
loadWebsite()
}
}
// MARK: WKWebView
extension WebViewVC: WKNavigationDelegate {
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
activityIndicator.startAnimating()
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
activityIndicator.stopAnimating()
}
}
// MARK: Private methods
extension WebViewVC {
private func loadWebsite() {
guard let url = URL(string: "google.com") else { return }
let urlRequest = URLRequest(url: url)
webView.load(urlRequest)
}
}

Resources