您的位置:首页 > 移动开发 > IOS开发

iOS缓存方案

2016-01-11 17:21 459 查看
App已经与我们形影不离了,不管在地铁上、公交上还是在会场你总能看到很多人拿出来手机,刷一刷微博,看看新闻。

据不完全统计有近一半的用户在非Wifi环境打开App,以下为一个典型iPhone和AndroidApp(50W+用户)的友盟后台数据:

3G、2G的数据连接往往不稳定(特别在公交或者地铁上),这时打开一些App就会像这样:

当然也会有一些体验很好的App,在离线状态下也能顺畅使用:

甚至提供了离线阅读功能:

如何做?

打开过的文章、下载过的音频、查看过的图片我们都希望Cache到本地,下次不用再向服务器请求。

首先,我们为了最快让用户看到内容,会在ViewDidLoad加载Cache数据,如:

?
1

2

3

4
-
(
void
)viewDidLoad
{


[self
getArticleList:0length:SECTION_LENGTHuseCacheFirst:YES];


}


然后在viewDidAppear中向服务器请求最新数据,如

?
1

2

3

4

5

6

7

8
-
(
void
)viewDidAppear:(
BOOL
)animated
{




[super
viewDidAppear:animated];


//...


[self
getArticleList:0length:SECTION_LENGTHuseCacheFirst:NO]


}


当然这里的getArticleList接口有useCacheFirst参数,我们需要网络请求模块能够支持这一点,下面就介绍这些库和工具。(借助一些工具很容易能做到这些,而不用自己造轮子。遵循“凡事都应该最简单,而不过于简陋”的原则,这里整理一下,方便项目中使用)。


1.NSMutableURLRequest

Sample(参考麒麟的文章《iOS开发之缓存(一):内存缓存》来使用NSURLCache):

?
1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32
NSString
*paramURLAsString=@
"http://www.baidu.com/"
;


if
([paramURLAsString
length]==0){


NSLog(@
"Nil
oremptyURLisgiven"
);


return
;


}


NSURLCache
*urlCache=[NSURLCachesharedURLCache];


/*
设置缓存的大小为1M*/


[urlCache
setMemoryCapacity:1*1024*1024];


//创建一个nsurl


NSURL
*url=[NSURLURLWithString:paramURLAsString];


//创建一个请求


NSMutableURLRequest
*request=


[NSMutableURLRequest


requestWithURL:url


cachePolicy:NSURLRequestUseProtocolCachePolicy


timeoutInterval:60.0f];


//从请求中获取缓存输出


NSCachedURLResponse
*response=


[urlCache
cachedResponseForRequest:request];


//判断是否有缓存


if
(response
!=nil){


NSLog(@
"如果有缓存输出,从缓存中获取数据"
);


[request
setCachePolicy:NSURLRequestReturnCacheDataDontLoad];


}


self.connection
=nil;


/*
创建NSURLConnection*/


NSURLConnection
*newConnection=


[[NSURLConnection
alloc]initWithRequest:request


delegate:self


startImmediately:YES];


self.connection
=newConnection;


[newConnection
release];


但是NSMutableURLRequest使用起来不够简便,在实际项目中我很少用它,而基本使用ASIHTTPRequest来代替。


2.ASIHTTPRequest

你可以从这里找到它的介绍:http://allseeing-i.com/ASIHTTPRequest/,在5.0/4.0及之前iOS版本,ASIHTTPRequest基本是主力的
HTTPrequestslibrary,它本身也是Github中的开源项目,但是从iOS5.0之后逐渐停止维护了。未来的项目可以使用AFNetworking或者MKNetworkKit代替ASIHTTPRequest。

ASIHTTPRequest的简介如下:

ASIHTTPRequestisaneasytousewrapperaroundtheCFNetworkAPIthatmakessomeofthemoretediousaspectsofcommunicatingwithwebserverseasier.ItiswritteninObjective-CandworksinbothMacOSXandiPhoneapplications.

ItissuitableperformingbasicHTTPrequestsandinteractingwithREST-basedservices(GET/POST/PUT/DELETE).TheincludedASIFormDataRequestsubclassmakesiteasytosubmitPOSTdataandfilesusingmultipart/form-data.

ASIHTTPRequest库API设计的简单易用,并且支持block、queue、gzip等丰富的功能,这是该开源项目如此受欢迎的主要原因。

ASIHTTPRequest库中提供了ASIWebPageRequest组件用于请求网页,并且能把网页中的外部资源一并请求下来,但是我在实际项目中使用后发现有严重Bug,所以不建议使用。

ASIHTTPRequest库的介绍中也提到了它可以支持REST-basedservice,但是与RestfullAPI打交道我们往往使用下面介绍的的RestKit。

Sample:

?
1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40
NSMutableString
*requestedUrl=[[NSMutableStringalloc]initWithString:self.url];


//如果优先使用本地数据


ASICachePolicy
policy=_useCacheFirst?ASIOnlyLoadIfNotCachedCachePolicy


:
(ASIAskServerIfModifiedCachePolicy|ASIFallbackToCacheIfLoadFailsCachePolicy);


