iOS编程基础-OC(十一)-Foundation框架中的系统服务:URL处理和进程间通信

该系列文章系个人读书笔记及总结性内容,任何组织和个人不得转载进行商业活动! 

     

     第11章 Foundation框架中的系统服务

   

  

     11.6 URL处理

     

     URL处理类用于通过标准Internet协议(ftp、http、https和本地文件),与URL进行交互和与数据资源进行通信;

     这些类提供了下列功能:

     1)URL加载;

     2)缓存管理;

     3)身份验证和证书管理;

     4)Cookie管理;

     5)协议支持;

     

     这些类还支持代理服务器和每个用户的系统首选项安全套接字(SOCKS)网关;

     

     11.6.1 URL加载

     

     NSURL类:

        NSURL对象用于管理URL和URL引用的资源;

        NSURL类的方法可以用来创建和初始化NSURL对象、查询URL以及访问URL组件(即主机和端口等);

        NSURL类还提供了用于处理书签数据的方法;

     

     书签:

        是指对文件位置的永久引用;它是一种宝贵的文件定位工具,因为即使在文件被移动或重命名的情况下,也可以使用它重建文件的URL;

  

    NSURL * url = [NSURL URLWithString:@"http://www.apress.com:80"];
    NSLog(@"URL: scheme %@,host %@,port %@",url.scheme,url.host,url.port);
     


     log:

     2017-12-26 10:53:01.911834+0800 精通Objective-C[26601:8389700] URL: scheme http,host www.apress.com,port 80


     NSURLRequest类和NSMutableURLRequest类:

        用于代表URL加载请求;

        NSURLRequest类:

            是一个独立的网络协议和URL方案;

            使用其方法可以创建和初始化URL请求以及获取请求的属性;

        NSMutableURLRequest类是NSURLRequest类的子类:

            使用其方法可以更改URL及其组件;

        示例:创建一个可变URL请求,然后设置该HTTP请求的方法值;

  

  NSMutableURLRequest * req = [NSMutableURLRequest requestWithURL:url];
    [req setHTTPMethod:@"GET"];

     

     NSURLResponse类和NSHTTPURLResponse类:

        用于代表URL请求反应的回应;

        NSURLResponse对象可以有执行URL请求的同步加载操作(sendSynchronousRequest:returningResponse:error:)的对象创建;

            也可以由遵守NSURLConnectionDataDelegate协议的对象创建;

        NSHTTPURLResponse是NSURLResponse类的子类:

            使用其方法可以访问由URL请求返回的HTTP特定信息;

     

     NSUELConnection类和NSURLDownload类:

        用于下载通过URL识别的资源;

        NSUELConnection类支持同步和异步方式的资源加载、开始和停止连接,以及管理用于控制URL连接各个方面(即缓存管理、身份认证和证书、协议支持和Cookie的管理)的委托对象;

     

     在使用异步加载资源时必须设置委托对象:

        该对象遵循NSURLConnectionDelegate协议,至少会实现如下方法:

     1)connection:didReceiveData:(获取被加载的数据)

     2)connection:didFailWithError:(处理链接错误)

     3)connection:didFinishLoading:(加载数据操作完成)

     

     示例:使用NSURLConnection类以同步的方式加载URL的内容:

  

  NSURL * url1 = [NSURL URLWithString:@"http://www.apress.com/index.html"];
    NSURLRequest * request1 = [NSURLRequest requestWithURL:url1];
    NSURLResponse * response1;
    NSError * aerror1;
    NSData * data1 = [NSURLConnection sendSynchronousRequest:request1 returningResponse:&response1 error:&aerror1];
    NSLog(@"Expected content length = %lld,loaded %lu bytes",[response1 expectedContentLength],[data1 length]);
    


     log:

     2017-12-26 11:25:39.451971+0800 精通Objective-C[26911:8415701] Expected content length = -1,loaded 11941 bytes


     注:ios9之后 推荐使用NSURLSession类;

     

     NSURLDownload类:

        用于通过异步方式,将URL的内容下载到文件中;

        使用其方法可以初始化下载操作(设置请求和委托对象)、设置目标路径、重新开始未完成的下载操作和取消下载请求;

        NSURLDownload类还提供了对MacBinary、BinHex和gzip格式文件的支持;

        其委托对象必须遵守NSURLDownloadDelegate协议,因而会至少实现下列方法:

        1)download:didFailWithError:(处理链接错误)

        2)downloadDidFinish:(加载数据完成后,执行处理操作)

     

     注:这个类只能在Max OX上使用,现在的话 推荐使用NSURLSessionDownloadTask类,可自行查阅API;

     

     11.6.2 缓存管理

     

     缓存管理类(NSURLCache和NSCachedURLResponse)为对URL请求的回应提供了缓存;

        NSURLCache类为NSURL提供了通用缓存;

        NSCachedURLResponse类用于封装URL回应(即NSURLResponse对象)和通用URL加载的数据(即NSData对象);

     

     NSURLConnection委托对象必须实现connection:willCacheResponse:方法,提供由NSURLCache实例初始化的NSCachedURLResponse对象,以便管理缓存

     

     接下里,我们将编写一个用URL加载类下载资源的程序;

     

     11.6.3 使用URL加载API下载资源

     

     下面编写使用URL加载API下载URL资源的类:C11NetConnector;

     (Code C11NetConnector.h C11NetConnector.m)

     

