iOS开发基础45-UIWebview

在iOS开发中,UIWebView是一个非常重要的组件,它可以加载和显示网页内容。本篇文章将详细介绍UIWebView以及和其相关的常用功能和高级特性。

一、UIWebView简介

什么是UIWebView

UIWebView是iOS系统内置的网页浏览控件,功能类似于系统自带的Safari浏览器。UIWebView不仅可以加载远程网页资源,还可以加载本地各种常见的文件类型,如:

  • HTML、HTM
  • PDF、DOC、PPT、TXT
  • MP4等

以下是加载网络和本地资源的示例:

// 加载网络资源
NSURL *url = [NSURL URLWithString:@"https://www.apple.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[webView loadRequest:request];

// 加载本地资源
NSString *htmlString = @"<html><body><h1>Hello, World!</h1></body></html>";
[webView loadHTMLString:htmlString baseURL:nil];

键盘工具条显示中文

UIWebView内输入时,工具条默认显示为英文。为让工具条显示中文,可以通过设置项目的Info.plist文件中的Localization native development region为中文(zh_CN)。

二、UIWebView的常用属性和方法

常用方法

  • reload 重新加载(刷新)

    [webView reload];
    
  • stopLoading 停止加载

    [webView stopLoading];
    
  • goBack 回退

    [webView goBack];
    
  • goForward 前进

    [webView goForward];
    

常用属性

  • dataDetectorTypes 检测的数据类型

    webView.dataDetectorTypes = UIDataDetectorTypeAll;
    
  • canGoBack 是否能回退

    if (webView.canGoBack) {
        [webView goBack];
    }
    
  • canGoForward 是否能前进

    if (webView.canGoForward) {
        [webView goForward];
    }
    
  • loading 是否正在加载

    if (webView.loading) {
        [webView stopLoading];
    }
    
  • scalesPageToFit 是否伸缩内容以适应屏幕当前尺寸

    webView.scalesPageToFit = YES;
    

三、UIWebView的代理

通过设置代理,可以监听UIWebView的加载过程。首先,需要让控制器遵循UIWebViewDelegate协议:

@interface MyViewController () <UIWebViewDelegate>
@end

然后实现相关的代理方法:

代理方法

  • webViewDidStartLoad: 开始加载

    - (void)webViewDidStartLoad:(UIWebView *)webView {
        NSLog(@"Web view did start load");
    }
    
  • webViewDidFinishLoad: 加载完成

    - (void)webViewDidFinishLoad:(UIWebView *)webView {
        NSLog(@"Web view did finish load");
    }
    
  • webView:didFailLoadWithError: 加载失败

    - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
        NSLog(@"Web view did fail load with error: %@", error.localizedDescription);
    }
    
  • webView:shouldStartLoadWithRequest:navigationType: 在每次加载请求之前调用,可以通过此方法拦截或修改请求

    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
      NSString *urlString = request.URL.absoluteString;
      if ([urlString hasPrefix:@"customscheme://"]) {
          // Handle custom scheme
          return NO;
      }
      return YES;
    }
    

四、NSInvocation和NSMethodSignature

在iOS开发中,我们常常需要将方法和其对应的参数进行封装,并在稍后阶段进行调用。NSInvocationNSMethodSignature正是实现这种需求的工具。

NSInvocation的使用

下面是一个通过NSInvocation来调用方法的示例:

- (void)invokeExample {
    // 方法签名
    NSMethodSignature *signature = [self methodSignatureForSelector:@selector(sendMessageWithNumber:andContent:status:)];
    if (!signature) {
        NSLog(@"Method not found.");
        return;
    }

    // 创建NSInvocation对象
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.target = self;
    invocation.selector = @selector(sendMessageWithNumber:andContent:status:);

    // 设置参数
    NSString *number = @"10086";
    NSString *content = @"Hello";
    NSString *status = @"Success";
    [invocation setArgument:&number atIndex:2];
    [invocation setArgument:&content atIndex:3];
    [invocation setArgument:&status atIndex:4];

    // 调用方法
    [invocation invoke];
}

