- 浏览: 237183 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
lanzhiyuan:
楼主还混这里不?NSData *data = [NSURLCo ...
[转] 为UIWebView实现离线浏览 -
hyc4117:
#define OpenSSLRSAPublicKeyFile ...
IOS openssl rsa encrypt/decrypt -
guogongjun:
确实有效,不错,感谢啦大神
[转]安装openfire后admin无法登录管理控制平台 -
xiongyoudou1:
怎么办,而且你那下载的demo和你讲解的不是一样
[转] 为UIWebView实现离线浏览 -
xiongyoudou1:
有问题。执行到方法NSData *data = [NSURLC ...
[转] 为UIWebView实现离线浏览
智能手机的流行让移动运营商们大赚了一笔,然而消费者们却不得不面对可怕的数据流量账单。因为在线看部电影可能要上千块通讯费,比起电影院什么的简直太坑爹了。
所以为了减少流量开销,离线浏览也就成了很关键的功能,而UIWebView这个让人又爱又恨的玩意弱爆了,居然只在Mac OS X上提供webView:resource:willSendRequest:redirectResponse:fromDataSource:这个方法,于是只好自己动手实现了。
原理就是SDK里绝大部分的网络请求都会访问[NSURLCache sharedURLCache]这个对象,它的cachedResponseForRequest:方法会返回一个NSCachedURLResponse对象。如果这个NSCachedURLResponse对象不为nil,且没有过期,那么就使用这个缓存的响应,否则就发起一个不访问缓存的请求。
要注意的是NSCachedURLResponse对象不能被提前释放,除非UIWebView去调用NSURLCache的removeCachedResponseForRequest:方法,原因貌似是UIWebView并不retain这个响应。而这个问题又很头疼,因为UIWebView有内存泄露的嫌疑,即使它被释放了,也很可能不去调用上述方法,于是内存就一直占用着了。
顺便说下NSURLRequest对象,它有个cachePolicy属性,只要其值为NSURLRequestReloadIgnoringLocalCacheData的话,就不会访问缓存。可喜的是这种情况貌似只有在缓存里没取到,或是强制刷新时才可能出现。
实际上NSURLCache本身就有磁盘缓存功能,然而在iOS上,NSCachedURLResponse却被限制为不能缓存到磁盘(NSURLCacheStorageAllowed被视为NSURLCacheStorageAllowedInMemoryOnly)。
不过既然知道了原理,那么只要自己实现一个NSURLCache的子类,然后改写cachedResponseForRequest:方法,让它从硬盘读取缓存即可。
于是就开工吧。这次的demo逻辑比较复杂,因此我就按步骤来说明了。
先定义视图和控制器。
它的逻辑是打开应用时就尝试访问缓存文件,如果发现存在,则显示缓存完毕;否则就尝试下载整个网页的资源;在下载完成后,也显示缓存完毕。
不过下载所有资源需要解析HTML,甚至是JavaScript和CSS。为了简化我就直接用一个不显示的UIWebView载入这个页面,让它自动去发起所有请求。
当然,缓存完了还需要触发事件来显示网页。于是再提供一个按钮,点击时显示缓存的网页,再次点击就关闭。
顺带一提,我本来想用Google为例的,可惜它自己实现了HTML 5离线浏览,也就体现不出这种方法的意义了,于是只好拿百度来垫背。
大部分的代码没什么要说的,随便挑2点。
实现了UIWebViewDelegate,因为需要知道缓存完毕或下载失败这个事件。
另外,正如前面所说的,UIWebView可能不会通知释放缓存。所以在收到内存警告时,如果UIWebView对象已被释放,那么就可以安全地清空缓存了(或许还要考虑多线程的影响)。
接下来就是重点了:实现URLCache类。
它需要2个属性:一个是用于保存NSCachedURLResponse的cachedResponses,另一个是用于保存响应信息的responsesInfo(包括MIME类型和文件名)。
另外还需要实现一个saveInfo方法,用于将responsesInfo保存到磁盘。不过大多数应用应该使用数据库来保存,这里我只是为了简化而已。
写完这些没技术含量的代码后,就来实现saveInfo方法吧。
这里有一个要点需要说下,iTunes会备份所有的应用资料,除非放在Library/Caches或tmp文件夹下。由于缓存并不是什么很重要的用户资料,没必要增加用户的备份时间和空间,所以我们应该把缓存放到这2个文件夹里。而后者会在退出应用或重启系统时清空,这显然不是我们想要的效果,于是最佳选择是前者。
这里我用了stringByAppendingString:方法,更保险的是使用stringByAppendingPathComponent:。不过我估计后者会做更多的检查工作,所以采用了前者。
在实现saveInfo后,初始化方法就也可以实现了。它主要就是载入保存的plist文件,如果不存在则新建一个空的NSMutableDictionary对象。
接下来就可以实现cachedResponseForRequest:方法了。
我们得先判断是不是GET方法,因为其他方法不应该被缓存。还得判断是不是网络请求,例如http、https和ftp,因为连data协议等本地请求都会跑到这个方法里来…
因为没必要处理它们,所以直接交给父类的处理方法了,它会自行决定是否返回nil的。
接着判断是不是已经在cachedResponses里了,这样的话直接拿出来即可:
再查查responsesInfo里有没有,如果有的话,说明可以从磁盘获取:
这里的难点在于构造NSURLResponse和NSCachedURLResponse,不过对照下文档看看也就清楚了。如前文所说,我们还得把cachedResponse保存到cachedResponses里,避免它被提前释放。
接下来就说明缓存不存在了,需要我们自己发起一个请求。可恨的是NSURLResponse不能更改属性,所以还需要手动新建一个NSMutableURLRequest对象:
实际上NSMutableURLRequest还有一些其他的属性,不过并不太重要,所以我就只复制了这2个。
然后就可以用它来发起请求了。由于UIWebView就是在子线程调用cachedResponseForRequest:的,不用担心阻塞的问题,所以无需使用异步请求:
如果下载没出错的话,我们就能拿到data和response了,于是就能将其保存到磁盘了。保存的文件名必须是合法且独一无二的,所以我就用到了sha1算法。
接下来还得将文件信息保存到responsesInfo,并构造一个NSCachedURLResponse。
然而这里还有个陷阱,因为直接使用response对象会无效。我稍微研究了一下,发现它其实是个NSHTTPURLResponse对象,可能是它的allHeaderFields属性影响了缓存策略,导致不能重用。
不过这难不倒我们,直接像前面那样构造一个NSURLResponse对象就行了,这样就没有allHeaderFields属性了:
OK,现在终于大功告成了,打开WIFI然后启动这个程序,过一会就会提示缓存完毕了。然后关掉WIFI,尝试打开网页,你会发现网页能正常载入了。
而查看log,也能发现这确实是从我们的缓存中取出来的。
还不放心的话可以退出程序,这样内存缓存肯定就释放了。然后再次进入并打开网页,你会发现一切仍然正常~
摘自:http://www.keakon.net/2011/08/14/为UIWebView实现离线浏览
你可以还一个网址试试,不要用优酷的。
所以为了减少流量开销,离线浏览也就成了很关键的功能,而UIWebView这个让人又爱又恨的玩意弱爆了,居然只在Mac OS X上提供webView:resource:willSendRequest:redirectResponse:fromDataSource:这个方法,于是只好自己动手实现了。
原理就是SDK里绝大部分的网络请求都会访问[NSURLCache sharedURLCache]这个对象,它的cachedResponseForRequest:方法会返回一个NSCachedURLResponse对象。如果这个NSCachedURLResponse对象不为nil,且没有过期,那么就使用这个缓存的响应,否则就发起一个不访问缓存的请求。
要注意的是NSCachedURLResponse对象不能被提前释放,除非UIWebView去调用NSURLCache的removeCachedResponseForRequest:方法,原因貌似是UIWebView并不retain这个响应。而这个问题又很头疼,因为UIWebView有内存泄露的嫌疑,即使它被释放了,也很可能不去调用上述方法,于是内存就一直占用着了。
顺便说下NSURLRequest对象,它有个cachePolicy属性,只要其值为NSURLRequestReloadIgnoringLocalCacheData的话,就不会访问缓存。可喜的是这种情况貌似只有在缓存里没取到,或是强制刷新时才可能出现。
实际上NSURLCache本身就有磁盘缓存功能,然而在iOS上,NSCachedURLResponse却被限制为不能缓存到磁盘(NSURLCacheStorageAllowed被视为NSURLCacheStorageAllowedInMemoryOnly)。
不过既然知道了原理,那么只要自己实现一个NSURLCache的子类,然后改写cachedResponseForRequest:方法,让它从硬盘读取缓存即可。
于是就开工吧。这次的demo逻辑比较复杂,因此我就按步骤来说明了。
先定义视图和控制器。
它的逻辑是打开应用时就尝试访问缓存文件,如果发现存在,则显示缓存完毕;否则就尝试下载整个网页的资源;在下载完成后,也显示缓存完毕。
不过下载所有资源需要解析HTML,甚至是JavaScript和CSS。为了简化我就直接用一个不显示的UIWebView载入这个页面,让它自动去发起所有请求。
当然,缓存完了还需要触发事件来显示网页。于是再提供一个按钮,点击时显示缓存的网页,再次点击就关闭。
顺带一提,我本来想用Google为例的,可惜它自己实现了HTML 5离线浏览,也就体现不出这种方法的意义了,于是只好拿百度来垫背。
#import <UIKit/UIKit.h> @interface WebViewController : UIViewController <UIWebViewDelegate> { UIWebView *web; UILabel *label; } @property (nonatomic, retain) UIWebView *web; @property (nonatomic, retain) UILabel *label; - (IBAction)click; @end #import "WebViewController.h" #import "URLCache.h" @implementation WebViewController @synthesize web, label; - (IBAction)click { if (web) { [web removeFromSuperview]; self.web = nil; } else { CGRect frame = {{0, 0}, {320, 380}}; UIWebView *webview = [[UIWebView alloc] initWithFrame:frame]; webview.scalesPageToFit = YES; self.web = webview; NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com/"]]; [webview loadRequest:request]; [self.view addSubview:webview]; [webview release]; } } - (void)addButton { CGRect frame = {{130, 400}, {60, 30}}; UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; button.frame = frame; [button addTarget:self action:@selector(click) forControlEvents:UIControlEventTouchUpInside]; [button setTitle:@"我点" forState:UIControlStateNormal]; [self.view addSubview:button]; } - (void)viewDidLoad { [super viewDidLoad]; URLCache *sharedCache = [[URLCache alloc] initWithMemoryCapacity:1024 * 1024 diskCapacity:0 diskPath:nil]; [NSURLCache setSharedURLCache:sharedCache]; CGRect frame = {{60, 200}, {200, 30}}; UILabel *textLabel = [[UILabel alloc] initWithFrame:frame]; textLabel.textAlignment = UITextAlignmentCenter; [self.view addSubview:textLabel]; self.label = textLabel; if (![sharedCache.responsesInfo count]) { // not cached textLabel.text = @"缓存中…"; CGRect frame = {{0, 0}, {320, 380}}; UIWebView *webview = [[UIWebView alloc] initWithFrame:frame]; webview.delegate = self; self.web = webview; NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com/"]]; [webview loadRequest:request]; [webview release]; } else { textLabel.text = @"已从硬盘读取缓存"; [self addButton]; } [sharedCache release]; } - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { self.web = nil; label.text = @"请接通网络再运行本应用"; } - (void)webViewDidFinishLoad:(UIWebView *)webView { self.web = nil; label.text = @"缓存完毕"; [self addButton]; URLCache *sharedCache = (URLCache *)[NSURLCache sharedURLCache]; [sharedCache saveInfo]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; if (!web) { URLCache *sharedCache = (URLCache *)[NSURLCache sharedURLCache]; [sharedCache removeAllCachedResponses]; } } - (void)viewDidUnload { self.web = nil; self.label = nil; } - (void)dealloc { [super dealloc]; [web release]; [label release]; } @end
大部分的代码没什么要说的,随便挑2点。
实现了UIWebViewDelegate,因为需要知道缓存完毕或下载失败这个事件。
另外,正如前面所说的,UIWebView可能不会通知释放缓存。所以在收到内存警告时,如果UIWebView对象已被释放,那么就可以安全地清空缓存了(或许还要考虑多线程的影响)。
接下来就是重点了:实现URLCache类。
它需要2个属性:一个是用于保存NSCachedURLResponse的cachedResponses,另一个是用于保存响应信息的responsesInfo(包括MIME类型和文件名)。
另外还需要实现一个saveInfo方法,用于将responsesInfo保存到磁盘。不过大多数应用应该使用数据库来保存,这里我只是为了简化而已。
#import <Foundation/Foundation.h> @interface URLCache : NSURLCache { NSMutableDictionary *cachedResponses; NSMutableDictionary *responsesInfo; } @property (nonatomic, retain) NSMutableDictionary *cachedResponses; @property (nonatomic, retain) NSMutableDictionary *responsesInfo; - (void)saveInfo; @end #import "URLCache.h" @implementation URLCache @synthesize cachedResponses, responsesInfo; - (void)removeCachedResponseForRequest:(NSURLRequest *)request { NSLog(@"removeCachedResponseForRequest:%@", request.URL.absoluteString); [cachedResponses removeObjectForKey:request.URL.absoluteString]; [super removeCachedResponseForRequest:request]; } - (void)removeAllCachedResponses { NSLog(@"removeAllObjects"); [cachedResponses removeAllObjects]; [super removeAllCachedResponses]; } - (void)dealloc { [cachedResponses release]; [responsesInfo release]; } @end
写完这些没技术含量的代码后,就来实现saveInfo方法吧。
这里有一个要点需要说下,iTunes会备份所有的应用资料,除非放在Library/Caches或tmp文件夹下。由于缓存并不是什么很重要的用户资料,没必要增加用户的备份时间和空间,所以我们应该把缓存放到这2个文件夹里。而后者会在退出应用或重启系统时清空,这显然不是我们想要的效果,于是最佳选择是前者。
static NSString *cacheDirectory; + (void)initialize { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); cacheDirectory = [[paths objectAtIndex:0] retain]; } - (void)saveInfo { if ([responsesInfo count]) { NSString *path = [cacheDirectory stringByAppendingString:@"responsesInfo.plist"]; [responsesInfo writeToFile:path atomically: YES]; } }
这里我用了stringByAppendingString:方法,更保险的是使用stringByAppendingPathComponent:。不过我估计后者会做更多的检查工作,所以采用了前者。
在实现saveInfo后,初始化方法就也可以实现了。它主要就是载入保存的plist文件,如果不存在则新建一个空的NSMutableDictionary对象。
- (id)initWithMemoryCapacity:(NSUInteger)memoryCapacity diskCapacity:(NSUInteger)diskCapacity diskPath:(NSString *)path { if (self = [super initWithMemoryCapacity:memoryCapacity diskCapacity:diskCapacity diskPath:path]) { cachedResponses = [[NSMutableDictionary alloc] init]; NSString *path = [cacheDirectory stringByAppendingString:@"responsesInfo.plist"]; NSFileManager *fileManager = [[NSFileManager alloc] init]; if ([fileManager fileExistsAtPath:path]) { responsesInfo = [[NSMutableDictionary alloc] initWithContentsOfFile:path]; } else { responsesInfo = [[NSMutableDictionary alloc] init]; } [fileManager release]; } return self; }
接下来就可以实现cachedResponseForRequest:方法了。
我们得先判断是不是GET方法,因为其他方法不应该被缓存。还得判断是不是网络请求,例如http、https和ftp,因为连data协议等本地请求都会跑到这个方法里来…
static NSSet *supportSchemes; + (void)initialize { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); cacheDirectory = [[paths objectAtIndex:0] retain]; supportSchemes = [[NSSet setWithObjects:@"http", @"https", @"ftp", nil] retain]; } - (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request { if ([request.HTTPMethod compare:@"GET"] != NSOrderedSame) { return [super cachedResponseForRequest:request]; } NSURL *url = request.URL; if (![supportSchemes containsObject:url.scheme]) { return [super cachedResponseForRequest:request]; } //... }
因为没必要处理它们,所以直接交给父类的处理方法了,它会自行决定是否返回nil的。
接着判断是不是已经在cachedResponses里了,这样的话直接拿出来即可:
NSString *absoluteString = url.absoluteString; NSLog(@"%@", absoluteString); NSCachedURLResponse *cachedResponse = [cachedResponses objectForKey:absoluteString]; if (cachedResponse) { NSLog(@"cached: %@", absoluteString); return cachedResponse; }
再查查responsesInfo里有没有,如果有的话,说明可以从磁盘获取:
NSDictionary *responseInfo = [responsesInfo objectForKey:absoluteString]; if (responseInfo) { NSString *path = [cacheDirectory stringByAppendingString:[responseInfo objectForKey:@"filename"]]; NSFileManager *fileManager = [[NSFileManager alloc] init]; if ([fileManager fileExistsAtPath:path]) { [fileManager release]; NSData *data = [NSData dataWithContentsOfFile:path]; NSURLResponse *response = [[NSURLResponse alloc] initWithURL:request.URL MIMEType:[responseInfo objectForKey:@"MIMEType"] expectedContentLength:data.length textEncodingName:nil]; cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data]; [response release]; [cachedResponses setObject:cachedResponse forKey:absoluteString]; [cachedResponse release]; NSLog(@"cached: %@", absoluteString); return cachedResponse; } [fileManager release]; }
这里的难点在于构造NSURLResponse和NSCachedURLResponse,不过对照下文档看看也就清楚了。如前文所说,我们还得把cachedResponse保存到cachedResponses里,避免它被提前释放。
接下来就说明缓存不存在了,需要我们自己发起一个请求。可恨的是NSURLResponse不能更改属性,所以还需要手动新建一个NSMutableURLRequest对象:
NSMutableURLRequest *newRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:request.timeoutInterval]; newRequest.allHTTPHeaderFields = request.allHTTPHeaderFields; newRequest.HTTPShouldHandleCookies = request.HTTPShouldHandleCookies;
实际上NSMutableURLRequest还有一些其他的属性,不过并不太重要,所以我就只复制了这2个。
然后就可以用它来发起请求了。由于UIWebView就是在子线程调用cachedResponseForRequest:的,不用担心阻塞的问题,所以无需使用异步请求:
NSError *error = nil; NSURLResponse *response = nil; NSData *data = [NSURLConnection sendSynchronousRequest:newRequest returningResponse:&response error:&error]; if (error) { NSLog(@"%@", error); NSLog(@"not cached: %@", absoluteString); return nil; }
如果下载没出错的话,我们就能拿到data和response了,于是就能将其保存到磁盘了。保存的文件名必须是合法且独一无二的,所以我就用到了sha1算法。
uint8_t digest[CC_SHA1_DIGEST_LENGTH]; CC_SHA1(data.bytes, data.length, digest); NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2]; for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) [output appendFormat:@"%02x", digest[i]]; NSString *filename = output;//sha1([absoluteString UTF8String]); NSString *path = [cacheDirectory stringByAppendingString:filename]; NSFileManager *fileManager = [[NSFileManager alloc] init]; [fileManager createFileAtPath:path contents:data attributes:nil]; [fileManager release];
接下来还得将文件信息保存到responsesInfo,并构造一个NSCachedURLResponse。
然而这里还有个陷阱,因为直接使用response对象会无效。我稍微研究了一下,发现它其实是个NSHTTPURLResponse对象,可能是它的allHeaderFields属性影响了缓存策略,导致不能重用。
不过这难不倒我们,直接像前面那样构造一个NSURLResponse对象就行了,这样就没有allHeaderFields属性了:
NSURLResponse *newResponse = [[NSURLResponse alloc] initWithURL:response.URL MIMEType:response.MIMEType expectedContentLength:data.length textEncodingName:nil]; responseInfo = [NSDictionary dictionaryWithObjectsAndKeys:filename, @"filename", newResponse.MIMEType, @"MIMEType", nil]; [responsesInfo setObject:responseInfo forKey:absoluteString]; NSLog(@"saved: %@", absoluteString); cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:newResponse data:data]; [newResponse release]; [cachedResponses setObject:cachedResponse forKey:absoluteString]; [cachedResponse release]; return cachedResponse;
OK,现在终于大功告成了,打开WIFI然后启动这个程序,过一会就会提示缓存完毕了。然后关掉WIFI,尝试打开网页,你会发现网页能正常载入了。
而查看log,也能发现这确实是从我们的缓存中取出来的。
还不放心的话可以退出程序,这样内存缓存肯定就释放了。然后再次进入并打开网页,你会发现一切仍然正常~
摘自:http://www.keakon.net/2011/08/14/为UIWebView实现离线浏览
- CacheDemo.zip (27.5 KB)
- 下载次数: 369
评论
6 楼
lanzhiyuan
2015-06-04
楼主还混这里不?
NSData *data = [NSURLConnection sendSynchronousRequest:newRequest
returningResponse:&response error:&error];就卡住了,是不是iOS6或者7之后sdk有变化?
NSData *data = [NSURLConnection sendSynchronousRequest:newRequest
returningResponse:&response error:&error];就卡住了,是不是iOS6或者7之后sdk有变化?
5 楼
xiongyoudou1
2012-12-13
怎么办,而且你那下载的demo和你讲解的不是一样
4 楼
xiongyoudou1
2012-12-13
有问题。
执行到方法NSData *data = [NSURLConnection sendSynchronousRequest:newRequest
returningResponse:&response error:&error];时,程序就卡死
执行到方法NSData *data = [NSURLConnection sendSynchronousRequest:newRequest
returningResponse:&response error:&error];时,程序就卡死
3 楼
re_reference
2012-03-21
wtthappy 写道
demo好像问题很多呀,关掉wifi,退出程序,再点开程序,直接卡死
你可以还一个网址试试,不要用优酷的。
2 楼
re_reference
2012-03-21
wtthappy 写道
demo好像问题很多呀,关掉wifi,退出程序,再点开程序,直接卡死
引用
恩,在处理数据那一块比较慢。加上文件有点多,但跟缓存没关系。
1 楼
wtthappy
2012-03-20
demo好像问题很多呀,关掉wifi,退出程序,再点开程序,直接卡死
发表评论
-
ios 开发技术
2015-01-09 11:59 747引用 主题:xcode 6制作动态&静态库 连接:ht ... -
ios 错误合集(updated!)
2015-01-09 11:57 804引用 错误:dyld: Library not loaded ... -
几个不错的xcode插件
2014-09-11 13:33 63461、代码补全插件 http://alcatraz.io 2、 ... -
xcode 插件目录
2014-09-11 13:14 461~/Library/Application\ Suppor ... -
GCD 倒计时
2014-08-19 10:00 1017-(void)startTime{ __bloc ... -
Eventkit使用案例
2014-02-15 16:06 3209- (void)createNewEventAndNewR ... -
ios 应用内跳转到系统设置界面的最好写法
2013-04-24 11:43 10174如下是跳转到系统设置诸多界面的url prefs:roo ... -
beeframework "___gxx_personality_sj0", referenced from:错误解决
2013-04-17 13:50 1844到Bee_Precompile.h 找到如下一行: #de ... -
pod update/install git pull 443错误解决
2013-01-22 18:38 2355自从12306.cn抢票插件搞爆github服务器以后,我就再 ... -
[转]如何编写一个CocoaPods的spec文件
2012-12-27 16:25 14316本文转自http://ishalou.com/blog/201 ... -
[转]How to use NSAttributedString in iOS 6
2012-12-25 16:09 2628本文转自:http://soulwithmobiletechn ... -
mac上的小工具(updated)
2012-12-24 18:05 1033mac上显示隐藏文件的命令,如果要隐藏则 -bool fals ... -
github README.md 编辑技巧小结 (updated)
2012-12-18 11:39 20751.文字连接 [文字](http://ace.ajax.org ... -
iOS 怎样更方便使用第三方框架
2012-11-29 12:45 1618管理第三方库越来越成为每个程序员的基本工作,因为每次都要去加入 ... -
CocoaPods:管理 Objective-C 專案裡頭各種 Library 關聯性最棒的方式
2012-11-26 14:53 1049介绍: 开发应用的时候第三方的库是不可缺少的,它能提高开发的 ... -
转载:用HTML5/CSS3/JS开发Android/IOS应用框架大全
2012-11-22 15:16 1276现在,用js调用本地代码已经不是一件新鲜事,已经有成熟的库来做 ... -
core data 分页查询
2012-11-07 11:26 1542NSFetchRequest *request = [[N ... -
[转]从Flurry导出数据
2012-10-17 10:51 1194有时我们需要一些详细 ... -
AFNetworking multipart upload
2012-10-12 14:52 5451+ (NSDictionary*)parametersOf ... -
IOS openssl rsa encrypt/decrypt
2012-09-29 15:15 6398对OpenSSL RSA加解密的封 ...
相关推荐
UIWebView不仅能够实时加载网络页面,还可以实现离线缓存功能,使得用户在没有网络连接时依然可以查看之前加载过的网页内容。这个特性对于提高用户体验,特别是对于那些在网络不稳定或者无网络环境下的应用来说,...
实现 UIWebView 的离线浏览(缓存)功能。 作者说: 原理:将get请求的数据缓存在本地cache目录中,以后访问的时候直接从cache中获取数据。 备注:在初始化缓存的时候可以指定缓存的有效期时间长度,具体参看...
系统默认会进行一定的缓存处理,但这种缓存机制对于离线浏览可能并不足够。为了解决这个问题,我们可以自定义URLProtocol,实现更精细的缓存控制。 【RNCachingURLProtocol-master】这个压缩包可能包含了一个名为`...
"webViewDemo:网易新闻中新闻详情页UIWebView的实现" 这个标题揭示了我们讨论的主题是一个iOS应用开发项目,名为“webViewDemo”,它专注于模仿网易新闻应用中的新闻详情页面。这个页面的实现是通过使用UIWebView...
这个名为"IOS应用源码——UIWebViewBrowse 2.rar"的压缩包可能包含了一个基于UIWebView实现的简单浏览器应用的完整源代码。UIWebViewBrowse 2很可能是该应用的第二个版本,意味着开发者可能对原始版本进行了一些改进...
在压缩包文件`sylverb-CIALBrowser-66a115a`中,可能包含了一个名为CIALBrowser的项目源码,你可以从中学习到实际的代码实现,包括如何组织控制器、界面布局以及与UIWebView的交互。通过对这个项目的分析和学习,你...
为了支持离线浏览,开发者需要在用户在线时将网页内容存入本地,这涉及到SQLite数据库或本地文件系统的使用。一种常见方法是使用HTML5的App Cache特性,通过manifest文件指定需要缓存的资源。 五、优化策略 1. 设置...
本项目名为“ZAKER风格主界面实现”,旨在模仿知名新闻阅读应用ZAKER的主界面设计,让用户在自己的应用中也能享受到类似的浏览、操作体验。我们将探讨这个项目涉及到的关键知识点,包括界面设计原则、布局管理、触摸...
除了基本的加载网页和下载功能,你可能还需要实现其他高级特性,比如注入JavaScript代码、拦截请求、自定义证书处理、支持离线缓存等。这些可以通过WKWebView的`evaluateJavaScript`、`setCustomUserAgent`、`...
最后,考虑到用户体验,我们还需要实现一些额外的功能,如进度条显示加载状态,添加分享、收藏和评论按钮,以及提供离线阅读的可能性。这些可以通过集成社交平台的SDK,或者利用SQLite数据库存储已下载的内容来实现...
`WKWebView`是Apple提供的一个强大的浏览引擎,替代了旧版的`UIWebView`,在性能、安全性和能耗上都有显著提升。下面我们将深入探讨`PFWebViewController`的实现细节以及`WKWebView`的相关知识。 1. **WKWebView...
此外,为了实现离线缓存或者提高加载速度,可能还会涉及到`NSCache`和本地存储机制。 对于用户交互,iOS提供了多种手势识别器(如`UIPanGestureRecognizer`, `UIPinchGestureRecognizer`等),这些都可以在源码中...
对于复杂的应用,可能还需要实现离线缓存、预加载策略等功能,以提升用户体验。 总的来说,`TOWebViewController`是一个实用的工具,它简化了在iOS应用中集成网页浏览功能的过程,同时保持了`WKWebView`的良好性能...
通过学习这份源码,开发者不仅可以掌握如何在iOS应用中实现网页缓存,还能了解到如何优化网络请求,提升应用性能,以及如何处理离线浏览场景。这是一个很好的实践案例,对于iOS开发者来说,尤其是对网络编程和性能...
- **HTML5离线化**:通过HTML5的离线存储技术如Application Cache (AppCache)、IndexedDB、Web SQL、File API等,实现应用的离线运行和数据存储。 - **混合式开发**:介绍ReactNative、小程序、Flutter等混合式开发...
相比旧版的UIWebView,WKWebView提供了更好的性能和安全性,同时对现代Web标准有更好的支持。"NewNXYTDemo.zip"这个压缩包可能包含了一个示例项目,演示了如何在iOS应用中使用WKWebView来加载和缓存网页数据。 首先...
在iOS开发中,"PagingScrollWithWebView"通常是指一种技术,它结合了分页滚动效果和WebView的使用,主要用于创建类似Apple的“新闻”或“图书”应用那样的多页面浏览体验。在这个场景中,"iphone ipad"表示该技术既...
在iOS中,这通常通过UIWebView或WKWebView来实现。UIWebView是较早的选项,但WKWebView自iOS 8引入后,由于其更好的性能和安全性,逐渐成为首选。此项目可能使用了其中一种或两者结合的方式。 2. **导航控制**:...
其次,可以通过扩展PBWebViewController类来添加自定义的功能,例如添加分享按钮、实现页面的离线缓存或是集成自定义的JavaScript接口。此外,PBWebViewController还支持URL过滤和拦截,这对于需要限制用户访问特定...