APP下载

基于IOS的社区金融App的关键技术研究

2018-12-20高建华

计算机技术与发展 2018年12期
关键词:服务器端线程队列

秦 业,高建华

(上海师范大学 计算机科学与工程系,上海 200234)

0 引 言

随着智能终端普及率的不断提高,生活中的很多问题都能用App来解决。对于生活社区,一款能解决用户金融理财、生活服务、缴费的App必不可少,因此文中推出了社区金融App产品。该App功能包括手机充值、代缴水煤电费;在线问诊、预约、挂号、咨询;查阅购买基金、股票、黄金等金融理财产品。

1 IOS平台

IOS系统主要用在iPhone、iPad等产品[1],是移动端最受欢迎的操作系统。IOS App开发采用Xcode,它集成了各个版本的模拟器,适合开发iPhone、iPad、等苹果公司产品的应用。IOS系统基于FreeBSD系统,从本质上说IOS是Unix的一个分支,特点主要体现在后台运行机制上,包括三个方面:

(1)IOS系统有独特的任务管理机制。当应用程序不在前台运行时,除了部分服务,其他应用在10分钟后都被系统挂起。被挂起等同于不执行,只是数据驻留在内存而已。

(2)内存管理机制。在执行任意应用时,应用向系统申请内存空间,如果应用在使用的过程中不断申请内存,超过了系统限定的内存区间,系统会发出内存警报,严重时会直接将应用杀死。同样,如果应用向系统申请内存时,系统内存空间不足,系统会结束后台应用的运行,以释放空间资源[2]。

(3)伪多任务。例如微信,退出后不在后台运行。用户收到消息是因为系统推送服务。无论用户的应用程序是否运行,IOS都会在后台维护这个服务实现伪多任务,所有应用程序共用这一服务。

2 社区金融App架构

IOS App开发主要有Native App、Hybrid App、Web App[3]等三种开发架构,各自特点如表1所示。

表1 三种IOS开发架构比较

该项目根据用户体验选择Native App作为开发架构。

2.1 基本视图设计原则

在手机平台上,手指触摸不是一个精确点击,而是一个“块”状的点击范围,在范围内的控件会被点击操作激发,这点和鼠标完全不一样。因此在功能设计中,“块”的设计相当重要。基于目前业界主流的页面设计,结合UITabbarController[4]和UITableViewController实现需求。前者可以将屏幕底部等分或自定义分成项目需要的模块,用来布置项目中最常用的几个功能模块;后者则能够以类似表格的形式展现每个功能模块对应的内容。

2.2 App开发

IOS App开发分为客户端和服务器端开发,是一个典型的C/S程序,计算工作由服务器端完成,客户端实现GUI界面的展示、数据的获取和解析、用户操作的捕捉等。这种前后端分离的开发模式有利于各司其职和实现松耦合,开发出更好的应用。文中专注客户端开发过程中的部分关键技术,主要包括MVVM设计模式、JSON数据解析、多线程编程技术和缓存机制技术。

3 关键开发技术

3.1 MVVM设计模式

MVVM模式是Model-View-ViewMode模式的简称。由视图(View)、视图模型(ViewModel)、模型(Model)三部分组成。通过这三部分实现UI逻辑、呈现逻辑和状态控制、数据与业务逻辑的分离[5]。

Model层代表了描述业务逻辑和数据的一系列类的集合。它也定义了数据修改和操作的业务规则。

View代表了UI组件,像CSS、Jquery、html等,只负责展示从Presenter接收到的数据,也就是把模型转化成UI。

View Model负责暴露方法,命令,其他属性来操作View的状态,组装Model作为View动作的结果,并且触发View自己的事件。

MVVM的技术关键点是:

(1)用户只通过View和服务端交互信息。

(2)View和ViewModel是多对一关系。意味着一个ViewModel只映射多个View(在MVC中一个View对应一个ViewController)。

(3)View持有ViewModel的引用,但是ViewModel没有任何View的信息。

(4)View和ViewModel之间有着双向数据绑定关系。

三个组件之间的关系如图1所示。

MVVM这种新的设计模式真正做到了将页面与数据逻辑分离,解决了传统MVC模式中Controller过于臃肿的问题,并且可以将使用次数多的视图逻辑放到ViewModel中,通过一对多的映射关系供更多的View重用,提高了复用性。

3.2 JSON数据解析

客户端向服务器端发送数据请求,服务器端响应后返回XML或者JSON格式的数据。由于JSON格式是一种轻量级数据交互格式[6],目前已经取代XML,该项目也采用JSON格式。

