1

I'm practicing Webkit in swift. I'm following this tutorial for the same purpose. And I'm stuck with an error in the very first few lines of the code.

This is what I have in the ViewController.swift so far :

import UIKit
import WebKit

class ViewController: UIViewController {

var webView : WKWebView

required init(coder aDecoder: NSCoder) {
    self.webView = WKWebView(frame: CGRectZero)
    super.init(coder: aDecoder)!
}

override func viewDidLoad() {
    super.viewDidLoad()

    self.view.addSubview(webView)
    webView.translatesAutoresizingMaskIntoConstraints = false
    let height = NSLayoutConstraint(item: webView, attribute: .Height, relatedBy: .Equal, toItem: view, attribute: .Height, multiplier: 1, constant: 0)
    let width = NSLayoutConstraint(item: webView, attribute: .Width, relatedBy: .Equal, toItem: view, attribute: .Width, multiplier: 1, constant: 0)
    webView.addConstraints([height,width])

    let url = NSURL(string: "http://www.google.com")
    let urlRequest = NSURLRequest(URL: url!)
    webView.loadRequest(urlRequest)

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}


}

and the following is how the console error output looks:

2016-10-27 11:29:09.015 Browser[68308:1113663] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '***
+[NSLayoutConstraint constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:]: Constraint items must each be an instance of UIView, or NSLayoutGuide.'
*** First throw call stack: (   0   CoreFoundation                      0x00000001060e0d85 __exceptionPreprocess + 165  1   libobjc.A.dylib    0x0000000108486deb objc_exception_throw + 48     2   CoreFoundation       0x00000001060e0cbd +[NSException raise:format:] + 205  3   Foundation  0x00000001064af0ac +[NSLayoutConstraint constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:]
+ 277   4   Browser                             0x0000000105ef890b _TTOFCSo18NSLayoutConstraintCfT4itemPs9AnyObject_9attributeOSC17NSLayoutAttribute9relatedByOSC16NSLayoutRelation6toItemGSqPS0___9attributeS1_10multiplierV12CoreGraphics7CGFloat8constantS4__S_
+ 123   5   Browser                             0x0000000105ef78ee _TFC7Browser14ViewController11viewDidLoadfT_T_ + 494     6   Browser                             0x0000000105ef7c12 _TToFC7Browser14ViewController11viewDidLoadfT_T_ + 34    7   UIKit                               0x0000000106aa5984
-[UIViewController loadViewIfRequired] + 1198   8   UIKit                               0x0000000106aa5cd3 -[UIViewController view] + 27    9   UIKit            0x000000010697bfb4 -[UIWindow addRootViewControllerViewIfPossible] + 61    10  UIKit                               0x000000010697c69d
-[UIWindow _setHidden:forced:] + 282    11  UIKit                               0x000000010698e180 -[UIWindow makeKeyAndVisible] + 42   12  UIKit       0x0000000106902ed9 -[UIApplication
_callInitializationDelegatesForMainScene:transitionContext:] + 4131     13  UIKit                               0x0000000106909568
-[UIApplication _runWithMainScene:transitionContext:completion:] + 1769     14  UIKit                               0x0000000106906714
-[UIApplication workspaceDidEndTransaction:] + 188  15  FrontBoardServices                  0x000000010a3558c8
__FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 24   16  FrontBoardServices                  0x000000010a355741
-[FBSSerialQueue _performNext] + 178    17  FrontBoardServices                  0x000000010a355aca -[FBSSerialQueue _performNextFromRunLoopSource] + 45     18  CoreFoundation                      0x0000000106006301
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17     19  CoreFoundation                      0x0000000105ffc22c
__CFRunLoopDoSources0 + 556     20  CoreFoundation                      0x0000000105ffb6e3 __CFRunLoopRun + 867     21  CoreFoundation            0x0000000105ffb0f8 CFRunLoopRunSpecific + 488     22  UIKit               0x0000000106905f21 -[UIApplication _run] + 402  23  UIKit              0x000000010690af09 UIApplicationMain + 171   24  Browser                0x0000000105ef92f2 main + 114    25  libdyld.dylib                       0x0000000108f5d92d start + 1 ) libc++abi.dylib: terminating with uncaught exception of type NSException

I'm a beginner so needless to say, I don't have any idea what this means. Additionally I'm getting the error message Thread 1: signal SIGABRT which I normally get if I ignore to remove an outlet reference that I created earlier. In this case I have not created any outlets.