asiRequest
=[ASIHTTPRequestrequestWithURL:


[NSURL
URLWithString:[requestedUrlstringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];


[asiRequest
setDownloadCache:[ASIDownloadCachesharedCache]];


[asiRequest
setCachePolicy:policy];


[asiRequest
setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];


//
Connection


if
(_connectionType
==ConnectionTypeAsynchronously){




[asiRequest
setDelegate:self];


[asiRequest
startAsynchronous];




//
Tellwe'rereceiving.


if
(!_canceled
&&[_delegaterespondsToSelector:@selector(downloaderDidStart:)])


[_delegate
downloaderDidStart:self];


}


else


{


[asiRequest
startSynchronous];




NSError
*error=[asiRequesterror];




if
(!error)


{


[self
requestFinished:asiRequest];


}


else


{


[self
requestFailed:asiRequest];


}


}


[requestedUrl
release];



3.RestKit

官方网站:http://restkit.org/,Github开源项目,与RestfullAPI的Web服务打交道,这个库非常便捷,它也提供了很完整的Cache机制。

Sample:

?
1

2

3

4

5

6

7

8

9

10

11

12
+
(
void
)setCachePolicy:(
BOOL
)useCacheFirst


{


RKObjectManager*
objectManager=[RKObjectManagersharedManager];




if
(useCacheFirst)
{


objectManager.client.cachePolicy
=RKRequestCachePolicyEnabled;
//使用本地Cache,如果没有Cache请求服务器


}


else


{


objectManager.client.cachePolicy
=RKRequestCachePolicyLoadIfOffline|RKRequestCachePolicyTimeout;
//离线或者超时时使用本地Cache


}


}


?
1

2

3

4

5

6

7

8

9

10

11

12
+
(
BOOL
)getHomeTimeline:(NSInteger)maxId


length:(NSInteger)length


delegate:(id<RKObjectLoaderDelegate>)delegate


useCacheFirst:(
BOOL
)useCacheFirst


{


if
(delegate
==nil)


return
NO;




[iKnowAPI
setCachePolicy:useCacheFirst];


//...


}


Cache请求只是RestKit最基本的功能,RestKit真正强大的地方在于处理与RESTfulwebservices交互时的相关工作非常简便(https://github.com/RestKit/RestKit/wiki),RestKit还可以Cache
datamodel到CoreData中:

CoreDatasupport.Buildingontopoftheobjectmappinglayer,RestKitprovidesintegrationwithApple'sCoreDataframework.ThissupportallowsRestKittopersistremotelyloadedobjectsdirectlybackintoalocalstore,eitherasafastlocalcacheor
aprimarydatastorethatisperiodicallysyncedwiththecloud.RestKitcanpopulateCoreDataassociationsforyou,allowingnaturalpropertybasedtraversalofyourdatamodel.ItalsoprovidesaniceAPIontopoftheCoreDataprimitivesthatsimplifies
configurationandqueryingusecasesthroughanimplementationoftheActiveRecordaccesspattern.

但实际上RKRequestCachePolicy已经解决了大部分Cache需求。


4.SDWebImage

SDWebImage是Github开源项目:https://github.com/rs/SDWebImage,它用于方便的请求、Cache网络图片,并且请求完毕后交由UIImageView显示。

AsynchronousimagedownloaderwithcachesupportwithanUIImageViewcategory.

SDWebImage作为UIImageView的一个Category提供的,所以使用起来非常简单:

?
1

2

3
//
HereweusethenewprovidedsetImageWithURL:methodtoloadthewebimage


[imageView
setImageWithURL:[NSURLURLWithString:@
"http://www.domain.com/path/to/image.jpg"
]


placeholderImage:[UIImage
imageNamed:@
"placeholder.png"
]];


AFNetworking也提供了类似功能(UIImageView+AFNetworking):

?
1

2
UIImageView
*imageView=[[UIImageViewalloc]initWithFrame:CGRectMake(0.0f,0.0f,100.0f,100.0f)];


[imageView
setImageWithURL:[NSURLURLWithString:@
"http://i.imgur.com/r4uwx.jpg"
]
placeholderImage:[UIImageimageNamed:@
"placeholder-avatar"
]];



5.UIWebView中的图片Cache

如果你使用UIWebView来展示内容,在离线情况下如果也想能显示的话需要实现2点:

CacheHtml页面
Cache图片等元素

使用上面介绍的网络组件来CacheHtml页面比较便捷,之后使用webViewloadHTMLString即可加载本地Html页面,而Cache图片需要更换NSURLCache公共实例为自定义的NSURLCache(UIWebView使用的即是+[NSURLCachesharedURLCache]):

?
1

2

3

4

5
//设置使用自定义Cache机制


LocalSubstitutionCache
*cache=[[[LocalSubstitutionCachealloc]init]autorelease];


[cache
setMemoryCapacity:4*1024*1024];


[cache
setDiskCapacity:10*1024*1024];


[NSURLCache
setSharedURLCache:cache];


自定义NSURLCache:

?
1

2

3

4

5

6

7

8

9

10
#import
<Foundation/Foundation.h>


@interface
LocalSubstitutionCache:NSURLCache


{


NSMutableDictionary
*cachedResponses;


}


+
(NSString*)pathForURL:(NSURL*)url;


@end


详细的见NewsReader中的LocalSubstitutionCache.h/.m和WebViewController.m中的viewDidLoad,News
Reader开源项目这里参考的是:http://cocoawithlove.com/2010/09/substituting-local-data-for-remote.html


NewsReader中的介绍


iOSNewsReader开源项目》这篇文章介绍到的开源项目改进了离线使用体验:



在没有网络的情况下使用已经Cache过的所有数据:文章、图片、音频等等,用到的主要方案已经在上面介绍了,详细的请看源码:https://github.com/cubewang/NewsReader。

NewsReader项目因为历史演进的原因已经有些庞大了,需要进一步重构,在之后的项目中我们的客户端结构更精简。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  iOS 缓存