JSON解析指的是将服务器端传来的JSON格式数据转化为IOS端显示的模型数据,并将JSON中各个属性数据赋值给模型对应属性。从IOS5开始,Xcode原生JSON解析类库NSJSONSerialization,但在实际开发中,NSJSONSerialization使用难度大、易出错。Github有许多类似的第三方类库更加优秀,有YYModel、MJExtension等,其中YYModel性能更好,使用起来更加简单方便。因此该项目使用YYModel解析JSON数据。

YYModel是通过对NSObject的部分内容进行封装来实现功能,具体是:

YYClassInfo是对Class进行封装描述:

·YYClassIvarInfo对Class的Ivar进行封装描述;

·YYClassMethodInfo对Class的Method进行封装描述;

·YYClassPropertyInfo对Class的Property进行封装描述。

YYModel是对YYClassInfo进行封装,并暴露调用接口给用户,具体是:

·YYModelMeta对YYClassInfo进行封装描述;

·YYModelPropertyMeta对YYClassProperty进行封装描述。

其中主要提供了三种解析类别:

(1)NSObject(YYModel):提供一些字典模型互转的方法,将对key/value进行匹配,赋值给Model对应的property。

(2)NSArray(YYModel):为NSArray提供字典转模型的方法。

(3)NSDictionary(YYModel):为NSDictionary提供字典转模型方法。

下面以用户点击加载“股票信息”为例,具体的解析流程如图2所示。

对应加载股票信息模块的部分代码如下:

//result表示服务器端返回的JSON数据,先保存到字典当中

NSDictionary *dic=result[@"singleData"][0];

//StockDetail调用YYModel里的yy_modelWithJSON方法,返回一个StockDetail模型对象

StockDetail *detail=[StockDetail yy_modelWithJSON:dic];

self.stockDetail=detail;

//YYModel中的yy_modelWithJSON方法将JSON数据转化成预定义好的StockDetail对象

+ (instancetype)yy_modelWithJSON:(id)json {

NSDictionary *dic=[self _yy_dictionaryWithJSON:json];

//将StockDetail对象赋值给模型中的self.stockDetail,显示到界面上

return [self yy_modelWithDictionary:dic];}

上述代码是通过AFNetworking实现HTTP或HTTPS链接请求,获取后端API返回的JSON字符串[7],再通过YYModel实现将JSON字符串转化为NSDIctionary格式的模型对象,最后将模型的数据显示到界面上。

图2 获取股票JSON流程

3.3 多线程编程技术

实际开发中,主线程主要负责完成主控制器的调用、控制和控制器之间的通信任务,而控制器所控制的视图上的数据获取则交给其他线程完成。因为线程中任务的执行是顺序执行的,也就是说在一个时间段内一个线程只能执行一个任务,对于需要同时执行的任务就需要多线程并发执行[8]。

IOS中实现多线程的方式有很多种,包括NSThread、NSOperation等。但最常用的是GCD。GCD是一个在后端管理线程池的工具[9],让开发人员无需和线程直接打交道。

GCD是基于C语言的底层API,其中最重要的概念就是dispatch_queue,它是一个对象,可以接受任务并以先到先执行的方式处理任务。根据GCD队列的种类处理方式有所不同,最主要的有以下2种:

Serial:串行队列以先进先出(FIFO)的顺序执行任务,所以串行队列经常用来做访问某些特定资源的同步处理。可根据需要创建多个队列,而这些队列相对其他队列都是并发执行的。即若创建了4个串行队列,每一个队列在同一时间都只执行一个任务,对这四个任务来说,它们是相互独立且并发执行的。如果需要创建串行队列,一般用dispatch_queue_create这个方法来实现。

Concueerent:并发队列虽然是能同时执行多个任务,但这些任务仍然是按照先到先执行(FIFO)的顺序来执行的。并发队列会基于系统负载来合适地选择并发执行这些任务。而在iOS5之后,也可以用dispatch_queue_create,并指定队列类型为DISPATCH_QUEUE_CONCURRENT来自己创建一个并发队列。

创建需要的队列后,需要将其添加到任务当中,这又分为同步和异步两种。一般情况下,使用dispatch_async和dispatch_async_f来执行异步操作。比如,添加一个block对象或C函数到一个队列后就会立即返回,任务会由GCD决定执行顺序,以及任务执行完毕时间。好处是,若需要在后台执行一个基于网络或CPU密集型任务,使用异步方法不会阻塞当前线程[10]。

尽管一般情况下,优先选择异步操作,但是在某些情况下,还是需要任务同步来执行。比如需要用同步操作来防止资源竞争或其他同步问题。这时可以用dispatch_sync和dispatch_sync_f方法把任务添加到队列中,这样被添加的任务会阻塞当前线程,直到这些任务执行完,确保同一资源在同一时间只能被一个线程访问到。

