App Store中的App分析

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

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

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

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

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

如何做?

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

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

1
2
3
4
- (void)viewDidLoad {
 
    [self getArticleList:0 length:SECTION_LENGTH useCacheFirst:YES];
}

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

1
2
3
4
5
6
7
8
- (void)viewDidAppear:(BOOL)animated {
     
    [super viewDidAppear:animated];
 
    //...
 
    [self getArticleList:0 length:SECTION_LENGTH useCacheFirst: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 or empty URL is given");
    return;
}
NSURLCache *urlCache = [NSURLCache sharedURLCache];
/* 设置缓存的大小为1M*/
[urlCache setMemoryCapacity:1*1024*1024];
 //创建一个nsurl
NSURL *url = [NSURL URLWithString: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基本是主力的 HTTP requests library,它本身也是Github中的开源项目,但是从iOS 5.0之后逐渐停止维护了。未来的项目可以使用AFNetworking或者MKNetworkKit代替ASIHTTPRequest。

ASIHTTPRequest的简介如下:

ASIHTTPRequest is an easy to use wrapper around the CFNetwork API that makes some of the more tedious aspects of communicating with web servers easier. It is written in Objective-C and works in both Mac OS X and iPhone applications.

It is suitable performing basic HTTP requests and interacting with REST-based services (GET / POST / PUT / DELETE). The included ASIFormDataRequest subclass makes it easy to submit POST data and files usingmultipart/form-data.

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

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

ASIHTTPRequest库的介绍中也提到了它可以支持REST-based service,但是与Restfull API打交道我们往往使用下面介绍的的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 = [[NSMutableString alloc] initWithString:self.url];
 
//如果优先使用本地数据
ASICachePolicy policy = _useCacheFirst ? ASIOnlyLoadIfNotCachedCachePolicy
    : (ASIAskServerIfModifiedCachePolicy | ASIFallbackToCacheIfLoadFailsCachePolicy);
 
asiRequest = [ASIHTTPRequest requestWithURL:
                   [NSURL URLWithString:[requestedUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
 
[asiRequest setDownloadCache:[ASIDownloadCache sharedCache]];
[asiRequest setCachePolicy:policy];
[asiRequest setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
 
// Connection
if (_connectionType == ConnectionTypeAsynchronously) {
     
    [asiRequest setDelegate:self];
    [asiRequest startAsynchronous];
     
    // Tell we're receiving.
    if (!_canceled && [_delegate respondsToSelector:@selector(downloaderDidStart:)])
        [_delegate downloaderDidStart:self];
}
else
{
    [asiRequest startSynchronous];
     
    NSError *error = [asiRequest error];
     
    if (!error)
    {
        [self requestFinished:asiRequest];
    }
    else
    {
        [self requestFailed:asiRequest];
    }
}
 
[requestedUrl release];

3.RestKit

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

Sample:

1
2
3
4
5
6
7
8
9
10
11
12
+ (void)setCachePolicy:(BOOL)useCacheFirst
{
    RKObjectManager* objectManager = [RKObjectManager sharedManager];
     
    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真正强大的地方在于处理与RESTful web services交互时的相关工作非常简便(https://github.com/RestKit/RestKit/wiki),RestKit还可以Cache data model到Core Data中:

Core Data support. Building on top of the object mapping layer, RestKit provides integration with Apple's Core Data framework. This support allows RestKit to persist remotely loaded objects directly back into a local store, either as a fast local cache or a primary data store that is periodically synced with the cloud. RestKit can populate Core Data associations for you, allowing natural property based traversal of your data model. It also provides a nice API on top of the Core Data primitives that simplifies configuration and querying use cases through an implementation of the Active Record access pattern.

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

4.SDWebImage

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

Asynchronous image downloader with cache support with an UIImageView category.

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

1
2
3
// Here we use the new provided setImageWithURL: method to load the web image
[imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]
               placeholderImage:[UIImage imageNamed:@"placeholder.png"]];

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

1
2
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 100.0f)];
[imageView setImageWithURL:[NSURL URLWithString:@"http://i.imgur.com/r4uwx.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder-avatar"]];

5.UIWebView中的图片Cache

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

  • Cache Html页面
  • Cache 图片等元素

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

1
2
3
4
5
//设置使用自定义Cache机制
LocalSubstitutionCache *cache = [[[LocalSubstitutionCache alloc] 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中的介绍

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

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

NewsReader项目因为历史演进的原因已经有些庞大了,需要进一步重构,在之后的项目中我们的客户端结构更精简。

如何改进iOS App的离线使用体验的更多相关文章

  1. 马蜂窝 iOS App 启动治理:回归用户体验

    增长.活跃.留存是移动 App 的常见核心指标,直接反映一款 App 甚至一个互联网公司运行的健康程度和发展动能.启动流程的体验决定了用户的第一印象,在一定程度上影响了用户活跃度和留存率.因此,确保启 ...

  2. iOS - App 上架审核被原因拒总结

    1.未遵守苹果 iOS APP 数据储存指导方针 如果你的 App 有离线数据下载功能,尤其需要关注这一点.因为离线数据一般占用存储空间比较大,可以被重新下载和重建,但是用户往往希望系统存储空间紧时也 ...

  3. 20个可以帮你简化iOS app开发流程的工具

    这里推荐20个可以帮你简化iOS app开发流程的工具.很多开发者都使用过这些工具,涉及原型和设计.编程.测试以及最后的营销,基本上涵盖了整个开发过程. 原型和设计 有了一个很好的创意后,你要做的不是 ...

  4. ios app开发步骤

    虽然开发一个app的任务看上去可能很艰巨,但是整个过程可以抽象成几个相对简单的步骤,下面这些步骤会在你开发第一个app时帮你步入正途. 定义Concept 每个好app都是从一个concept开始. ...

  5. 提高 iOS App 通知功能启用率的三个策略

    我们都知道推送通知在 App 运营中的作用巨大.但是,很多用户却并不买帐,App 第一次启动提示是否「启用推送通知」时,他们直接选择了「否」. 是的,最近我本人就转变成了这样的人 - 认真地评估每个应 ...

  6. 移动应用开发过程中需要哪些IOS APP工具

    虽说如今要开发一款IOS app应用软件已经不是什么难事,app开发技术已经发展成熟,所以要制作一款适用于苹果IOS智能操作系统的app软件也挺容易的了.不过对于开发者来说,可以通过一些app工具来更 ...

  7. 改进iOS客户端的升级提醒功能

    改进iOS客户端的升级提醒功能 功能设计 先申明一下,我是码农,不是一个产品经理,但我觉得现有市面上的很多 App,设计的 "升级提示功能" 都不太友好.在此分享一下我的想法,欢迎 ...

  8. CRM2013版本 IOS APP 说明(IPhone、IPad)

    CRM2013版本 IOS APP 说明(IPhone.IPad) IPhone版本 首页 CRM APP在登录时输入账号信息,可以进行首面.其首页显示内容可以在CRM后台设置. 系统默认显示:Pho ...

  9. iOS App中数据加载的6种方式

    我们看到的APP,往往有着华丽的启动界面,然后就是漫长的数据加载等待,甚至在无网络的时候,整个处于不可用状态.那么我们怎么处理好界面交互中的加载设计,保证体验无缝衔接,保证用户没有漫长的等待感,而可以 ...

随机推荐

  1. Visual Studio 2010 简体中文旗舰、专业版(MSDN原版下载)

    Visual Studio 2010 简体中文旗舰.专业版(MSDN原版下载)(Visual Studio 2010 ultimate professional x86 dvd)2010[光盘镜像]- ...

  2. 2次成功投诉EMS和中国移动的经验

    上个月要找房子,搬家很多事情,真实头疼...搬家还把腰闪了....现在还有点痛.然后中间碰到 移动宽带 移机的事情,搞得我非常火.然后想起去年投诉EMS的事情,在事情处理完成后,我果断总结了下来,让大 ...

  3. Android获取屏幕长宽

    总结了下,我遇到的获取Android屏幕长宽的方式总共有三种.大同小异,重点在于如何获取系统中的WindowManager管理类对象,方可对数据的操作: 代码如下 /** * @return 屏幕的长 ...

  4. TF-IDF 简介

      假设我们手头有大量的文档(或网页), 通常我们会比较关心以下几个问题: 1. 每一个文档的关键词(或主题词)包括哪些? 2. 给定一个(或一组)关键词,与这个(或组)词最相关的文档是哪一个? 3. ...

  5. 使用 Web Tracing Framework 分析富 JS 应用的性能

    来自谷歌的 Web Tracing Framework 包含一组工具和脚本,用于 JavaScript 相关代码的性能分析.它是重 JavaScript 应用程序的理想选择,而 JavaScript ...

  6. C#语法糖之 cache操作类 asp.net

    因为考虑到我下面我将写session cookies 等 操作类 ,与cache具有共性. 所以都统一继承了IHttpStorageObject  abstract class 来保函数风格的统一 , ...

  7. Dictionary序列化和反序列化

    public class SerializeHelper { public static string XmlSerialize(List<CustomSearchEntity> obj) ...

  8. Java中接口式的匿名内部类的构造方法

    在使用多线程的时候,时常会使用两种方式实现,一种是直接继承Thread类来实现多线程,另外一种就是实现Runnable接口. 我们都知道,接口是没有构造方法的,同时匿名内部类也是没有构造方法的.原因有 ...

  9. Web开发者选择的最佳HTML5/CSS3代码生成器

    原文地址:http://codecloud.net/css3-code-generators-for-web-programmers-6672.htmlHTML5 和CSS3是一入门就能用的最好的语言 ...

  10. Unity3D-terrain brush地形画刷无法出现在Scene中,无法刷地图2

    原因大概是 画刷brush 太小了,地图也太小了,没出出现. 如图,非正常状态: 解决方法: tag: terrain brush not working unity