版本记录
版本号 | 时间 |
---|---|
V1.0 | 2018.08.03 |
前言
iOS8
和OS X 10.10
以后,苹果推出了新框架WebKit
,提供了替换UIWebView
的组件WKWebView
。各种UIWebView
的问题没有了,速度更快了,占用内存少了。接下来几篇我们就对WebKit
框架进行全面深度的解析,还是老规矩,从简单到复杂,从面到点。感兴趣的可以看我写的上面几篇。
1. WebKit框架解析(一)—— 基本概览及WKWebView(一)
2. WebKit框架解析(二)—— 基本概览及WKWebView(二)
WKWebView优点
WKWebView
是iOS 8.0就出现了,目前iOS系统已经出到11了,所以以支持最近三代系统的原则进行计算,很多App已经没必要支持iOS8了,而且iOS8用户非常之少了,同时考虑到WKWebView
比UIWebView
性能上带来的优越性,所以是时候考虑到替换webview的API了。
WKWebView
比UIWebView
性能上带来的优越性主要体现在如下几点:
- 加载网页是占用的内存少,同样加载百度,WKWebView占用20M,而UIWebView占用85M。
- 允许JavaScript的Nitro库加载并使用(UIWebView中限制)。
- 支持了更多的HTML5特性。
- 高达60fps的滚动刷新率以及内置手势。
加载网页
加载网页的方式和UIWebview是一样的,都是loadRequest
NSString *urlString = [self.urlStr stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60.0];
[self.webView loadRequest:request];
这里,self.webView就是WKWebView,self.urlStr 就是从外部传进来的URL了,具体如何传递可以根据业务逻辑进行处理,这里不是讨论的重点。
WKNavigationDelegate
这个是WKWebView三个代理中的一个,主要是负责加载的状态回调以及页面跳转。
/*! A class conforming to the WKNavigationDelegate protocol can provide
methods for tracking progress for main frame navigations and for deciding
policy for main frame and subframe navigations.
*/
@protocol WKNavigationDelegate <NSObject>
@optional
/*! @abstract Decides whether to allow or cancel a navigation.
@param webView The web view invoking the delegate method.
@param navigationAction Descriptive information about the action
triggering the navigation request.
@param decisionHandler The decision handler to call to allow or cancel the
navigation. The argument is one of the constants of the enumerated type WKNavigationActionPolicy.
@discussion If you do not implement this method, the web view will load the request or, if appropriate, forward it to another application.
*/
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
/*! @abstract Decides whether to allow or cancel a navigation after its
response is known.
@param webView The web view invoking the delegate method.
@param navigationResponse Descriptive information about the navigation
response.
@param decisionHandler The decision handler to call to allow or cancel the
navigation. The argument is one of the constants of the enumerated type WKNavigationResponsePolicy.
@discussion If you do not implement this method, the web view will allow the response, if the web view can show it.
*/
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
/*! @abstract Invoked when a main frame navigation starts.
@param webView The web view invoking the delegate method.
@param navigation The navigation.
*/
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation;
/*! @abstract Invoked when a server redirect is received for the main
frame.
@param webView The web view invoking the delegate method.
@param navigation The navigation.
*/
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation;
/*! @abstract Invoked when an error occurs while starting to load data for
the main frame.
@param webView The web view invoking the delegate method.
@param navigation The navigation.
@param error The error that occurred.
*/
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error;
/*! @abstract Invoked when content starts arriving for the main frame.
@param webView The web view invoking the delegate method.
@param navigation The navigation.
*/
- (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation;
/*! @abstract Invoked when a main frame navigation completes.
@param webView The web view invoking the delegate method.
@param navigation The navigation.
*/
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation;
/*! @abstract Invoked when an error occurs during a committed main frame
navigation.
@param webView The web view invoking the delegate method.
@param navigation The navigation.
@param error The error that occurred.
*/
- (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error;
/*! @abstract Invoked when the web view needs to respond to an authentication challenge.
@param webView The web view that received the authentication challenge.
@param challenge The authentication challenge.
@param completionHandler The completion handler you must invoke to respond to the challenge. The
disposition argument is one of the constants of the enumerated type
NSURLSessionAuthChallengeDisposition. When disposition is NSURLSessionAuthChallengeUseCredential,
the credential argument is the credential to use, or nil to indicate continuing without a
credential.
@discussion If you do not implement this method, the web view will respond to the authentication challenge with the NSURLSessionAuthChallengeRejectProtectionSpace disposition.
*/
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler;
/*! @abstract Invoked when the web view's web content process is terminated.
@param webView The web view whose underlying web content process was terminated.
*/
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView API_AVAILABLE(macosx(10.11), ios(9.0));
@end
下面分类详细的说一下
1. 加载回调状态
上面这些代理方法中有几个是和加载回调状态相关的。
// 页面开始加载时调用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;
// 当内容开始返回时调用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;
// 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;
// 页面加载失败时调用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation;
// 在这里处理失败的逻辑,包括断网逻辑的处理
2. 页面跳转状态
// 接收到服务器跳转请求之后调用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation;
// 在收到响应后,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
// 在发送请求之前,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
这里,我们用的比较多的方法就是- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
。一般在这个方法里面可以打印出要跳转的全地址。
//打印请求的全地址
NSLog(@"==== decidePolicyForNavigationAction url = %@", navigationAction.request.URL.absoluteString);
这里需要给个回调WKNavigationActionPolicy
是一个枚举,其实就是告诉API要不要跳转。
/*! @enum WKNavigationActionPolicy
@abstract The policy to pass back to the decision handler from the
webView:decidePolicyForNavigationAction:decisionHandler: method.
@constant WKNavigationActionPolicyCancel Cancel the navigation.
@constant WKNavigationActionPolicyAllow Allow the navigation to continue.
*/
typedef NS_ENUM(NSInteger, WKNavigationActionPolicy) {
WKNavigationActionPolicyCancel,
WKNavigationActionPolicyAllow,
} API_AVAILABLE(macosx(10.10), ios(8.0));
当我们回调WKNavigationActionPolicyCancel
时,就不能进行跳转到相应的url,选择WKNavigationActionPolicyAllow
就可以跳转到相应的URL,二者只能返回一个,否则如果连着分别进行返回就会直接Crash。
WKUIDelegate
这个也是WKWebView的代理,其主要的API如下所示:
@class WKFrameInfo;
@class WKNavigationAction;
@class WKOpenPanelParameters;
@class WKPreviewElementInfo;
@class WKWebView;
@class WKWebViewConfiguration;
@class WKWindowFeatures;
/*! A class conforming to the WKUIDelegate protocol provides methods for
presenting native UI on behalf of a webpage.
*/
@protocol WKUIDelegate <NSObject>
@optional
/*! @abstract Creates a new web view.
@param webView The web view invoking the delegate method.
@param configuration The configuration to use when creating the new web
view.
@param navigationAction The navigation action causing the new web view to
be created.
@param windowFeatures Window features requested by the webpage.
@result A new web view or nil.
@discussion The web view returned must be created with the specified configuration. WebKit will load the request in the returned web view.
If you do not implement this method, the web view will cancel the navigation.
*/
- (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures;
/*! @abstract Notifies your app that the DOM window object's close() method completed successfully.
@param webView The web view invoking the delegate method.
@discussion Your app should remove the web view from the view hierarchy and update
the UI as needed, such as by closing the containing browser tab or window.
*/
- (void)webViewDidClose:(WKWebView *)webView API_AVAILABLE(macosx(10.11), ios(9.0));
/*! @abstract Displays a JavaScript alert panel.
@param webView The web view invoking the delegate method.
@param message The message to display.
@param frame Information about the frame whose JavaScript initiated this
call.
@param completionHandler The completion handler to call after the alert
panel has been dismissed.
@discussion For user security, your app should call attention to the fact
that a specific website controls the content in this panel. A simple forumla
for identifying the controlling website is frame.request.URL.host.
The panel should have a single OK button.
If you do not implement this method, the web view will behave as if the user selected the OK button.
*/
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;
/*! @abstract Displays a JavaScript confirm panel.
@param webView The web view invoking the delegate method.
@param message The message to display.
@param frame Information about the frame whose JavaScript initiated this call.
@param completionHandler The completion handler to call after the confirm
panel has been dismissed. Pass YES if the user chose OK, NO if the user
chose Cancel.
@discussion For user security, your app should call attention to the fact
that a specific website controls the content in this panel. A simple forumla
for identifying the controlling website is frame.request.URL.host.
The panel should have two buttons, such as OK and Cancel.
If you do not implement this method, the web view will behave as if the user selected the Cancel button.
*/
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;
/*! @abstract Displays a JavaScript text input panel.
@param webView The web view invoking the delegate method.
@param message The message to display.
@param defaultText The initial text to display in the text entry field.
@param frame Information about the frame whose JavaScript initiated this call.
@param completionHandler The completion handler to call after the text
input panel has been dismissed. Pass the entered text if the user chose
OK, otherwise nil.
@discussion For user security, your app should call attention to the fact
that a specific website controls the content in this panel. A simple forumla
for identifying the controlling website is frame.request.URL.host.
The panel should have two buttons, such as OK and Cancel, and a field in
which to enter text.
If you do not implement this method, the web view will behave as if the user selected the Cancel button.
*/
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler;
#if TARGET_OS_IPHONE
/*! @abstract Allows your app to determine whether or not the given element should show a preview.
@param webView The web view invoking the delegate method.
@param elementInfo The elementInfo for the element the user has started touching.
@discussion To disable previews entirely for the given element, return NO. Returning NO will prevent
webView:previewingViewControllerForElement:defaultActions: and webView:commitPreviewingViewController:
from being invoked.
This method will only be invoked for elements that have default preview in WebKit, which is
limited to links. In the future, it could be invoked for additional elements.
*/
- (BOOL)webView:(WKWebView *)webView shouldPreviewElement:(WKPreviewElementInfo *)elementInfo API_AVAILABLE(ios(10.0));
/*! @abstract Allows your app to provide a custom view controller to show when the given element is peeked.
@param webView The web view invoking the delegate method.
@param elementInfo The elementInfo for the element the user is peeking.
@param defaultActions An array of the actions that WebKit would use as previewActionItems for this element by
default. These actions would be used if allowsLinkPreview is YES but these delegate methods have not been
implemented, or if this delegate method returns nil.
@discussion Returning a view controller will result in that view controller being displayed as a peek preview.
To use the defaultActions, your app is responsible for returning whichever of those actions it wants in your
view controller's implementation of -previewActionItems.
Returning nil will result in WebKit's default preview behavior. webView:commitPreviewingViewController: will only be invoked
if a non-nil view controller was returned.
*/
- (nullable UIViewController *)webView:(WKWebView *)webView previewingViewControllerForElement:(WKPreviewElementInfo *)elementInfo defaultActions:(NSArray<id <WKPreviewActionItem>> *)previewActions API_AVAILABLE(ios(10.0));
/*! @abstract Allows your app to pop to the view controller it created.
@param webView The web view invoking the delegate method.
@param previewingViewController The view controller that is being popped.
*/
- (void)webView:(WKWebView *)webView commitPreviewingViewController:(UIViewController *)previewingViewController API_AVAILABLE(ios(10.0));
#endif // TARGET_OS_IPHONE
#if !TARGET_OS_IPHONE
/*! @abstract Displays a file upload panel.
@param webView The web view invoking the delegate method.
@param parameters Parameters describing the file upload control.
@param frame Information about the frame whose file upload control initiated this call.
@param completionHandler The completion handler to call after open panel has been dismissed. Pass the selected URLs if the user chose OK, otherwise nil.
If you do not implement this method, the web view will behave as if the user selected the Cancel button.
*/
- (void)webView:(WKWebView *)webView runOpenPanelWithParameters:(WKOpenPanelParameters *)parameters initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSArray<NSURL *> * _Nullable URLs))completionHandler API_AVAILABLE(macosx(10.12));
#endif
这个协议主要用于WKWebView处理web界面的三种提示框(警告框、确认框、输入框)。
WebView与JS交互
其实就是原生与H5之间的交互。
1. WebView调用JS
这个其实和UIWebView是一样的,都是调用一句话就可以。
// javaScriptString是JS方法名,
// completionHandler是异步回调block
[self.webView evaluateJavaScript:javaScriptString completionHandler:completionHandler];
2. JS调用WebView
与webView调用JS相比,这个就有点复杂了。UIWebView中可以使用JavaScriptCore使用JSExport协议实现H5的JS调用原生,但是对于WKWebView来说不在支持JavaScriptCore了,而是有专门对应的类WKUserContentController
中的下面方法进行处理。
- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;
这里,name就是调用的H5调用原生的方法名,scriptMessageHandler
是代理回调,JS调用name
方法后,OC会调用scriptMessageHandler
指定的对象。
先看下面一个简单的示例,后面会给一个比较全的调用封装。
//OC注册供JS调用的方法
[[_webView configuration].userContentController addScriptMessageHandler:self name:@"H5CallNative"];
//OC在JS调用方法做的处理
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
NSLog(@"JS 调用了 %@ 方法,传回参数 %@",message.name, message.body);
}
//JS调用
window.webkit.messageHandlers.H5CallNative.postMessage(null);
这里H5CallNative
就是H5调用的OC方法名。
3. JS和WKWebView交互引擎的封装
1)webview中处理部分
在实例化webview时要设置引擎对象,一般如下所示:
WKUserContentController *userContentVC = [[WKUserContentController alloc] init];
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
config.userContentController = userContentVC;
self.webView = [[WKWebView alloc] initWithFrame:rect configuration:config];
self.webView.navigationDelegate = self;
[userContentVC addScriptMessageHandler:[JJJSEngine shared] name:@"JSCallNative"];
[JJJSEngine shared].webview = self.webView;
这里JJJSEngine是处理交互使用的引擎,@"JSCallNative"
就是JS要调用的native的方法名。
注意在dealloc中使用完要移除引擎和清空引擎。
- (void)dealloc
{
[[JJJSEngine shared] cleanUp];
[JJJSEngine shared].webview = nil;
[[self.webView configuration].userContentController removeScriptMessageHandlerForName:@"JSCallNative"];
}
2)JJJSEngine引擎中处理部分
下面就看一下JJJSEngine引擎中需要处理的内容。
#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>
@interface JJJSEngine : NSObject <WKScriptMessageHandler>
@property (nonatomic, weak) WKWebView *webview;
@property (nonatomic, weak) id <WKScriptMessageHandler> scriptDelegate;
+ (instancetype)shared;
//清理
- (void)cleanUp;
//native向js发送消息
- (void)sendJSMessage:(NSString *)content;
@end
@interface JJJSEngine()
@property (nonatomic, strong) dispatch_queue_t jsQueue;
@property (nonatomic, strong) NSMutableDictionary *jsCallbacksDictM;
@end
@implementation JJJSEngine
#pragma mark - Override Base Function
- (instancetype)init
{
self = [super init];
if (self) {
_jsQueue = dispatch_queue_create("com.xxxxx.jsbridge", DISPATCH_QUEUE_SERIAL);
_jsCallbacksDictM = [NSMutableDictionary dictionaryWithCapacity:5];
}
return self;
}
#pragma mark - Object Private Function
//发送JS消息
- (void)sendJSMessageName:(NSString *)callback response:(NSDictionary *)response
{
if ([callback isNotEmpty] == NO || self.webview == nil) {
return;
}
NSString *responseStr = [JSONHelp object2NSString:response];
responseStr = responseStr ? : @"";
responseStr = [responseStr stringByReplacingOccurrencesOfString:@"'" withString:@"\'"];
NSString *jsCallStr = [NSString stringWithFormat: @"%@(\'%@\');", callback, responseStr];
dispatch_async(dispatch_get_main_queue(), ^{
@try {
[self.webview evaluateJavaScript:jsCallStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
if (error != nil) {
DDLogError(@"evaluate script fail :%@",jsCallStr);
}
}];
} @catch (NSException *exception) {
DDLogError(@"webview evaluate error :%@",[exception reason]);
}
});
}
#pragma mark - Object Public Function
- (void)cleanUp
{
[self.jsCallbacksDictM removeAllObjects];
}
//native向js发送消息
- (void)sendJSMessage:(NSString *)content
{
[self sendJSMessageName:self.jsCallbacksDictM[@"xxxx"] response:response];
}
#pragma mark - Class Public Function
+ (instancetype)shared
{
static JJJSEngine *object;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
object = [[self alloc] init];
});
return object;
}
#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
NSLog(@"JS 调用了 %@ 方法,传回参数 %@",message.name, message.body);
if ([message.name isEqualToString:@"JSCallNative"]) {
//在这里处理Json字符串并根据actionType进行其他逻辑处理
}
}
@end
3)JS中处理部分
window.webkit.messageHandlers.JSCallNative.postMessage("待传递处理的json字符串");
Cookie存放信息
先说一下一个应用场景,很多时候我们需要将个别几个信息放在cookie里面,然后当我们加载webview的时候,H5会拿我们的信息去服务端去请求数据,然后渲染页面,比如说我的等级页面,需要uid和token,然后请求服务器,这样的显示界面才是属于我们自己的等级。还有比如关于App的界面需要传递一个版本号,那么也可以在cookie里面进行存储。
1. UIWebView存储cookie信息
在UIWebView中我们直接可以使用下面的例子进行cookie的信息存储。
//获取 Version 版本号
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
//获取 Build 构建版本号
NSString *build = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
NSString *versionStr = [NSString stringWithFormat:@"%@.%@", version, build];
NSHTTPCookie *versionCookie = [NSHTTPCookie cookieWithProperties:@{NSHTTPCookieName:@"version",
NSHTTPCookieValue:_To_Str(versionStr),
NSHTTPCookiePath:@"/",
NSHTTPCookieDomain:@".xxxx.com",
NSHTTPCookieOriginURL:@".xxxx.com"}];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:versionCookie];
所以使用NSHTTPCookieStorage
就可以实现cookie中的信息存储和传递。
2. WKWebView存储cookie信息
对于WKWebView
来说上面的那一套cookie的NSHTTPCookieStorage
机制就不管用了,如果还是按照那种存储方式的话,你打开调试器可以看见cookie里面根本就没有值,也就是说NSHTTPCookieStorage
在WKWebView
中失效了。
真正的解决方法就是用WKUserScript
进行注入
//在WKWebView实例化的时候
NSString *cookieStr = [self calculateCookie];
WKUserScript *cookieScript = [[WKUserScript alloc] initWithSource: cookieStr injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
WKUserContentController *userContentVC = [[WKUserContentController alloc] init];
[userContentVC addUserScript:cookieScript];
//获取要注入的cookie字符串
- (NSString *)calculateCookie
{
NSString *cookieStr = @"";
//获取 Version 版本号
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
//获取 Build 构建版本号
NSString *build = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
NSString *versionStr = [NSString stringWithFormat:@"%@.%@", version, build];
cookieStr = [NSString stringWithFormat:@"document.cookie='token=%@';document.cookie='userId=%@';document.cookie='version=%@'", [JJUserManager token], [JJUserManager userID], versionStr];
return cookieStr;
}
这样,我们通过网络监察器查看,就可以看见cookie中确实有值了。
动态设置导航栏title
1. UIWebView设置title
UIWebView可以在代理方法- (void)webViewDidFinishLoad:(UIWebView *)webView
中,也就是加载完成后设置title,如下所示:
NSString *title = [self.webView stringByEvaluatingJavaScriptFromString:@"document.title"];
self.title = title;
2. WKWebView设置title
对于WKWebView,可以使用KVO监听设置title,如下所示
//webview实例化后就添加KVO
[self.webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:nil];
#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
if ([keyPath isEqualToString:@"title"]) {
if (object == self.webView) {
self.title = self.webView.title;
}
else{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
}
注意:在dealloc后要移除观察。
[self.webView removeObserver:self forKeyPath:@"title"];
参考文章
后记
本篇主要讲述了WKWebView替换UIWebView,感兴趣的给个赞或者关注~~~~