WKWebView in Interface Builder

7 Solutions Collect From Internet About “WKWebView in Interface Builder”

You are correct – it doesn’t seem to work. If you look in the headers, you’ll see:

- (instancetype)initWithCoder:(NSCoder *)coder NS_UNAVAILABLE;

which implies that you can’t instantiate one from a nib.

You’ll have to do it by hand in viewDidLoad or loadView.

As pointed out by some, as of Xcode 6.4, WKWebView is still not available on Interface Builder. However, it is very easy to add them via code.

I’m just using this in my ViewController. Skipping Interface builder

import UIKit
import WebKit

class ViewController: UIViewController {

    private var webView: WKWebView?

    override func loadView() {
        webView = WKWebView()

        //If you want to implement the delegate
        //webView?.navigationDelegate = self

        view = webView
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        if let url = URL(string: "https://google.com") {
            let req = URLRequest(url: url)
            webView?.load(req)
        }
    }
}

Add WKWebView with Swift 3 and Xcode 8

using StoryBoard

ViewController.swift

import UIKit
import WebKit

// Add WKWebView in StoryBoard
class ViewController: UIViewController {

    @IBOutlet var webView: WebView!

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        webView.loadUrl(string: "http://apple.com")
    }
}

class WebView: WKWebView {

    required init?(coder: NSCoder) {

        if let _view = UIView(coder: coder) {
            super.init(frame: _view.frame, configuration: WKWebViewConfiguration())
            autoresizingMask = _view.autoresizingMask
        } else {
            return nil
        }
    }

    func loadUrl(string: String) {
        if let url = URL(string: string) {
            load(URLRequest(url: url))
        }
    }
}

Main.storyboard

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11542" systemVersion="16B2555" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
    <device id="retina4_7" orientation="portrait">
        <adaptation id="fullscreen"/>
    </device>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11524"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--View Controller-->
        <scene sceneID="tne-QT-ifu">
            <objects>
                <viewController id="BYZ-38-t0r" customClass="ViewController" customModule="stackoverflow_24167812" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
                        <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0zg-ri-o6Y" customClass="WebView" customModule="stackoverflow_24167812" customModuleProvider="target">
                                <rect key="frame" x="0.0" y="20" width="375" height="647"/>
                                <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                            </view>
                        </subviews>
                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                    </view>
                    <connections>
                        <outlet property="webView" destination="0zg-ri-o6Y" id="G0g-bh-eej"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="140" y="138.98050974512745"/>
        </scene>
    </scenes>
</document>

programmatically

import UIKit
import WebKit

// Add WKWebView programmatically
class ViewController: UIViewController {

    var webView: WKWebView?

    override func viewDidLoad() {
        super.viewDidLoad()
        // init webView
        webView = WKWebView(frame: view.bounds)
        view.addSubview(webView!)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        // load url
        webView?.loadUrl(string: "http://apple.com")
    }
}

extension WKWebView {
    func loadUrl(string: String) {
        if let url = URL(string: string) {
            load(URLRequest(url: url))
        }
    }
}

With Xcode 8 this is now possible, but the means of achieving it is a little hacky to say the least. But hey, a working solution is a working solution, right? Let me explain.

WKWebView’s initWithCoder: is no longer annotated as “NS_UNAVAILABLE”. It now looks as shown below.

- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;

Start by subclassing WKWebView and override initWithCoder. Instead of calling super initWithCoder, you’ll need to use a different init method, such as initWithFrame:configuration:. Quick example below.

- (instancetype)initWithCoder:(NSCoder *)coder
{
    // An initial frame for initialization must be set, but it will be overridden 
    // below by the autolayout constraints set in interface builder. 
    CGRect frame = [[UIScreen mainScreen] bounds];
    WKWebViewConfiguration *myConfiguration = [WKWebViewConfiguration new];

    // Set any configuration parameters here, e.g.
    // myConfiguration.dataDetectorTypes = WKDataDetectorTypeAll; 

    self = [super initWithFrame:frame configuration:myConfiguration];

    // Apply constraints from interface builder.
    self.translatesAutoresizingMaskIntoConstraints = NO;

    return self;
}

Over in your Storyboard, use a UIView and give it a custom class of your new subclass. The rest is business as usual (setting auto-layout constraints, linking the view to an outlet in a controller, etc).

Finally, WKWebView scales content differently to UIWebView. Many people are likely going to want to follow the simple advice in Suppress WKWebView from scaling content to render at same magnification as UIWebView does to make WKWebView more closely follow the UIWebView behaviour in this regard.

Here’s a simple Swift 3 version based on crx_au‘s excellent answer.

import WebKit

class WKWebView_IBWrapper: WKWebView {
    required convenience init?(coder: NSCoder) {
        let config = WKWebViewConfiguration()
        //config.suppressesIncrementalRendering = true //any custom config you want to add
        self.init(frame: .zero, configuration: config)
        self.translatesAutoresizingMaskIntoConstraints = false
    }
}

Create a UIView in Interface Builder, assign your constraints, and assign it WKWebView_IBWrapper as a custom class, like so:

Utilities -> Identity Inspector Tab[1]

This is now apparently fixed in Xcode 9b4. The release notes say “WKWebView is available in the iOS object library.”

I haven’t looked deeper to see if it requires iOS 11 or is backward compatible yet.

This worked for me in Xcode 7.2…

First add the web view as a UIWebView outlet in the storyboard / IB. This will give you a property like this:

@property (weak, nonatomic) IBOutlet UIWebView *webView;

Then just edit your code to change it to a WKWebView.

@property (weak, nonatomic) IBOutlet WKWebView *webView;

You should also change the custom class to WKWebView in the Identity inspector.