以用户点击“详情”获取对应股票的详情信息为例,主线程在获取视图控制器和文字内容时,子线程负责加载图片,这样可以做到在加载图片的过程中不会出现卡顿现象,步骤如图3所示。

图3 YYCache结构关系图

当然,GCD的使用场景很多,该项目在清理缓存信息时使用GCD异步删除本机的缓存,部分实现代码如下:

//判断缓存文件路径是否存在

if (![path isEqualToString:_cachePath]) {

//调用GCD,开启异步线程,传递线程队列和回调函数

dispatch_async(_queue, ^{

//将字符串路径转化为IOS识别的文件路径

NSURL *fileURL=[NSURL URLWithString:path];

NSDictionary *dictionary=[fileURL

resourceValuesForKeys:@[NSURLContentModificationDateKey] error:nil];

//得到内容的最后修改时间

NSDate *modificationDate=[dictionary objectForKey:NSURLContentModificationDateKey];

if (modificationDate.timeIntervalSince1970 - date.timeIntervalSince1970 <0) {

[_fileManager removeItemAtPath:fileURL.absoluteString error:nil];

//从文件路径和缓存中删除缓存文件

[_memoryCache removeObjectForKey:fileURL.lastPathComponent];}});}

3.4 缓存机制技术

在App的使用过程中缓存机制是必不可少的,根据存储的不同缓存也可以分为内存缓存和文件缓存[11],分别具有高速度低容量和低速度高容量的特点。YYCache同时具有这两种缓存机制,项目选择YYCache作为缓存框架。

YYCache中内存缓存和文件缓存的关系如图4所示。

图4 YYCache结构关系图

内存缓存是初次请求数据时将获取到的数据存放到内存当中,当用户再次访问到该数据时无需再向服务器请求数据,直接从内存中获取缓存数据,具有高速度的特点,但由于内存较为昂贵,所以容量较低。

文件缓存是将获得的数据存放在客户端数据库文件中,社区金融App使用了SQLite数据库做文件缓存。在用户初次请求服务器获得数据时,将音乐、图片等大容量文件按照键值对的形式存放到SQLite.db文件中,当客户端再次访问相同页面时,控制器会先检测是否有对应的db文件,若无则发送请求给服务器,并将返回的数据缓存到SQLite中[12],若有则直接从db文件中取得数据并显示在界面上。

在请求社区金融新闻信息时,可能同时存在内存缓存和文件缓存,使用YYCache得到的缓存流程如图5所示。

在获取金融类新闻信息时使用YYCache的部分代码如下所示:

//初始化YYCache

YYCache *cache=[YYCache cacheWithName:@"mydb"];

//缓存普通字符

[cache setObject:@"中国中车" forKey:@"name"];

NSString *name=(NSString*)[cache objectForKey:@"name"];

NSLog(@"name: %@",name);

//缓存模型

[cache setObject:(id)model forKey:@"user"];

//缓存数组

NSMutableArray *array=@[].mutableCopy;

For (NSInteger i=0;i<10;i++) {

[array addObject:model];

}

//异步缓存

[cache setObject:array forKey:@"user" withBlock:^{

// 异步回调

NSLog(@"%@", [NSThread currentThread]);

NSLog(@"array缓存完成....");

}];

//延时读取

dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(0.3*NSEC_PER_SEC)),dispatch_get_main_queue(),^{

//异步读取

[cache objectForKey:@"user" withBlock:^(NSString*_Nonnull key,id_Nonnull object){

//异步回调

NSLog(@"%@",[NSThread currentThread]);

NSLog(@"%@",object);}];});

图5 获取缓存流程

内存缓存和文件缓存的区别在于,当应用还在进程中时,应用有内存缓存和文件缓存两种缓存方式,当应用进程被杀死时,应用只存在文件缓存,内存缓存将被清空。因此对于图片、音频、视频等大容量文件,App使用了文件缓存技术将数据缓存到SQLite数据库中,节省资源;对于文字等小容量内容则缓存到内存中,方便获取[13]。

4 结束语

为了更好地适应移动互联网时代,社区金融IOS端App将不断更新维护,未来开发的重点在于功能模块的扩展,让App满足更多理财需求。考虑到移动开发成本问题,统一IOS和安卓App的跨平台开发[14]是大势所趋,因此从Native App到Hybrid App的迁移是以后工作的重点。

猜你喜欢

服务器端线程队列
实时操作系统mbedOS 互斥量调度机制剖析
浅析体育赛事售票系统错票问题的对策研究
Linux环境下基于Socket的数据传输软件设计
队列队形体育教案
队列里的小秘密
基于多队列切换的SDN拥塞控制*
在队列里
基于Qt的安全即时通讯软件服务器端设计
基于Qt的网络聊天软件服务器端设计
基于C/S架构的嵌入式监控组态外设扩展机制研究与应用