#import <Foundation/Foundation.h>

#define HTTP_SCHEME @"http"
#define HTTPS_SCHEME @"https"

#define CACHE_MEMARY_SIZE (4*1024*1024)

@interface C11NetConnector : NSObject<NSURLConnectionDelegate>//接口采用NSURLConnectionDelegate协议的代理,因而能够通过异步方式加载来自NSURLConnection实例的数据

@property (readonly) BOOL finishedLoading;//表示 是否结束了加载数据的操作

-(id)initWithRequest:(NSURLRequest *)request;
-(void)reloadRequest;//重新加载NSURLRequest对象

@end

#import "C11NetConnector.h"

//通过扩展声明,提供属性
@interface C11NetConnector()<NSURLConnectionDataDelegate>

@property NSURLRequest * request;
@property BOOL finishedLoading;
@property NSURLConnection * connector;
@property NSMutableData * receiveData;

@end;

@implementation C11NetConnector

-(id)initWithRequest:(NSURLRequest *)request{
    if (self = [super init]) {
        _request = request;
        
        //通过合适的内存存储结构,创建URL缓存
        NSURLCache * URLCache = [[NSURLCache alloc] init];
        [URLCache setMemoryCapacity:CACHE_MEMARY_SIZE];
        [NSURLCache setSharedURLCache:URLCache];
        
        //创建连接并开始下载资源数据
        _connector = [NSURLConnection connectionWithRequest:request delegate:self];
    }
    return self;
}

-(void)reloadRequest{
    self.finishedLoading = NO;
    self.connector = [NSURLConnection connectionWithRequest:self.request delegate:self];
}

#pragma mark -
#pragma mark Delegate methods
//当连接能够对请求做出回应时,会发送该消息
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    if (self.receiveData != nil) {
        //将receiveData对象长度置0,从而丢弃了通过上一个请求接收的数据
        [self.receiveData setLength:0];
    }
}
//在连接将回应存储到缓存前,会发送该消息
-(NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse{
    //使用这个方法能够修改该回应,也可以阻止它被存储到缓存中
    NSURLResponse * response = [cachedResponse response];
    NSURL * url = [response URL];
    if ([[url scheme] isEqualToString:HTTP_SCHEME] || [[url scheme] isEqualToString:HTTPS_SCHEME]) {
        NSLog(@"Downloaded data,caching response");
        return cachedResponse;
    }else{
        NSLog(@"Downloaded data,not caching response");
        return nil;
    }
}
//接收资源时,,会发送该消息;若以递增的方式接收数据,在单个请求中该方法可能会被调用多次
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
    if (self.receiveData != nil) {
        [self.receiveData appendData:data];
    }else{
        self.receiveData = [[NSMutableData alloc] initWithData:data];
    }
}
//当连接成功完成加载数据操作时,会发送该消息
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
    NSUInteger length = [self.receiveData length];
    NSLog(@"Download %lu bytes from request %@",length,self.request);
    
    //加载数据后,设置退出运行循环的标记
    self.finishedLoading = YES;
}
//当连接加载数据失败时,会发送该消息
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
    NSLog(@"Error loading request %@",[error localizedDescription]);
    self.finishedLoading = YES;
}