- (void)sendMessageWithNumber:(NSString *)number andContent:(NSString *)content status:(NSString *)status {
    NSLog(@"Number: %@, Content: %@, Status: %@", number, content, status);
}

五、NSInvocation封装

通过分类,我们能够更加灵活地使用NSInvocation来调用带有多个参数的方法。

#import "NSObject+PerformSelector.h"
@implementation NSObject (PerformSelector)

- (id)performSelector:(SEL)aSelector withObjects:(NSArray *)objects {
    NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:aSelector];
    if (!signature) {
        NSString *reason = [NSString stringWithFormat:@"No method found for selector %@", NSStringFromSelector(aSelector)];
        @throw [NSException exceptionWithName:@"Method Invocation Exception" reason:reason userInfo:nil];
    }
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.target = self;
    invocation.selector = aSelector;

    NSUInteger argumentCount = signature.numberOfArguments - 2;
    NSUInteger count = MIN(objects.count, argumentCount);

    for (NSUInteger i = 0; i < count; i++) {
        id object = objects[i];
        [invocation setArgument:&object atIndex:i + 2];
    }

    [invocation invoke];

    if (signature.methodReturnLength > 0) {
        id returnValue;
        [invocation getReturnValue:&returnValue];
        return returnValue;
    }

    return nil;
}

@end

使用示例:

NSArray *params = @[@"10086", @"Hello"];
[self performSelector:@selector(sendMessageWithNumber:andContent:) withObjects:params];

六、JavaScript交互

在OC中调用JavaScript

通过stringByEvaluatingJavaScriptFromString方法,可以在UIWebView中执行JavaScript代码:

[webView stringByEvaluatingJavaScriptFromString:@"alert('Hello, World!')"];

在JavaScript中调用OC方法

通过拦截UIWebView的请求,可以在JavaScript中调用OC方法。首先,在JavaScript中定义一个跳转:

function callOCFunction() {
    window.location.href = "customscheme://call";
}

然后,在UIWebView的代理方法中处理这个请求:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    NSString *urlString = request.URL.absoluteString;
    NSString *scheme = @"customscheme://";

    if ([urlString hasPrefix:scheme]) {
        NSString *methodName = [urlString substringFromIndex:scheme.length];
        SEL sel = NSSelectorFromString(methodName);

        if ([self respondsToSelector:sel]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
            [self performSelector:sel];
#pragma clang diagnostic pop
        }
        return NO;
    }
    return YES;
}

- (void)call {
    NSLog(@"OC method called from JS");
}

处理多个参数

对于带有多个参数的OC方法,可以通过自定义URL实现不同的方法调用:

// JavaScript中定义跳转
function callOCFunctionWithParams() {
    window.location.href = "customscheme://sendMessageWithNumber_andContent_?12345&Hello";
}

在OC中解析并调用:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    NSString *urlString = request.URL.absoluteString;
    NSString *scheme = @"customscheme://";

    if ([urlString hasPrefix:scheme]) {
        NSString *path = [urlString substringFromIndex:scheme.length];
        NSArray *components = [path componentsSeparatedByString:@"?"];

        NSString *methodName = components.firstObject;
        methodName = [methodName stringByReplacingOccurrencesOfString:@"_" withString:@":"];
        SEL sel = NSSelectorFromString(methodName);

        if ([self respondsToSelector:sel]) {
            NSArray *params = [components.lastObject componentsSeparatedByString:@"&"];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
            [self performSelector:sel withObjects:params];
#pragma clang diagnostic pop
        }
        return NO;
    }
    return YES;
}

总结

本文介绍了如何使用UIWebView进行网页资源的加载和访问,并涉及了NSInvocationNSMethodSignature的高级用法。通过这些特性和工具,iOS开发者可以实现更加丰富和灵活的应用交互,提升用户体验。

posted @ 2015-08-26 17:13  Mr.陳  阅读(1016)  评论(0编辑  收藏  举报