iOS-KVO初探

KVO全称为Key Value Observing,键值监听机制,由NSKeyValueObserving协议提供支持,NSObject类继承了该协议,所以NSObject的子类都可使用该方法。

实现KVO

  1. 注册监听
  2. 移除监听
  3. 接受通知

我们一为WKWebView添加一个网页请求进度加载条为例。实现一个简单的观察逻辑。

我们首先完成简单的UI逻辑。

//
//  DetailViewController.m
//  KVO
//
//  Created by Ryan on 2020/3/12.
//  Copyright © 2020 Ryan. All rights reserved.
//

#import "DetailViewController.h"
#import <WebKit/WebKit.h>

@interface DetailViewController ()

@property (strong, nonatomic, readwrite) WKWebView *webView;
@property (strong, nonatomic, readwrite) UIButton *button;
@property (strong, nonatomic, readwrite) UIProgressView *progressView;

@end

@implementation DetailViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];

	// 添加顶部栏左部button
    [self.view addSubview:({
        self.button = [[UIButton alloc] initWithFrame:CGRectMake(10, 40, 50, 50)];
        [self.button setImage:[UIImage systemImageNamed:@"return"] forState:UIControlStateNormal];
        [self.button addTarget:self action:@selector(dismissVC) forControlEvents:UIControlEventTouchUpInside];
        self.button;
    })];

	// 添加进度条
    [self.view addSubview:({
        self.progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 90, self.view.frame.size.width, 10)];
        self.progressView;
    })];

	// 添加webView
    [self.view addSubview:({
        self.webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 100, self.view.frame.size.width, self.view.frame.size.height - 100)];
        self.webView;
    })];

	// 为webView请求百度站点
    [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.baidu.com/"]]];
}

// VC的dissMiss
- (void)dismissVC {
    [self dismissViewControllerAnimated:YES completion:nil];
}

@end

在WKWebView的代码页面我们可以发现具有一些可KVO的属性,代表我们可以为WKWebView注册观察者,来观察其KVO属性,来实现一些业务逻辑。

/*! @abstract The page title.
 @discussion @link WKWebView @/link is key-value observing (KVO) compliant
 for this property.
 */
@property (nullable, nonatomic, readonly, copy) NSString *title;

/*! @abstract The active URL.
 @discussion This is the URL that should be reflected in the user
 interface.
 @link WKWebView @/link is key-value observing (KVO) compliant for this
 property.
 */
@property (nullable, nonatomic, readonly, copy) NSURL *URL;

/*! @abstract A Boolean value indicating whether the view is currently
 loading content.
 @discussion @link WKWebView @/link is key-value observing (KVO) compliant
 for this property.
 */
@property (nonatomic, readonly, getter=isLoading) BOOL loading;

/*! @abstract An estimate of what fraction of the current navigation has been completed.
 @discussion This value ranges from 0.0 to 1.0 based on the total number of
 bytes expected to be received, including the main document and all of its
 potential subresources. After a navigation completes, the value remains at 1.0
 until a new navigation starts, at which point it is reset to 0.0.
 @link WKWebView @/link is key-value observing (KVO) compliant for this
 property.
 */
@property (nonatomic, readonly) double estimatedProgress;

注册监听

estimatedProgress属性显示当前页面加载进度,可以用于我们所需要的进度条更新。我们为webView注册观察者,在viewDidLoad添加一些代码

[self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
  • self作为监听者,接受事件
  • 监听self.webView的estimatedProgress属性
  • 在options:NSKeyValueObservingOptionNew的时候发出通知

移除通知

注册的观察者需要手动在dealloc时移除观察者对象。我们在DetailViewController的扩展方法中添加以下代码:

-(void)dealloc {
    [self.webView removeObserver:self forKeyPath:@"estimatedProgress"];
}

接受通知

需要实现该方法。

- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context;

我们在扩展方法中添加以下代码,简单的将webView的estimatedProgress属性赋给progressView的progress属性,实现页面加载进度的更新传递。

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    self.progressView.progress = self.webView.estimatedProgress;
}

这样我们就实现了一个简单的进度条显示web页面加载进度逻辑。

//
//  DetailViewController.m
//  KVO
//
//  Created by Ryan on 2020/3/12.
//  Copyright © 2020 Ryan. All rights reserved.
//

#import "DetailViewController.h"
#import <WebKit/WebKit.h>

@interface DetailViewController ()

@property (strong, nonatomic, readwrite) WKWebView *webView;
@property (strong, nonatomic, readwrite) UIButton *button;
@property (strong, nonatomic, readwrite) UIProgressView *progressView;

@end

@implementation DetailViewController

-(void)dealloc {
    [self.webView removeObserver:self forKeyPath:@"estimatedProgress"];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    [self.view addSubview:({
        self.button = [[UIButton alloc] initWithFrame:CGRectMake(10, 40, 50, 50)];
        [self.button setImage:[UIImage systemImageNamed:@"return"] forState:UIControlStateNormal];
        [self.button addTarget:self action:@selector(dismissVC) forControlEvents:UIControlEventTouchUpInside];
        self.button;
    })];
    [self.view addSubview:({
        self.progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 90, self.view.frame.size.width, 10)];
        self.progressView;
    })];
    [self.view addSubview:({
        self.webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 100, self.view.frame.size.width, self.view.frame.size.height - 100)];
        self.webView;
    })];
    [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.baidu.com/"]]];
    [self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
}

- (void)dismissVC {
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    self.progressView.progress = self.webView.estimatedProgress;
}

@end

发布了92 篇原创文章 · 获赞 33 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/WxqHUT/article/details/104812187