iOS开发——网络篇——UIWebview基本使用,NSInvocation(封装类),NSMethodSignature(签名),JavaScript,抛异常,消除警告
一、UIWebView简介
1、UIWebView
什么是UIWebView
UIWebView是iOS内置的浏览器控件
系统自带的Safari浏览器就是通过UIWebView实现的
UIWebView不但能加载远程的网页资源,还能加载绝大部分的常见文件
html\htm
pdf、doc、ppt、txt
mp4
… …
UIWebView常用的加载资源的方法
- (void)loadRequest:(NSURLRequest *)request;
2、键盘工具条显示中文

二、常用属性和方法
重新加载(刷新)
- (void)reload;
停止加载
- (void)stopLoading;
回退
- (void)goBack;
前进
- (void)goForward;
需要进行检测的数据类型
@property(nonatomic) UIDataDetectorTypes dataDetectorTypes
是否能回退
@property(nonatomic,readonly,getter=canGoBack) BOOL canGoBack;
是否能前进
@property(nonatomic,readonly,getter=canGoForward) BOOL canGoForward;
是否正在加载中
@property(nonatomic,readonly,getter=isLoading) BOOL loading;
是否伸缩内容至适应屏幕当前尺寸
@property(nonatomic) BOOL scalesPageToFit;
三、代理
监听UIWebView的加载过程
成为UIWebView的代理,遵守UIWebViewDelegate协议,就能监听UIWebView的加载过程
开始发送请求(加载数据)时调用这个方法
- (void)webViewDidStartLoad:(UIWebView *)webView;
请求完毕(加载数据完毕)时调用这个方法
- (void)webViewDidFinishLoad:(UIWebView *)webView;
请求错误时调用这个方法
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error;
UIWebView在发送请求之前,都会调用这个方法,如果返回NO,代表停止加载请求,返回YES,代表允许加载请求
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
四、NSInvocation,NSMethodSignature(签名)
// Signature签名: 在创建NSInvocation的时候, 必须传递一个签名对象
// 签名对象的作用 : 用于获取参数的个数和方法的返回值
// 注意点: 创建签名对象的时候不是使用NSMethodSignature类创建 \
而是方法属于谁就用谁来创建
NSMethodSignature *signature = [ViewController instanceMethodSignatureForSelector:@selector(sendMessageWithNumber:andContent:status:)]; // NSInvocation; 用来包装方法和对应的对象, 它可以存储方法的名称,对应的对象 ,对应的参数
// 1.创建一个NSInvocation对象
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; invocation.target = self; // 保存方法所属的对象
// 给invocation设置的方法, 必须和签名中的方法一致
invocation.selector = @selector(sendMessageWithNumber:andContent:status:); // 保存方法名称 // 第一个参数: 需要给指定方法传递的值
// + 第一个参数需要接收一个指针, 也就是传递值的时候需要传递地址
// 第二个参数: 需要给指定方法的第几个参数传值
NSString *number = @"";
// 注意: 设置参数的索引时不能从0开始, 因为0已经被self占用, 1已经被_cmd占用
[invocation setArgument:&number atIndex:]; NSString *content = @"love";
[invocation setArgument:&content atIndex:]; NSString *status = @"success";
[invocation setArgument:&status atIndex:]; // 2.调用NSInvocation对象的invoke方法
// 只要调用invocation的invoke方法, 就代表需要执行 \
NSInvocation对象中指定对象的指定方法, 并且传递指定的参数
[invocation invoke];
五、invocation封装
这分类用于实现多个参数的方法
#import "NSObject+performSelector.h" @implementation NSObject (performSelector) - (id)performSelector:(SEL)aSelector withObjects:(NSArray *)objects
{
// 1.创建签名对象
NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:aSelector]; // 判断传入的方法是否存储, 如果方法不存在签名对象为nil
if (signature == nil) {
// 传入的方法不存在
NSString *info = [NSString stringWithFormat:@" -[%@ %@]: unrecognized selector sent to instance", [self class], NSStringFromSelector(aSelector)];
// 抛异常
@throw [[NSException alloc] initWithName:@"一个牛B的错误" reason:info userInfo:nil];
} // 2.创建一个NSInvocation对象
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; // 3.保存方法所属的对象
invocation.target = self; // 给invocation设置的方法, 必须和签名中的方法一致
// 4.保存方法名称
invocation.selector = aSelector; // 5.设置参数
/*
当前如果直接遍历参数数组来设置参数, 会存在问题
如果参数数组元素多余参数个数, 那么就会报错
*/
NSUInteger arguments = signature.numberOfArguments - ;
/*
如果直接遍历参数值的个数, 会存在问题
如果参数的个数大于了参数值的个数, 那么数组会越界
*/
NSUInteger objectsCount = objects.count;
/*
参数和参数值, 谁少就遍历谁
*/
NSUInteger count = MIN(arguments, objectsCount); for (int i = ; i < count; i++) {
NSObject *obj = objects[i];
// 处理数组参数中NSNull问题
if ([obj isKindOfClass:[NSNull class]]) {
obj = nil;
}
[invocation setArgument:&obj atIndex:i + ];
} // 6.调用NSInvocation对象的invoke方法
[invocation invoke]; id res = nil;
// 判断当前方法是否有返回值
// NSLog(@"ReturnType = %zd", signature.methodReturnLength);
if ( signature.methodReturnLength != ) {
// 7.获取返回值
// getReturnValue方法会将会去到的方法返回值赋值给传入的对象
[invocation getReturnValue:&res];
} return res;
}
@end
若要给参数传空值
[self performSelector:@selector(sendMessageWithNumber:andContent:) withObjects:@[[NSNull null], @"love"]];
六、JavaScript
1、OC中调用JavaScipt
如何在OC中调用JavaScript代码
使用UIWebView的stringByEvaluatingJavaScriptFromString方法即可
// [self.webView stringByEvaluatingJavaScriptFromString:@"showTitle();"];
2、JavaScipt中调用OC方法
比如要在这个网页中调用oc的方法
<html>
<!--描述网页信息-->
<head>
<meta charset="UTF-8"/>
<title>hello world</title>
<script>
function show()
{
alert();
} function showTitle()
{
alert(document.title);
} function repost()
{
location.href = "http://www.520it.com";
}
function sum()
{
return + ;
} function btnClick()
{
location.href = "xmg://sendMessageWithNumber_andContent_?10086&love";
}
</script>
</head>
<!--网页具体内容-->
<body>
电话号码: </br>
邮箱: @qq.com</br> <button style = "background: red; height: 150px; width: 150px;" onclick = "btnClick();">哥是按钮</button>
</body>
</html>
注意看function btnClick()这个方法
固定格式:
//后面跟的是方法名和参数
:用_代替
方法名和参数之间用?隔开
每个参数之间用&隔开
比如说现在有这四个oc方法
- (void)call
{
NSLog(@"%s", __func__);
} // callWithNumber:
- (void)callWithNumber:(NSString *)number
{
NSLog(@"打电话给%@", number);
} //sendMessageWithNumber:andContent:
- (void)sendMessageWithNumber:(NSString *)number andContent:(NSString *)content
{
NSLog(@"发信息给%@, 内容是%@", number, content);
} - (void)sendMessageWithNumber:(NSString *)number andContent:(NSString *)content status:(NSString *)status
{
NSLog(@"发信息给%@, 内容是%@, 发送的状态是%@", number, content, status);
}
要在JS跳转网页,实现下面这个代理方法
// 每次发送请求前都会调用
// 利用该方法作为JS和OC之间的桥梁
// 在OC代理方法中通过判断自定义协议头, 决定是否是JS调用OC方法
// 在OC代理方法中通过截取字符串, 获取JS想调用的OC方法名称
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
没有参数的情况(消除异常)
NSString *schem = @"xmg://";
NSString *urlStr = request.URL.absoluteString;
if ([urlStr hasPrefix:schem]) {
NSLog(@"需要调用OC方法");
// 1.从URL中获取方法名称
// xmg://call
NSString *methodName = [urlStr substringFromIndex:schem.length];
NSLog(@"%@", methodName);
// 2.调用方法
SEL sel = NSSelectorFromString(methodName);
// 忽略警告信息的作用范围开始
#pragma clang diagnostic push
// 下面这一行代码是用于指定需要忽略的警告信息
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[self performSelector:sel withObject:nil];
// 忽略警告信息的作用范围结束
#pragma clang diagnostic pop
return NO;
}
一个参数的情况
NSString *schem = @"xmg://";
NSString *urlStr = request.URL.absoluteString;
if ([urlStr hasPrefix:schem]) {
NSLog(@"需要调用OC方法");
// 1.从URL中获取方法名称
// xmg://callWithNumber_?10086
NSString *subPath = [urlStr substringFromIndex:schem.length];
// 注意: 如果指定的用于切割的字符串不存在, 那么就会返回整个字符串
NSArray *subPaths = [subPath componentsSeparatedByString:@"?"];
// 2.获取方法名称
NSString *methodName = [subPaths firstObject];
methodName = [methodName stringByReplacingOccurrencesOfString:@"_" withString:@":"];
NSLog(@"%@", methodName);
// 2.调用方法
SEL sel = NSSelectorFromString(methodName);
NSString *parmas = nil;
if (subPaths.count == ) {
parmas = [subPaths lastObject];
}
[self performSelector:sel withObject:parmas];
return NO;
两个参数的情况
NSString *schem = @"xmg://";
NSString *urlStr = request.URL.absoluteString;
if ([urlStr hasPrefix:schem]) {
NSLog(@"需要调用OC方法");
// 1.从URL中获取方法名称
// xmg://sendMessageWithNumber_andContent_?10086&love
NSString *subPath = [urlStr substringFromIndex:schem.length];
// 注意: 如果指定的用于切割的字符串不存在, 那么就会返回整个字符串
NSArray *subPaths = [subPath componentsSeparatedByString:@"?"];
// 2.获取方法名称
NSString *methodName = [subPaths firstObject];
methodName = [methodName stringByReplacingOccurrencesOfString:@"_" withString:@":"];
NSLog(@"%@", methodName);
// 2.调用方法
SEL sel = NSSelectorFromString(methodName); // 3.处理参数
NSString *parma = nil;
if (subPaths.count == ) {
parma = [subPaths lastObject];
// 3.截取参数
NSArray *parmas = [parma componentsSeparatedByString:@"&"];
[self performSelector:sel withObject:[parmas firstObject] withObject:[parmas lastObject]];
return NO;
}
[self performSelector:sel withObject:parma];
return NO;
}
三个参数的情况
// xmg://
NSString *schem = @"xmg://";
NSString *urlStr = request.URL.absoluteString;
if ([urlStr hasPrefix:schem]) {
NSLog(@"需要调用OC方法");
// 1.从URL中获取方法名称
// sendMessageWithNumber_andContent_?10086&love
NSString *subPath = [urlStr substringFromIndex:schem.length];
// 注意: 如果指定的用于切割的字符串不存在, 那么就会返回整个字符串
// sendMessageWithNumber_andContent_
// 10086&love
NSArray *subPaths = [subPath componentsSeparatedByString:@"?"];
// 2.获取方法名称
NSString *methodName = [subPaths firstObject];
methodName = [methodName stringByReplacingOccurrencesOfString:@"_" withString:@":"];
NSLog(@"%@", methodName);
// 2.调用方法
SEL sel = NSSelectorFromString(methodName);
// 3.处理参数
NSArray *parmas = nil;
if (subPaths.count == ) {
parmas = [[subPaths lastObject] componentsSeparatedByString:@"&"];
}
[self performSelector:sel withObjects:parmas];
return NO;
} return YES;
iOS开发——网络篇——UIWebview基本使用,NSInvocation(封装类),NSMethodSignature(签名),JavaScript,抛异常,消除警告的更多相关文章
- iOS开发网络篇—数据缓存
iOS开发网络篇—数据缓存 一.关于同一个URL的多次请求 有时候,对同一个URL请求多次,返回的数据可能都是一样的,比如服务器上的某张图片,无论下载多少次,返回的数据都是一样的. 上面的情况会造 ...
- iOS开发网络篇—监测网络状态(转)
文章转载自:http://www.cnblogs.com/wendingding/p/3950114.html iOS开发网络篇—监测网络状态 一.说明 在网络应用中,需要对用户设备的网络状态进行实时 ...
- iOS开发网络篇—大文件的多线程断点下载
http://www.cnblogs.com/wendingding/p/3947550.html iOS开发网络篇—多线程断点下载 说明:本文介绍多线程断点下载.项目中使用了苹果自带的类,实现了同时 ...
- iOS开发网络篇—简单介绍ASI框架的使用
iOS开发网络篇—简单介绍ASI框架的使用 说明:本文主要介绍网络编程中常用框架ASI的简单使用. 一.ASI简单介绍 ASI:全称是ASIHTTPRequest,外号“HTTP终结者”,功能十分强大 ...
- iOS开发网络篇—网络编程基础
iOS开发网络篇—网络编程基础 一.为什么要学习网络编程 1.简单说明 在移动互联网时代,移动应用的特征有: (1)几乎所有应用都需要用到网络,比如QQ.微博.网易新闻.优酷.百度地图 (2)只有通过 ...
- iOS开发网络篇—搭建本地服务器
iOS开发网络篇—搭建本地服务器 一.简单说明 说明:提前下载好相关软件,且安装目录最好安装在全英文路径下.如果路径有中文名,那么可能会出现一些莫名其妙的问题. 提示:提前准备好的软件 apache- ...
- iOS开发网络篇—HTTP协议
iOS开发网络篇—HTTP协议 说明:apache tomcat服务器必须占用8080端口 一.URL 1.基本介绍 URL的全称是Uniform Resource Locator(统一资源定位符) ...
- iOS开发网络篇—NSURLConnection基本使用
iOS开发网络篇—NSURLConnection基本使用 一.NSURLConnection的常用类 (1)NSURL:请求地址 (2)NSURLRequest:封装一个请求,保存发给服务器的全部数据 ...
- iOS开发网络篇—GET请求和POST请求
iOS开发网络篇—GET请求和POST请求 一.GET请求和POST请求简单说明 创建GET请求 // 1.设置请求路径 NSString *urlStr=[NSString stringWithFo ...
随机推荐
- Linux bash 中,如何将正常信息和错误信息输出到文件
问题描述: $ command 2>> error $ command 1>> output 是否有方法,在bash同一行,实现输出stderr到error文件,输出stdou ...
- cmd chcp命令切换字符格式UTF8
cmd chcp命令切换字符格式 命令介绍: chcp 65001 #换成utf-8代码页 chcp 936 #换成默认的gbk chcp 437 #美国英 ...
- 结合Hadoop,简单理解SSH
在启动dfs和yarn时,需要多次输入密码,不但启动本机进程还有辅服务器启动那些节点也需要相应密码,主与辅服务器之间是通过SSH连接的,并发送操作指令 一.ssh密码远程登录 1.使用ssh连接另一台 ...
- easyui tree获取直接子节点而不获取孙子节点方法
$(node.target.nextElementSibling).children().each(function(index,ele){ if(checked){ $('#rcDimTreeRow ...
- Runner站立会议01
开会时间:9.10-9.30 地点:二教 今天做了什么:学了文本输入,button按钮,界面转换(意图) 遇到什么困难:界面转换时,出现问题,没有正常跳转 明天打所作什么:解决今天遇到的问题,学了第二 ...
- init.php 建立自己的前端共享文件
文件位置:include/init.php 1.新建文件lib_xxx.php(lib_liangxin.php) 2.在文件init.php 第74行加入代码 require(ROOT_PATH . ...
- Latex 表格内公式换行方法
Latex 表格内的公式实现换行的方法 简单的两步走: 1.先将下面的语句放在latex正文的导言区: \newcommand{\tabincell}[2]{\begin{tabula ...
- Effective Objective-C 2.0 — 第七条:在对象内部尽量直接访问实例变量
直接访问实例变量,不经过”方法派发“(method dispatch) 速度快. 直接访问实例变量,不会调用其“设置方法”,这就绕过了为相关属性所定义的“内存管理语义”. 直接访问实例变量,不会触发“ ...
- 【9-6】Centos学习笔记
linux文件系统结构 常用技巧 快捷键启动终端 su命令,使用超级用户登陆 visudo :编辑用户权限 tar xf 文件名:解压文件 Vim编辑器 Tips yum包管理:Yum(全称为 Yel ...
- Linux服务器管理: 日志管理(一)
1.日志管理介绍: a.日志服务:在CentOS6.x中日志服务以及由rsyslogd取代了原有的syslogd服务.rsyslogd日志服务更加先进,功能更多.但是不论该服务的使用,还是日子文件的格 ...