NSURL 基本方法 absoluteString

本文通过一个具体的NSURL实例,详细解析了其各个属性的意义及获取方法,包括scheme、host、absoluteString等,有助于理解NSURL如何表示和处理URL。

转载自:http://my.oschina.net/wangdk/blog/165554       


  NSURL *url = [NSURL URLWithString:@"http://www.baidu.com/search?id=1"];

2     NSLog(@"scheme:%@", [url scheme]); //协议 http
3     NSLog(@"host:%@", [url host]);     //域名 www.baidu.com
4     NSLog(@"absoluteString:%@", [url absoluteString]); //完整的url字符串 http://www.baidu.com:8080/search?id=1
  (刚才在真机上跑了一下,并没有打印出来端口 8080 啊)
5     NSLog(@"relativePath: %@", [url relativePath]); //相对路径 search
6     NSLog(@"port :%@", [url port]);  // 端口 8080
7     NSLog(@"path: %@", [url path]);  // 路径 search
8     NSLog(@"pathComponents:%@", [url pathComponents]); // search
9     NSLog(@"Query:%@", [url query]);  //参数 id=1
<think> 我们正在开发一个类似浏览器的iOS应用,使用Xcode和Objective-C语言。主要功能包括: 1. 请求网站并获取数据(可能是HTML、图片等)。 2. 将获取的数据缓存到本地(以便下次快速加载或离线使用)。 3. 展示缓存的数据(当没有网络时,或者用户选择查看缓存时)。 根据引用[2]的内容,我们知道在iOS开发中本地数据存储有几种方式。考虑到我们需要缓存网页数据(可能包括文本、图片等),我们可以选择以下几种存储方式: - 使用文件系统存储:将整个网页保存为HTML文件,图片等资源保存在文件夹中。 - 使用数据库(如SQLite或Core Data):适合结构化存储,但网页数据通常是半结构化或非结构化的,所以文件存储可能更直接。 - 使用NSUserDefaults:只适合存储小量数据,不适合网页缓存。 - 使用Plist文件:引用[2]提到它适合固态数据,不适合频繁改动,而我们的缓存需要频繁更新,所以不太合适。 因此,我们选择使用文件系统来存储缓存。具体步骤: 1. 发起网络请求获取网页数据(使用NSURLSession)。 2. 将获取的数据(HTML、图片等)保存到应用的缓存目录(Cache目录)或文档目录(Document目录)。 - 缓存目录:系统可能会在空间不足时清理,适合临时缓存。 - 文档目录:需要持久保存的数据,不会被系统清理。 3. 当需要展示网页时,先检查是否有缓存,如果有则从缓存加载,否则再发起网络请求。 另外,我们还需要一个机制来管理缓存,例如: - 缓存文件命名:使用URL的MD5值作为文件名,避免非法字符。 - 缓存过期策略:可以设置缓存有效期,超过有效期则重新请求。 下面我们设计主要的实现步骤: ### 1. 网络请求与数据获取 使用NSURLSession发起请求,获取数据。 ### 2. 缓存数据 将获取的数据(NSData)写入到缓存目录中。 ### 3. 加载缓存 当需要加载网页时,先检查缓存目录中是否存在对应的缓存文件,如果存在则读取并展示。 ### 4. 展示网页 使用UIWebView或WKWebView来展示网页。注意:如果网页中有图片等资源,我们需要确保这些资源也被缓存,并且网页中引用的路径指向本地缓存。 但是,网页中的资源(如图片、CSS、JS)是相对路径,直接加载本地HTML文件可能无法正确加载这些资源。因此,我们需要: - 将整个网页(包括所有资源)下载并保存到本地的一个文件夹中,然后修改HTML文件中资源路径为本地路径。 - 或者,我们可以使用WKWebView的离线加载机制(例如,使用NSURLProtocol拦截请求并返回缓存数据)。但这种方法较为复杂。 为了简化,我们这里采用第一种方式:当我们请求一个网页时,我们并不只是保存HTML文件,而是需要解析HTML,然后下载其中引用的资源(图片、CSS等)。但这实际上是一个复杂的网页抓取和离线保存过程,对于简单的浏览器应用来说,可能过于复杂。 另一种更简单的方式:使用WKWebView的内置缓存(NSURLCache)来管理。但是,系统默认的缓存策略可能不够持久(例如,应用退出后缓存可能被清除,或者空间不足时会被清除)。所以,我们需要自定义缓存。 考虑到复杂度,我们这里先实现只缓存HTML文本,而不缓存资源。这样,当离线加载时,图片等资源可能无法显示。但是,我们可以后续再扩展。 因此,我们分两步走: 第一步:只缓存HTML文本,离线时只显示文字(图片等资源可能显示占位符)。 第二步:后续再考虑完整离线缓存。 ### 实现代码框架 #### 网络请求与缓存管理类 我们将创建一个网络请求管理类,负责请求和缓存。 ```objectivec // NetworkManager.h #import <Foundation/Foundation.h> typedef void (^CompletionHandler)(NSData *data, NSError *error); @interface NetworkManager : NSObject + (instancetype)sharedManager; - (void)loadURL:(NSURL *)url completion:(CompletionHandler)completion; @end ``` ```objectivec // NetworkManager.m #import "NetworkManager.h" @interface NetworkManager () @property (nonatomic, strong) NSURLSession *session; @end @implementation NetworkManager + (instancetype)sharedManager { static NetworkManager *sharedInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [[self alloc] init]; }); return sharedInstance; } - (instancetype)init { self = [super init]; if (self) { NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; _session = [NSURLSession sessionWithConfiguration:config]; } return self; } - (void)loadURL:(NSURL *)url completion:(CompletionHandler)completion { // 先尝试从缓存读取 NSData *cachedData = [self loadCachedDataForURL:url]; if (cachedData) { completion(cachedData, nil); return; } // 没有缓存则发起网络请求 NSURLSessionDataTask *task = [self.session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (error) { completion(nil, error); return; } // 缓存数据 [self saveData:data forURL:url]; dispatch_async(dispatch_get_main_queue(), ^{ completion(data, nil); }); }]; [task resume]; } // 获取缓存路径 - (NSString *)cachePathForURL:(NSURL *)url { NSString *filename = [url.absoluteString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet alphanumericCharacterSet]]; NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject]; return [path stringByAppendingPathComponent:filename]; } // 读取缓存数据 - (NSData *)loadCachedDataForURL:(NSURL *)url { NSString *filePath = [self cachePathForURL:url]; return [NSData dataWithContentsOfFile:filePath]; } // 保存数据到缓存 - (void)saveData:(NSData *)data forURL:(NSURL *)url { NSString *filePath = [self cachePathForURL:url]; [data writeToFile:filePath atomically:YES]; } @end ``` #### 在ViewController中使用 我们使用WKWebView来展示网页。注意:这里我们加载的是NSData数据(即HTML字符串),所以需要使用webView的loadHTMLString:baseURL:方法。但是,由于我们没有缓存资源,所以baseURL设置为原始URL,这样在联网情况下,资源还是可以加载;离线时,资源则无法加载。 ```objectivec // ViewController.m #import "ViewController.h" #import <WebKit/WebKit.h> #import "NetworkManager.h" @interface ViewController () @property (nonatomic, strong) WKWebView *webView; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds]; [self.view addSubview:self.webView]; // 示例:加载百度 NSURL *url = [NSURL URLWithString:@"https://www.baidu.com"]; [[NetworkManager sharedManager] loadURL:url completion:^(NSData *data, NSError *error) { if (error) { NSLog(@"Error: %@", error.localizedDescription); return; } NSString *htmlString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; [self.webView loadHTMLString:htmlString baseURL:url]; }]; } @end ``` ### 说明 1. 我们只缓存了原始的HTML数据,没有处理其中的资源(图片、CSS等)。因此离线时,这些资源无法加载(会显示破损的图片或没有样式)。 2. 缓存的文件名使用URL的绝对字符串进行百分号编码,避免了非法字符,但同一个URL多次请求会覆盖之前的缓存。 ### 后续优化方向 1. 完整缓存:下载网页中的所有资源并修改HTML中的链接指向本地文件。这需要解析HTML,下载所有资源,并修改路径。 2. 缓存过期:可以给每个缓存文件设置一个过期时间,在加载缓存时检查是否过期。 3. 缓存清理:当缓存过大时,清理旧缓存。 以上是一个基础的实现。如果需要完整离线缓存,可以考虑使用第三方库(例如,SDWebImage缓存图片,但针对整个网页的离线缓存可能需要更复杂的方案),或者使用iOS 11+的WKWebView的离线缓存功能(WKWebsiteDataStore)。 由于用户要求使用OC,我们使用Objective-C编写。 §§相关问题§§ 1. 如何优化上述缓存机制以实现完整的离线浏览(包括图片等资源)? 2. 如何设置缓存的有效期并自动清理过期缓存? 3. 在iOS开发中,除了文件缓存,还有哪些适合存储网页数据的缓存方式? 4. 如何防止缓存占用过多磁盘空间? </think> ### 使用Xcode和OC开发类浏览器App的数据缓存与展示方案 以下是实现数据缓存及展示功能的完整步骤: #### 1. 网络请求与数据获取 使用NSURLSession发起网络请求,获取网页数据: ```objectivec - (void)fetchDataFromURL:(NSURL *)url { NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (data) { // 缓存数据 [self cacheResponseData:data forURL:url]; // 展示数据 dispatch_async(dispatch_get_main_queue(), ^{ [self displayCachedData:data]; }); } }]; [task resume]; } ``` #### 2. 数据缓存实现 在Documents目录创建缓存文件,使用URL的MD5值作为文件名: ```objectivec - (void)cacheResponseData:(NSData *)data forURL:(NSURL *)url { // 获取缓存路径 NSString *cacheDir = [NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; // 生成唯一文件名 (使用URL的MD5) NSString *filename = [self md5Hash:url.absoluteString]; NSString *filePath = [cacheDir stringByAppendingPathComponent:filename]; // 写入文件 [data writeToFile:filePath atomically:YES]; } // MD5哈希生成方法 - (NSString *)md5Hash:(NSString *)input { const char *ptr = [input UTF8String]; unsigned char md5Buffer[CC_MD5_DIGEST_LENGTH]; CC_MD5(ptr, (CC_LONG)strlen(ptr), md5Buffer); NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2]; for(int i=0; i<CC_MD5_DIGEST_LENGTH; i++) [output appendFormat:@"%02x", md5Buffer[i]]; return output; } ``` #### 3. 读取缓存数据 ```objectivec - (NSData *)getCachedDataForURL:(NSURL *)url { NSString *filename = [self md5Hash:url.absoluteString]; NSString *filePath = [[NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:filename]; return [NSData dataWithContentsOfFile:filePath]; } ``` #### 4. 数据展示方案 使用WKWebView展示缓存的HTML内容: ```objectivec - (void)displayCachedData:(NSData *)data { WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds]; [webView loadData:data MIMEType:@"text/html" characterEncodingName:@"UTF-8" baseURL:nil]; [self.view addSubview:webView]; } ``` #### 5. 缓存管理优化 添加缓存过期机制: ```objectivec // 保存时记录时间戳 NSDictionary *metadata = @{ @"lastUpdated": [NSDate date], @"url": url.absoluteString }; [metadata writeToFile:[filePath stringByAppendingString:@".meta"] atomically:YES]; // 检查是否过期(例如30天) - (BOOL)isCacheValid:(NSString *)filePath { NSString *metaPath = [filePath stringByAppendingString:@".meta"]; NSDictionary *meta = [NSDictionary dictionaryWithContentsOfFile:metaPath]; NSDate *lastUpdated = meta[@"lastUpdated"]; return [[NSDate date] timeIntervalSinceDate:lastUpdated] < 30*24*3600; } ``` ### 关键组件说明 1. **缓存策略**: - 使用文件系统存储原始数据 - URL的MD5哈希值作为唯一文件名 - 文档目录存储确保数据持久化 2. **数据加载流程**: ```mermaid graph TD A[用户请求URL] --> B{检查缓存} B -->|存在缓存| C[读取本地文件] B -->|无缓存| D[发起网络请求] D --> E[保存到缓存] C & E --> F[WKWebView渲染] ``` 3. **缓存管理**: - 添加metadata文件记录缓存时间 - 实现LRU(最近最少使用)清理策略 - 设置最大缓存尺寸(如100MB) ### 注意事项 1. 需要在`Info.plist`中配置ATS确保HTTP请求权限: ```xml <key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict> ``` 2. 大文件缓存建议使用`NSFileHandle`分块读写 3. 图片等二进制资源缓存可使用`NSCache`做内存缓存优化 此方案实现了基本的网络请求→数据缓存→离线展示流程,后续可扩展为完整的离线浏览器应用[^1][^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值