I've gone through some other answers on Stack on similar problems in Objective C but I couldn't understand it well.

I know the solution might be relatively simple but any help will be appreciated.

Ajil O.
  • 6,562
  • 5
  • 40
  • 72

2 Answers2

1

Every view needs 4 constraints such that the system can calculate: x,y, width, height (labels and imageViews already have intrinsic dimensions but you can still constrain them if you want). Here are 4 constraints for the webview:

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(webView)
        webView.translatesAutoresizingMaskIntoConstraints = false
        let attributes: [NSLayoutAttribute] = [.centerX, .centerY, .width, .height]
        NSLayoutConstraint.activate(attributes.map {NSLayoutConstraint(item: webView, attribute: $0, relatedBy: .equal, toItem: webView.superview, attribute: $0, multiplier: 1, constant: 0) })
        let url = URL(string: "http://www.google.com")!
        let urlRequest = URLRequest(url: url)
        webView.load(urlRequest)
    }
Josh Homann
  • 15,933
  • 3
  • 30
  • 33
  • I'm not sure I completely understand how this code is supposed to work. It's not running, I'm using Swift 2.1 so I'll have to modify the code a bit. I'll let you know if it works. But I didn't get what the `$0` does. – Ajil O. Oct 27 '16 at 06:35
  • 1
    map transforms the attributes into NSLayoutConstraints. $0 is the default parameter that stands in for each element in the attributes array. It works in swift 2. You will have to capitalize all of the NSLayoutAttribute enums for swift 2 and change URL and URLRequest back to NSURL and NSURLRequest. – Josh Homann Oct 27 '16 at 06:41
  • I modified the code like this. `NSLayoutConstraint.activateConstraints(attributes.map({NSLayoutConstraint(item: webView, attribute: $0, relatedBy: .Equal, toItem: webView, attribute: $0, multiplier: 1, constant: 0)}))` – Ajil O. Oct 27 '16 at 06:43
  • It compiles but displays just an empty view. What am I doing wrong? NSLayoutConstarint doesn't have an activate property, which is why I changed it to activateConstraints – Ajil O. Oct 27 '16 at 06:46
  • check the view debugger; the webview is there. My guess is that you did not make an app transport exception for http: loads which are blocked by default. Changing this to https: works for me. Otherwise see http://stackoverflow.com/questions/30731785/how-do-i-load-an-http-url-with-app-transport-security-enabled-in-ios-9 – Josh Homann Oct 27 '16 at 06:51
  • Ok. I have now made the app transport exception. But still no output. How do I check the view debugger? Did you mean the View hierarchy? Well, I have UIView in the hierarchy that shows a faded blue on the View when I click on it. Right inside UIView I have WKWebView which doesn't show any output when clicked – Ajil O. Oct 27 '16 at 07:08
  • 1
    That means the webview is there. Something is wrong with your load. put static text in it to test (use a much bigger string) webView.loadHTMLString("test", baseURL: nil) – Josh Homann Oct 27 '16 at 07:13
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/126794/discussion-between-ajil-o-and-josh-homann). – Ajil O. Oct 27 '16 at 07:21
1

So I finally fixed the code! Here's the corrected code.

import UIKit
import WebKit
class ViewController: UIViewController {    
    var webView : WKWebView
    required init(coder aDecoder: NSCoder) {
        self.webView = WKWebView(frame: CGRect(x: 0, y: 0, width: 414, height: 736))
        super.init(coder: aDecoder)!
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(webView)
        webView.translatesAutoresizingMaskIntoConstraints = false
        let views = ["webView" : webView]
        let h = NSLayoutConstraint.constraintsWithVisualFormat("H:|[webView]|", options: [], metrics: nil , views: views)
        let w = NSLayoutConstraint.constraintsWithVisualFormat("V:|[webView]|", options: [], metrics: nil, views: views)
        view.addConstraints(h)  //This is where I was going wrong
        view.addConstraints(w)  //This is where I was going wrong 
        let url = NSURL(string: "http://www.google.com")
        let urlRequest = NSURLRequest(URL: url!)
        webView.loadRequest(urlRequest)
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

Turns out I was adding the constraints to webView where I should have been adding it to view.

Ajil O.
  • 6,562
  • 5
  • 40
  • 72