iOS Runtime 实践(1)
2016-07-06 11:29
357 查看
很多时候我们都在看iOS开发中的黑魔法——Runtime。懂很多,但如何实践却少有人提及。本文便是iOS Runtime的实践第一篇。
WebView
我们这次的实践主题,是使用针对接口编程的方式,借助Excalibur系统,来达到动态切换UIWebView和WKWebkit的目的。
为什么要动态切换?其实我们众所周知,Apple的UIWebView存在巨大的内存泄漏。当网页内容较复杂,图片较大时,经常会出现150MB+的内存占用率;并且这个内存占用率会一直存在无法消除。虽然StackOverflow上有很多大神想出了各种方式,但作用却很小。
Apple 从 iOS8 开始,推出了更新、优化更好的WKWebkit。这个库是UIWebView的继承者,在相同的浏览页面下,WKWebKit提供的WKWebView的内存占用率甚至可以只有UIWebView的1/10。可惜的是,我们很多时候为了保证用户的覆盖率,target iOS Version都是 iOS7。这时候我们就需要使用UIWebView来达到显示的目的。
那么问题来了,如何实现根据iOS版本来达到动态加载的目的呢?
Excalibur
Excalibur是我们用来映射类和字符串scheme对应关系的类。通过注册scheme对应的类,来达到目的。
注册一个类:
+
(void)registerScheme:(nonnull
NSString
*)scheme
forClass:(nonnull
__unsafe_unretained Class)aClass
{
NSParameterAssert(scheme);
NSParameterAssert(aClass);
if
([Excalibur
classForScheme:scheme])
{
[NSException
raise:@"Scheme
Already Exists"
format:@"'%@'
Scheme Already Exists",
scheme];
return;
}
if
(![aClass
isSubclassOfClass:[NSObject
class]])
{
[NSException
raise:@"Wrong
Class Type"
format:@"Class
should inherit from NSObject"];
return;
}
if
([scheme
isEqualToString:@""])
{
[NSException
raise:@"Scheme
Wrong"
format:@"Scheme
should not be blank"];
return;
}
[sharedInstance
addScheme:scheme
forClass:aClass];
}
从Excalibur中获取scheme指定的类:
+
(nullable
__unsafe_unretained Class)classForScheme:(nonnull
NSString
*)scheme
{
return
[sharedInstance.mapTable
objectForKey:scheme];
}
通过Excalibur,我们使用哪个类,就可以在Runtime时期才确定。
针对接口编程
在设计模式上,我们经常听到说,要针对接口编程。那么在iOS开发中,怎样才算是针对接口编程呢?这个又有什么好处呢?
在Objective-C语言中,我们一般认为Protocol便是接口功能的协议。
这里,我们想达到的目的,是在不同的iOS版本下,调用不同的Webkit来进行网页渲染。而网页的渲染一般放在一个ViewController下,因此我们可以针对这个需求,制订一个用来渲染指定URL的ViewController接口:
@protocol
DWKProtocol
+
(instancetype)webViewControllerForUrl:(NSURL
*)url;
@end
这里的接口,返回一个ViewController,该VC可以用来打开url网页。
现在我们可以写两个ViewController,分别是DWKWebViewController和DWKWebkitViewController;其中DWKWebViewController使用UIWebView来渲染网页:
@interface
DWKWebViewController
()
@property
(nonatomic,
strong)
UIWebView
*webView;
@property
(nonatomic,
strong)
NSURL
*url;
@end
而 DWKWebkitViewController则使用WKWebView来渲染网页:
@interface
DWKWebkitViewController
()
@property
(nonatomic,
strong)
WKWebView
*webView;
@property
(nonatomic,
strong)
NSURL
*url;
@end
接下来,二者在Runtime的初始化阶段向Excalibur注册自己:
DWKWebViewController
+
(void)load
{
if
(iOSVersion
DWKWebkitViewController
+
(void)load
{
if
(iOSVersion
>= 8.0)
{
static
dispatch_once_t
onceToken;
dispatch_once(&onceToken,
^{
[Excalibur
registerScheme:DWK_MODULE_WEB_VC
forClass:[self
class]];
});
}
}
那么,8.0以下时,DWKWebViewController就会是DWK_MODULE_WEB_VC模块的实现者;而在8.0及其以上时,DWKWebkitViewController则是DWK_MODULE_WEB_VC模块的实现者。
调用
做好了以上两步准备,接下来便是调用DWK_MODULE_WEB_VC的模块来渲染网页了。
这里,我们已经约定好,实现DWK_MODULE_WEB_VC的ViewController肯定会实现DWKProtocol,因此我们可以这样来获取我们想要的ViewController Class:
Class webViewControllerClass
= [Excalibur
classForScheme:DWK_MODULE_WEB_VC];
UIViewController
*webViewController
= [webViewControllerClass
webViewControllerForUrl:[NSURL
URLWithString:@"www.baidu.com"]];
总结
至此,使用Runtime达到动态加载UIWebView和WKWebkit的目的达成。
代码链接
我把代码放到了Github上,希望对你有所帮助:
https://github.com/DemoMania/dynamicWebkit
WebView
我们这次的实践主题,是使用针对接口编程的方式,借助Excalibur系统,来达到动态切换UIWebView和WKWebkit的目的。
为什么要动态切换?其实我们众所周知,Apple的UIWebView存在巨大的内存泄漏。当网页内容较复杂,图片较大时,经常会出现150MB+的内存占用率;并且这个内存占用率会一直存在无法消除。虽然StackOverflow上有很多大神想出了各种方式,但作用却很小。
Apple 从 iOS8 开始,推出了更新、优化更好的WKWebkit。这个库是UIWebView的继承者,在相同的浏览页面下,WKWebKit提供的WKWebView的内存占用率甚至可以只有UIWebView的1/10。可惜的是,我们很多时候为了保证用户的覆盖率,target iOS Version都是 iOS7。这时候我们就需要使用UIWebView来达到显示的目的。
那么问题来了,如何实现根据iOS版本来达到动态加载的目的呢?
Excalibur
Excalibur是我们用来映射类和字符串scheme对应关系的类。通过注册scheme对应的类,来达到目的。
注册一个类:
+
(void)registerScheme:(nonnull
NSString
*)scheme
forClass:(nonnull
__unsafe_unretained Class)aClass
{
NSParameterAssert(scheme);
NSParameterAssert(aClass);
if
([Excalibur
classForScheme:scheme])
{
[NSException
raise:@"Scheme
Already Exists"
format:@"'%@'
Scheme Already Exists",
scheme];
return;
}
if
(![aClass
isSubclassOfClass:[NSObject
class]])
{
[NSException
raise:@"Wrong
Class Type"
format:@"Class
should inherit from NSObject"];
return;
}
if
([scheme
isEqualToString:@""])
{
[NSException
raise:@"Scheme
Wrong"
format:@"Scheme
should not be blank"];
return;
}
[sharedInstance
addScheme:scheme
forClass:aClass];
}
从Excalibur中获取scheme指定的类:
+
(nullable
__unsafe_unretained Class)classForScheme:(nonnull
NSString
*)scheme
{
return
[sharedInstance.mapTable
objectForKey:scheme];
}
通过Excalibur,我们使用哪个类,就可以在Runtime时期才确定。
针对接口编程
在设计模式上,我们经常听到说,要针对接口编程。那么在iOS开发中,怎样才算是针对接口编程呢?这个又有什么好处呢?
在Objective-C语言中,我们一般认为Protocol便是接口功能的协议。
这里,我们想达到的目的,是在不同的iOS版本下,调用不同的Webkit来进行网页渲染。而网页的渲染一般放在一个ViewController下,因此我们可以针对这个需求,制订一个用来渲染指定URL的ViewController接口:
@protocol
DWKProtocol
+
(instancetype)webViewControllerForUrl:(NSURL
*)url;
@end
这里的接口,返回一个ViewController,该VC可以用来打开url网页。
现在我们可以写两个ViewController,分别是DWKWebViewController和DWKWebkitViewController;其中DWKWebViewController使用UIWebView来渲染网页:
@interface
DWKWebViewController
()
@property
(nonatomic,
strong)
UIWebView
*webView;
@property
(nonatomic,
strong)
NSURL
*url;
@end
而 DWKWebkitViewController则使用WKWebView来渲染网页:
@interface
DWKWebkitViewController
()
@property
(nonatomic,
strong)
WKWebView
*webView;
@property
(nonatomic,
strong)
NSURL
*url;
@end
接下来,二者在Runtime的初始化阶段向Excalibur注册自己:
DWKWebViewController
+
(void)load
{
if
(iOSVersion
DWKWebkitViewController
+
(void)load
{
if
(iOSVersion
>= 8.0)
{
static
dispatch_once_t
onceToken;
dispatch_once(&onceToken,
^{
[Excalibur
registerScheme:DWK_MODULE_WEB_VC
forClass:[self
class]];
});
}
}
那么,8.0以下时,DWKWebViewController就会是DWK_MODULE_WEB_VC模块的实现者;而在8.0及其以上时,DWKWebkitViewController则是DWK_MODULE_WEB_VC模块的实现者。
调用
做好了以上两步准备,接下来便是调用DWK_MODULE_WEB_VC的模块来渲染网页了。
这里,我们已经约定好,实现DWK_MODULE_WEB_VC的ViewController肯定会实现DWKProtocol,因此我们可以这样来获取我们想要的ViewController Class:
Class webViewControllerClass
= [Excalibur
classForScheme:DWK_MODULE_WEB_VC];
UIViewController
*webViewController
= [webViewControllerClass
webViewControllerForUrl:[NSURL
URLWithString:@"www.baidu.com"]];
总结
至此,使用Runtime达到动态加载UIWebView和WKWebkit的目的达成。
代码链接
我把代码放到了Github上,希望对你有所帮助:
https://github.com/DemoMania/dynamicWebkit
相关文章推荐
- 获取URL中的某个参数/删除URL中的某个参数
- iOS 代理方法声明的两种形式:加号,减号,及使用场景说明
- 《Motion Design for iOS》(三十一)
- [iOS 扩展转] iOS扩展开发-Today扩展&share扩展
- iOS静态库开发中对Bitcode的支持
- IOS代码笔记之仿电子书书架效果
- iOS AVCaptureDevice 图像90度问题
- iOS Runtime 实践(1)
- IOS如何替换电话号码中间4位为"-"符号
- IOS 缓存清理
- iOS 使用命令行打包程序
- Android,IOS QQ在线客服代码
- iOS-模糊查询
- iOS开发之17个常用代码整理
- IOS代码笔记之勾选"记住密码"整体button
- iOS Socket介绍及其简单应用
- 解析 iOS 动画原理与实现
- IOS:pch的一些用法
- IOS代码笔记之文字走马灯效果
- iOS中集成ijkplayer视频直播框架