-(void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{
    //使用用户名 密码 创建了一个证书
    NSURLCredential * credential = [NSURLCredential credentialWithUser:@"TestUser" password:@"TestPassword" persistence:NSURLCredentialPersistenceForSession];
    //使用证书回应连接的身份认证质询
    [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
}

@end

     我们来详细看一下这段代码:

     1)使用分类声明了C11NetConnector类的实现代码中使用的私有属性;

        C11NetConnector的实现代码定义了接口声明的方法和NSURLConnectionDataDelegate协议声明方法;

        init方法中,为了缓存回应,创建并初始化了一个NSURLCache实例;

            创建缓存,并使用内存存储结构配置了该缓存,然后将其设置为与连接一起使用的共享缓存;

        最后创建了一个NSURLConnection对象并开始下载URL;

     2)其余代理方法,我们在代码中做了注释;

     

     编写好这个类之后,我们来使用它加载一个URL;

  

 NSString * index_url = @"http://www.wikipedia.com/index.html";
    
    //获取当前的运行循环
    NSRunLoop * runloop = [NSRunLoop currentRunLoop];
    
    //使用指定的缓存策略来创建请求,然后开始下载
    NSURLRequest * request2 = [NSURLRequest requestWithURL:[NSURL URLWithString:index_url] cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:5];
    
    C11NetConnector * netConnect = [[C11NetConnector alloc] initWithRequest:request2];
    //一直循环 知道加载资源操作结束为止
    while (!netConnect.finishedLoading && [runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) {
    }
    
    //记录缓存占用内存大小
    NSLog(@"Cache memory usage = %lu bytes",[[NSURLCache sharedURLCache] currentMemoryUsage]);
    
    //通过请求重新加载数据,这次会从缓存获取数据
    [netConnect reloadRequest];
    while (!netConnect.finishedLoading && [runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) {
        //运行循环,直到netConnect.finishedLoading == YES;
    }
    //释放缓存
    [[NSURLCache sharedURLCache] removeAllCachedResponses];

     log:

     2017-12-26 16:05:35.861566+0800 精通Objective-C[29350:8632734] Downloaded data,caching response

     2017-12-26 16:05:35.861917+0800 精通Objective-C[29350:8632734] Download 1242 bytes from request <NSURLRequest: 0x60c000012d70> { URL: http://www.wikipedia.com/index.html }

     2017-12-26 16:05:35.862149+0800 精通Objective-C[29350:8632734] Cache memory usage = 1242 bytes

     2017-12-26 16:05:36.059240+0800 精通Objective-C[29350:8632734] Download 1242 bytes from request <NSURLRequest: 0x60c000012d70> { URL: http://www.wikipedia.com/index.html }

     

     分析:

     1)NSURLRequestReturnCacheDataElseLoad对应的缓存策略设置了只有在cache中不存在data时才从原始地址下载;

        注意,如果某个url不支持缓存策略,即便设置了也是无效的;

     2)    while (!netConnect.finishedLoading && [runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]])

        这段代码可能会觉得熟悉,是的我们之前用过:

            这段代码会运行循环,从输入源接收事件并执行相应的委托方法,直到连接完成加载资源的操作为止;

     3)我们将缓存使用情况打印出来;

        重新请求时,因为数据已经被存储在缓存中,而且缓存策略设置了应使用的缓存大小,所以无须从URL加载数据就可以立即得到数据;

            从缓存中获取数据,connection: willCacheResponse:委托方法将不会被调用;

     4)最后释放缓存;

     

     这个程序实践了使用URL加载API,通过异步方式下载URL的知识;

     

     备注:

     1.NSURLRequestUseProtocolCachePolicy NSURLRequest   默认的cache policy,使用Protocol协议定义。

     2.NSURLRequestReloadIgnoringCacheData               忽略缓存直接从原始地址下载。

     3.NSURLRequestReturnCacheDataDontLoad               只使用cache数据,如果不存在cache,请求失败;用于没有建立网络连接离线模式

     4.NSURLRequestReturnCacheDataElseLoad               只有在cache中不存在data时才从原始地址下载。

     5.NSURLRequestReloadIgnoringLocalAndRemoteCacheData 忽略本地和远程的缓存数据,直接从原始地址下载,与NSURLRequestReloadIgnoringCacheData类似。

     6.NSURLRequestReloadRevalidatingCacheData           验证本地数据与远程数据是否相同,如果不同则下载远程数据,否则使用本地数据

     

     下面介绍下载资源是解决身份验证的手段;

     

     11.6.4 身份认证和证书管理

     

     身份认证和证书管理类:

        NSURLProtectionSpace、NSURLCredentialStorage、NSURLCredential、NSURLAuthenticationChallenge和NSURLAuthenticationChallengeSender;

        提供了对请求访问受保护URL的用户进行身份认证;

        需要身份认证的资源要求 尝试加载资源的客户端提供证书;

     

     Foundation框架的NSURLAuthenticationChallenge类封装了从客户端向服务端提供认证请求的功能;

     NSURLCredential类代表为了回应身份认证要求,用户返回的证书;

     

     当连接请求要求进行身份认证时,NSURLConnection和NSURLDownload实例的委托协议就是被发送的消息;

        这样就会实现相应的方法,返回正确的证书;

     

     对于NSURLConnectionDelegate协议来说:

        应实现connection:willSendRequestForAuthenticationChallenge:方法;

        我们可以为C11NetConnector类实现这个方法;

     (Code)

     -(void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{
        //使用用户名 密码 创建了一个证书
        NSURLCredential * credential = [NSURLCredential credentialWithUser:@"TestUser" password:@"TestPassword" persistence:NSURLCredentialPersistenceForSession];
        //使用证书回应连接的身份认证质询
        [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
     }

     

     11.6.5 Cookie管理

     

     使用Foundation框架的NSHTTPCookie和NSHTTPCookieStorage类可以创建和管理HTTP Cookie;

        这类Cookie用于永久存储跨URL请求的数据;

        一个NSHTTPCookie实例就代表一个Cookie;

        NSHTTPCookieStorage是一个单例对象,用于管理Cookie;

     

     对于OS X Cookie是公用的,并且由多个进程以同步方式访问;

     对于单个进程来说,会话Cookie是局部的;不会与其他程序共享;

     

     NSHTTPCookie提供的方法:

        可以创建Cookie、将Cookie转换为请求的报头和 获取Cookie属性;

     

     NSHTTPCookieStorage提供的方法:

        使用可以回去公用Cookie的存储实例、管理Cookie接受策略和管理(即添加、删除和获取)Cookie;

     

     11.6.6 协议支持

     

     使用Foundation框架的NSURLProtocol类和NSURLProtocolClient类;

        可以从url加载数据创建自定义协议;

        NSURLProtocol类:

            是一个抽象类,提供了执行协议特定URL加载的基础结构;

            使用其方法可以创建NSURLProtocol对象、注册协议类和取消协议类的注册、管理请求、获取协议特性以及开始和停止下载操作;

        NSURLProtocolClient类:

            是一个由NSURLProtocol类的子类使用的协议,用于与URL加载系统通信;

     

     

     11.7 进程间通信

     

     Foundation框架提供了许多用于进程间通信的类;

        尤其可以创建和使用通信信道;

     

     11.7.1 通过信道通信

     

     NSPipe类可以封装管道(pipe);

        管道是用于在进程间进行通信的单向信道;

        使用其方法可以创建和初始化管道,以及获取管道的想用NSFileHandle实例;

     

     NSTask类(进程)提供了两个方法:

        setStandardOutput:和setStandardInput:,用于设置进程的输入和输出信道;

     

     示例:使用NSPipe和NSTask类,创建并启动一个任务,设置标准输出,然后在任务完成后获取该标准输出并将之写入信道

     (Unix命令/bin/ls仅用于列出当前目录中的文件)

     (Code_11.7.1)

 

    NSTask * task = [[NSTask alloc] init];
     [task setLaunchPath:@"/bin/ls"];
     NSPipe * outPipe = [NSPipe pipe];
     [task setStandardOutput:outPipe];
     [task launch];
     NSData * output = [[outPipe fileHandleForReading] readDataToEndOfFile];
     NSString * lsout = [[NSString alloc] initWithData:output encoding:NSUTF8StringEncoding];
     NSLog(@"/bin/ls output:\n%@",lsout);

     

     log:(由于这个类只能在OS X上使用,所以我们在C11BonjourClient工程中的main函数中,实现如上测试代码)

     C11BonjourClient[30348:9164991] /bin/ls output:

     C11BonjourClient

     

     11.7.2 通过端口通信

     

     NSPort、NSMachPort、MSMessagePort和NSSocketPort类:

        为进程和线程间通信提供了底层机制(通常通过NSPortMessage对象);

     

     NSPort类:

        是一个抽象类;使用其方法可以创建和初始化端口、创建端口连接、设置端口信息和监听端口;

     

     NSMachPort、MSMessagePort和NSSocketPort类:

        是NSPort类的具体子类,用于设置通信端口的类型;

        NSMachPort、MSMessagePort类:

            仅允许进行本地通信(即在同一台设备上);

            此外,NSMachPort类用于Mach端口(OS X中的基础通信端口);

        NSSocketPort类:

            即允许进行本地通信,也允许进行远程通信;(用作本地通信时效率不如专门用于本地通信的类)

     

     在创建NSConnection实例时(使用initWithReceivePort:sendPort:方法),可以将端口实例用作参数;

     还可以通过NSPort类的scheduleInRunLoop:forMode:方法,向运行循环中添加端口;

     

     因为端口是底层的进程间通信机制,所以在实现应用通信时,应在尽可能地使用分布式对象,而只在必要时使用NSPort对象;

     结束对端口对象的操作后,必须使用NSPort类的invalidate方法显示地使对象失效;

     

     11.7.3 端口注册

     

     NSPortNameServer、NSMachBootstrapServer、NSMessagePortNameServer和NSSocketPortNameServer类为端口注册服务提供了接口;

        使用它们可以获取NSMachPort、NSMessagePort和NSSocketPort实例;

     

     NSPortNameServer类为分布式对象系统使用的端口注册服务提供了面向对象的接口;

        NSConnection对象使用该接口相互联系,并将对象分发到网络中;

        直接通过NSPortNameServer实例进行交互的情况极少见;

     

     NSMachBootstrapServer、NSMessagePortNameServer和NSSocketPortNameServer类:

        是NSPortNameServer类的子类;

        它们可以返回相应的端口实例(NSMachPort、MSMessagePort和NSSocketPort);

     

     11.8 小结

     

     本章介绍Foundation框架,专注于为大多数OC程序提供通用功能的类;

     现在熟悉这些类提供的如下功能即可:

     1)网络服务;

     2)应用服务;

     3)文件系统服务;

     4)URL处理;

     5)进程间通信;

     6)并发机制和线程;

     


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值