It seems that the IB object templates in XCode 6 beta are still creating old-style objects (UIWebView for iOS and WebView for OSX). Hopefully Apple will update them for the modern WebKit, but until then, what is the best way to create WKWebViews in Interface Builder? Should I create a basic view (UIView or NSView) and assign its type to WKWebView? Most of the examples I find online add it to a container view programmatically; is that better for some reason?
Ios – WKWebView in Interface Builder
iosmacosuiwebviewwkwebviewxcode
Related Solutions
If what you really want to do is generating the vector of all possibles solutions and then test them, you will have to use the preprocessor to generate them all for you.
However, another solution would consist into using a generator: a wrapper class which will instantiate all your solutions and test them. You might want to consult the Hierarchy Generators of Loki (detailed in the book).
// never remember where they put boost::same_type :x
#include <boost/mpl/if.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/mpl/begin.hpp>
#include <boost/mpl/end.hpp>
#include <boost/mpl/next.hpp>
using namespace boost::mpl;
struct None
{
static void test() {}
};
template <class UIterator, class UTypes,
class VIterator, class VTypes,
class WIterator, class WTypes>
class Generator;
template <class UIterator, class UTypes,
class VIterator, class VTypes,
class WIterator, class WTypes>
struct Next
{
// u_begin is not necessary ;)
// it would be cheaper not to pre-declare all of them since we force evaluation
// however this dramatically increase the readability
typedef typename begin<VIterator>::type v_begin;
typedef typename begin<WIterator>::type w_begin;
typedef typename next<UIterator>::type u_next;
typedef typename next<VIterator>::type v_next;
typedef typename next<WIterator>::type w_next;
typedef typename end<UIterator>::type u_end;
typedef typename end<VIterator>::type v_end;
typedef typename end<WIterator>::type w_end;
typedef if_< boost::same_type<w_next, w_end>,
if_< boost::same_type<v_next, v_end>,
if_< boost::same_type<u_next, u_end>,
None,
Generator< u_next, UTypes,
v_begin, VTypes,
w_begin, WTypes >
>,
Generator< UIterator, UTypes,
v_next, VTypes,
w_begin, WTypes >
>,
Generator< UIterator, UTypes,
VIterator, VTypes,
w_next, WTypes>
>::type type;
};
template <class UIterator, class UTypes,
class VIterator, class VTypes,
class WIterator, class WTypes>
struct Generator
{
typedef S< deref<UIterator>::type,
deref<VIterator>::type,
deref<WIterator>::type > S_type;
typedef Next<UIterator, UTypes,
VIterator, VTypes,
WIterator, WTypes>::type next_type;
static void test()
{
// test my variation of S
S_Type my_S;
test_func(my_S);
// test the variations of my next and its next and... you get the idea :)
next_type::test();
}
};
// And finally
int main(int argc, char* argv[])
{
typedef Generator< begin<u_types>::type, u_types,
begin<v_types>::type, v_types,
begin<w_types>::type, w_types > base_generator_type;
base_generator_type::test();
}
Disclaimer: this code has not been compiled and may lack some include / typename / use directives... nevertheless I hope you get my point.
If you have any idea of what the Design Patterns are, it is highly similar to a 'decorator' or a 'composite' design in its way of adding another round of tests at each step layer.
I would also like to note that this takes more that 50 lines of code... but at least it will grow nicely with the vectors :)
Check KINWebBrowser on GitHub to see a full implementation of the solution below.
If you look closely at the documentation for the estimatedProgress
property of WKWebView
that you linked to you will see:
The WKWebView class is key-value observing (KVO) compliant for this property.
This means that you can set up key value observing on the estimatedProgress
property to observe changes to it's value. From the observeValueForKeyPath
method you can update your UI.
The KVO design pattern in Cocoa is pretty messy. Check out this excellent NSHipster article about the best practices of Key Value Observing.
Here is the KVO implementation for estimatedProgress
on WKWebView
:
From your UIViewController
, set up your WKWebView
and add self as an observer of estimatedProgress
self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:self.webView];
[self.webView addObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress)) options:NSKeyValueObservingOptionNew context:NULL];
In the same UIViewController
set up your observeValueForKeyPath
method to filter out the estimatedProgress
property of webView
. You can then access the estimatedProgress
value directly and update your UI accordingly.
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:NSStringFromSelector(@selector(estimatedProgress))] && object == self.webView) {
NSLog(@"%f", self.webView.estimatedProgress);
// estimatedProgress is a value from 0.0 to 1.0
// Update your UI here accordingly
}
else {
// Make sure to call the superclass's implementation in the else block in case it is also implementing KVO
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
Make sure to remove KVO from the UIViewController
in the dealloc method of that UIViewController. It is important to check if isViewLoaded
to avoid a crash if the observer has not already been added.
- (void)dealloc {
if ([self isViewLoaded]) {
[self.wkWebView removeObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress))];
}
// if you have set either WKWebView delegate also set these to nil here
[self.wkWebView setNavigationDelegate:nil];
[self.wkWebView setUIDelegate:nil];
}
To see this in action on some large files load a huge image file of this sweet galaxy. (This file is 35MB. Make sure you are on WiFi!)
NSURLRequest *URLRequest = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://www.spacetelescope.org/static/archives/images/large/opo0328a.jpg"]];
[self.webView loadRequest:URLRequest];
If you are using a UIProgressView
you can achieve a safari like fade-out effect with this code:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:NSStringFromSelector(@selector(estimatedProgress))] && object == self.wkWebView) {
[self.progressView setAlpha:1.0f];
[self.progressView setProgress:self.wkWebView.estimatedProgress animated:YES];
if(self.wkWebView.estimatedProgress >= 1.0f) {
[UIView animateWithDuration:0.3 delay:0.3 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self.progressView setAlpha:0.0f];
} completion:^(BOOL finished) {
[self.progressView setProgress:0.0f animated:NO];
}];
}
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
Best Answer
You are correct - it doesn't seem to work. If you look in the headers, you'll see:
which implies that you can't instantiate one from a nib.
You'll have to do it by hand in viewDidLoad or loadView.