365bet地区构建由365bet地区后端提供支持的Objective C iOS客户端

365bet地区本指南演示了如何将365bet地区用作使用Objective C构建的iOS应用程序的后端

s塞尔吉奥·德尔阿莫

365bet地区版本 3.3.1

365bet地区培训

365bet地区培训由创建并积极维护365bet地区框架的人们开发和交付

入门

在本指南中,您将构建一个365bet地区365bet地区应用它将用作公司Intranet后端。它公开了公司公告的JSON API

另外,您将建立一个iOS应用使用后端提供的JSON API的Intranet客户端

该指南探讨了不同API版本的支持

您将需要什么

要完成本指南,您将需要以下内容

  • 花些时间在你手上

  • 体面的文本编辑器或IDE

  • 安装了JDK或更高版本JAVA首页适当配置

  • 最新的稳定版本Xcode本指南是使用Xcode编写的

如何完成指南

要完成本指南,您需要从Github中签出源代码并按照指南中介绍的步骤进行操作

要开始,请执行以下操作

365bet地区遵循365bet地区部分

  • 光盘进入grails指导构建由grails后端初始驱动的ios对象客户端

365bet地区或者,如果您已经安装了365bet地区,则可以在“终端”窗口中使用以下命令创建新的应用程序

grails创建应用程序intranet后端grails应用程序配置文件rest api cd grails应用程序

365bet地区当create app命令完成时,365bet地区将使用配置为创建REST应用程序的应用程序创建grails应用程序目录,这是由于使用了参数配置文件rest api并配置为将休眠功能与H数据库一起使用

365bet地区您可以直接转到完整的365bet地区示例,如果您光盘进入grails指导构建由grails后端驱动的ios对象客户端

跟随iOS部分

  • 光盘进入grails指导构建由grails后端初始Objectivec支持的ios对象客户端

  • 前往下一部分

或者,您可以使用Xcode Studio的“新建项目向导”来创建iOS应用程序,如以下屏幕截图所示。

创建新项目
选择主要细节应用
选择目标c
您可以直接转到iOS示例的完整版本光盘进入grails指导构建由grails后端提供支持的ios objectc客户端完整的Objectivec ios v
您可以直接转到iOS示例的完整版本光盘进入grails指导构建由grails后端提供支持的ios objectc客户端完整的Objectivec ios v

总览

下图说明了iOS应用版本的行为iOS应用由两个View Controller组成

  • 当iOS应用程序初始屏幕加载时,它会请求一个公告列表

  • 365bet地区365bet地区应用程序发送一个JSON负载,其中包含公告列表。对于每个公告,都包含唯一的标识符,标题和HTML正文

  • iOS应用程序将JSON有效负载呈现在UITableView

  • 用户点击公告的标题,应用程序会转到详细信息屏幕。初始屏幕向详细信息屏幕发送公告标识标题和HTML正文,后者将以UIWebView

概观

365bet地区编写365bet地区应用程序

365bet地区现在您可以开始编写365bet地区应用程序了

创建域类持久性实体

365bet地区我们需要创建持久性实体来存储公司公告,365bet地区通过使用来处理持久性365bet地区365bet地区域类:

域类满足Model View Controller MVC模式中的M,并表示映射到基础数据库表上的持久实体。在365bet地区中,域是位于grails应用程序域目录中的类。

365bet地区365bet地区使用以下命令简化了域类的创建创建域类命令.

grailsw创建域类公告解决依赖关系请等待成功配置总时间secs创建grails应用grails公司intranet公告groovy创建src test groovy grails公司intranet AnnouncementSpec groovy

为了简单起见,我们假设公司公告中仅包含一个标题还有一个HTML主体我们将修改在上一步中生成的域类以存储该信息

365bet地区应用程序域Intranet后端公告groovy
内部网后端 公告 {

    标题身体静态的约束标题尺寸: 0..255身体可为空: 
    }

    静态的映射体类型: '文本'  (1)
    }
}
1 它使我们能够在字符串中存储多个字符身体.

域类单元测试

365bet地区365bet地区使测试更加容易从低级单元测试到高级功能测试

我们将测试在Announcement域中定义的约束类的constraints属性,尤其是标题属性和正文属性的可空性和长度

src测试groovy内部网后端公告Spec groovy
内部网后端 免费测试gorm DomainUnitTest
 spock lang规格

 公告规格 延伸规格实施DomainUnitTest {

    虚空 "测试体可以为空"() {
        期望:
        公告身体: 空值验证'身体'])
    }

    虚空 "测试标题不能为空"() {
        期望:
        !公告标题: 空值验证'标题'])
    }

    虚空 "测试体可以有多个字符"() {

        什么时候: '用于一串字符'
        海峡''
        256Times Str'一种' }

        然后: '身体验证合格'
        公告身体str验证'身体'])
    }

    虚空 "测试标题最多可包含字符"() {

        什么时候: '用于一串字符'
        海峡''
        256Times Str'一种' }

        然后: '标题验证失败'
        !公告标题str验证'标题'])

        什么时候: '用于一串字符'海峡''
        255Times Str'一种' }

        然后: '标题验证通行证'
        公告标题str验证'标题'])
    }
}

我们可以运行所有测试,包括我们刚刚使用命令test应用创建的测试

grailsw test app解析依赖项,请等待成功配置总时间secs完成compileJava UP截止日期完成compileGroovy完成buildProperties完成processResources完整类完成compileTestJava UP截止日期完整compileTestGroovy完成processTestResources截止日期Date testGroy完成测试完成compileIntegrationTest DATE完成processIntegrationTestResources UP截止日期DATE完全IntegrationTestClasses UP截止日期DATE完全IntegrationTest UP截止日期DATE完全mergeTestReports建立成功的测试通过

版本控制

从一开始就考虑API版本控制非常重要,尤其是当您创建手机应用程序使用的API时用户将运行该应用程序的不同版本,并且需要对API进行版本控制以创建高级功能,但仍要支持旧版本

365bet地区365bet地区允许多种方式版本REST资源.

  • 使用URI

  • 使用接受版本标题

  • 使用超媒体Mime类型

在本指南中,我们将使用“接受版本”标头对API进行版本控制

运行版本的设备将调用公告要求通过接受版本HTTP头

curl i H接受版本X GET http localhost公告

运行版本的设备将调用公告指定在接受版本标头中传递

curl i H接受版本X GET http localhost公告

创建一个控制器

我们创建一个控制者为了域类我们之前创建的Controller扩展了RestfulController这将为我们提供RESTful功能,以列出创建更新和删除操作公告使用不同HTTP方法的资源

365bet地区应用程序控制器Intranet后端v AnnouncementController groovy
内网后端v 365bet地区 Rest RestfulController
 Intranet后端公告

 公告控制器 延伸RestfulController {
    静态的命名空间'' (1)
    静态的responseFormats'json'] (2)公告控制器公告
1 该控制器将处理我们的api的v
2 我们只想回应JSON有效负载

网址映射

我们希望端点监听公告,而不是公告。此外,我们希望为先前的控制器声明一个v的命名空间,以将Accept Version Http Header设置为来处理请求。

365bet地区365bet地区使功能强大URL映射进行配置,将下一行添加到映射闭包中

365bet地区应用程序控制器Intranet后端UrlMappings groovy
得到"公告"(:'1.0', 控制者: '公告', 命名空间:'')

加载测试数据

当应用程序启动时,我们将用几条公告填充数据库

为了做到这一点,我们编辑grails应用程序初始化grails公司Intranet BootStrap常规.

365bet地区公司内部网 引导带 {

    定义初始化servletContext公告每个保存定义破坏静态的 清单公告公告标题: '365bet地区365bet地区 Quickcast 365bet地区拦截器'),
                公告标题: '365bet地区365bet地区 Quickcast JSON视图')
        ]
    }
}
上一个代码片段中的公告不包含身体保持代码样本较小的内容365bet地区应用程序初始化Intranet后端BootStrap常规查看完整的代码

功能测试

功能测试涉及对正在运行的应用程序发出HTTP请求并验证结果行为

我们使用365bet地区Rest Client Builder 365bet地区插件当我们使用轮廓

家庭travis构建grails指南构建由grails后端提供动力的ios objectc客户端

src集成测试groovy内部网后端AnnouncementControllerSpec groovy
内部网后端 grails插件rest client RestBuilder
 grails测试mixin集成集成
 org springframework bean工厂注释值
 spock lang规格
 javax servlet http HttpServletResponse

积分
 公告控制器规格 延伸规格定义 "测试体存在于Api的json公告有效载荷中"() {
        给定RestBuilder的休息RestBuilder的什么时候: '要求发布版本'
        定义休息休息"HTTP本地主机${服务器端口}公告") { (1)标头"接受版本", "1.0") (2)
        }

        然后: '请求成功'响应状态HttpServletResponse SC OK(3)

        : '响应是JSON有效负载'resp标头获取'内容类型') == ['应用程序json字符集UTF']

        : 'json有效内容包含ID为title和body的通告数组'分别回复json断言 ID断言 标题断言 身体(4)
        }
    }

    定义 "测试体不存在于Api的json公告有效载荷中"() {
        给定RestBuilder的休息RestBuilder的
1 365bet地区serverPort属性是自动注入的,它包含功能测试期间运行365bet地区应用程序的随机端口
2 将api版本作为Http头传递
3 验证响应代码是否正确
4 正文存在于JSON有效负载中

365bet地区365bet地区命令测试应用运行单元集成和功能测试

运行应用程序

要运行该应用程序,请使用gradlew bootRun命令将在端口上启动应用程序

编写iOS应用程序

获取公告

365bet地区下图说明了365bet地区应用程序公开的通知的获取和呈现中涉及的类

ios公告概述

模型

服务器发送的公告将被渲染为一个对象

完整目标c ios v内联网客户端公告h
进口接口公告NSObject属性非原子复制NSNumber primaryKey属性非原子复制NSString标题属性非原子复制NSString主体结束
完整目标c ios v内联网客户端公告m
进口公告h实施公告结束

杰森到模型

要从JSON字符串构建Model对象,我们使用几个构建器类

完整的ObjectiveC iOS v IntranetClient AnnouncementBuilder h
进口导入ElementBuilder h外部NSString kAnnouncementBuilderErrorDomain枚举kAnnouncementBuilderInvalidJSONError kAnnouncementBuilderMissingDataError接口AnnouncementBuilder ElementBuilder NSArrayannouncementFromJSON NSString objectNotation error NSError error end
完整的Objective C iOS v IntranetClient AnnouncementBuilder m
完整的Objective C iOS v IntranetClient ElementBuilder h
进口接口ElementBuilder NSObject NSArray arrayFromJSON NSString objectNotation键NSString键错误NSError错误invalidJSONErrorCode NSInteger invalidJSONErrorCode missingDataErrorCode NSInteger missingDataErrorCode errorDomain NSString errorDomain end
完整的ObjectiveC iOS v IntranetClient ElementBuilder m
导入ElementBuilder h实现ElementBuilder NSArray arrayFromJSON NSString objectNotation key NSString key error NSError error invalidJSONErrorCode NSInteger invalidJSONErrorCode missingDataErrorCode NSInteger missingDataErrorCode errorDomain NSString errorDomain id parsedObject self parseJSON objectNotation error error invalidJSONErrorCode invalidJSONErrorCode errorDomain errorDomain NSDomainsObjects NSD如果已解析的对象则为nSD parsedObject isKindOfClass NSArray类元素NSArray parsedObject if元素nil如果错误NULL错误NSError errorWithDomain error域代码missingDataErrorCode userInfo nil返回nil NSMutableArray结果NSMutableArray arrayWithCapacity元素中NSDictionary parsedEl的元素计数id id el self newElementWithDictionary parsedEl错误error invalidJSONErrorCode invalidJSONErrorCode missingDataErrorCode missingDataErrorCode errorDomain errorDomain返回nil,因为如果elValid为null,则前一个方法调用中存在错误,如果elValid为self addObject el返回结果副本BOOL isElementValid id el这可以在子类中覆盖return YES id newElementWithDictionary NSDictionary dict error NSError error invalidJSONErrorCode NSInteger invalidJSONErrorC ode MissingDataErrorCode NSInteger missingDataErrorCode errorDomain NSString errorDomain throw NSException exceptionWithName NSInternalInconsistencyExceptionException原因NSString stringWithFormat您必须在子类NSStringFromSelector cmd userInfo中覆盖null id parseJSON NSString objectNotation error NSError错误invalidJSONErrorCode NSInteger invalidJSONErrorCode errorDomain NSString ErrorDomain NSDataError对象IDNotError objectNotation dataUsingEncoding NSUTF StringEncoding jsonObject NSJSONSerialization JSONObjectWithData unicodeNotation选项错误localError如果jsonObject nil如果错误NULL NSMutableDictionary userInfo NSMutableDictionary dictionaryWithCapacity如果localError nil userInfo setObject localError forKey NSUnderlyingErrorKey错误NSError errorWithDomain errorDomain代码invalidJSONErrorCode userInfo userInfo返回nil返回自身isNotNilTheKey密钥atDict字典自身isArrayTheKey密钥atDict字典BOOL isNotNilAndNotNumberTheKey NSString密钥atDict NSDictionary dict返回自身isNotNilTheKey密钥atDict字典self isNumberTheKey密钥atDict字典BOOL isNotNilAndNotStringTheKey NSString密钥atDict NSDictionary dict返回self isNotNilTheKey key atDict dict self isStringTheKey key atDict dict BOOL isNotNilTheKey NSString key atDict NSDictionary dict if dict key id NSNull null dict key return YES return NO BOOL isStringTheKey NSString key atDict NSDictionary dict if dict key id NSNull null dictKey dictClass isKind YES return NO BOOL isNumberTheKey NSString key atDict NSDictionary dict if dict key id NSNull null dict key dict key isKindOfClass NSNumber class return YES return NO BOOL isArrayTheKey NSString key atDict NSDictionary dict if dict key id NSNull null dict key dict key isKindOfClass NSArray类返回YES return没有结束

应用程式传输安全性

365bet地区我们将连接到运行365bet地区服务器的本地计算机,我们需要禁用应用程式传输安全性如下图所示

应用程序传输安全

联网代码

我们用NSURLSession365bet地区连接到365bet地区 API中设置了几个常量365bet地区365bet地区Fetcher

365bet地区完整的ObjectiveC iOS v IntranetClient 365bet地区Fetcher h
进口365bet地区静态NSString kServerUrl http静态NSString kApiVersion静态NSString kAnnouncementsResourcePath公告静态NSInteger快速时间间隔接口365bet地区Fetcher NSObject属性非原子性强NSURLSession会话NSURLRequest getURLRequestWithUrlString NSString urlString cachePolicy NSURLRequestCachePolicy cachePolicy timeoutInterval间隔NSTimeInterval time
1 365bet地区365bet地区应用服务器网址
2 365bet地区我们在365bet地区应用中配置的路径UrlMappings常规
3 API版本
您可能需要更改IP地址以匹配本地计算机
365bet地区完整的Objectivec iOS v IntranetClient 365bet地区Fetcher m
365bet地区导入365bet地区Fetcher h接口365bet地区Fetcher365bet地区(1)结束
1 我们设置接受版本每个请求的Http标头
完整的ObjectiveC iOS v IntranetClient AnnouncementsFetcher h
进口365bet地区导入365bet地区Fetcher h协议AnnouncementsFetcherDelegate接口AnnouncementsFetcher 365bet地区Fetcher id initWithDelegate id委托void fetchAnnouncements结束
完整的Objectivec iOS v IntranetClient公告提取器m
import AnnouncementsFetcher h import AnnouncementsFetcherDelegate h import AnnouncementBuilder h接口AnnouncementsFetcher属性非原子弱ID委托属性非原子性强AnnouncementBuilder构建器最终实现AnnouncementsFetcher id initWithDelegate id如果自身超级委托,则超级委托自身委托,委托自身构造器,AnnouncementBuilder alloc init返回,返回自身void fetchAnnouncements,自我fetchAnnouncementsWithCompletionHandler NSData数据NSURLResponse响应,如果错误,则返回NSError错误NSString分配initWithData数据编码NSUTF StringEncoding NSError builderError NSArray声明自我构建者announcementFromJSON objectNotation错误builderError if builderError if self de合法的自我委托声明FetchingFailed失败,如果自我代表自我代理声明FetchedFailedFailedResponseTimer NoticesURLString返回NSString stringWithFormat kServerUrl kAnnouncementsResourcePath结束

一旦获得公告列表,我们就将响应传达给实现委托的类

进口协议公告FetcherDelegate无效的公告FetchingFailed无效的公告获取的NSArray公告结束

MasterViewController实现fetcher委托协议,从而接收通知

完整的Objective C iOS v IntranetClient MasterViewController h
进口类DetailViewController接口MasterViewController UITableViewController属性强非原子性DetailViewController detailViewController结束
完整的ObjectiveC iOS v IntranetClient MasterViewController m
导入MasterViewController h导入DetailViewController h导入AnnouncementsFetcherDelegate h导入AnnouncementsFetcher h导入AnnouncementsTableViewDataSource h导入AnnouncementsTableViewDelegate h导入公告h静态NSString kSegueShowDetail showDetail接口MasterViewController属性NSMutableArray对象属性非原子强AnnouncementsFetcher fetcher属性非原子强IDtableViewDataSource属性非原子强标识(1)void viewWillDisappear BOOL动画超级viewWillDisappear动画self unregisterNotifications杂注标记通知如果发送者issequal标识符为isEqualToString,则发送者,如果是发送者isKindOfClass,则为seSectionViewController topViewController;如果发送者为isKindOfClass,则通知类。水泥控制器navigationItem leftBarButtonItem自splitViewController displayModeButtonItem控制器navigationItem leftItemsSupplementBackButton是杂注标记私有方法voidannounced如果通知对象为isKindOfClass Announcement类Announcement公告Announcement通知通知对象self performSegueWithIdentifier kSegueShowDetail发送者公告void setNetworkActivityIndi​​cator self fetchAnnouncements pragma标记AnnouncementsFetcherDelegate无效公告FetchingFailed自我setNetworkActivityIndi​​cator否无效公告获取NSArray公告自我setNetworkActivityIndi​​cat如果self tableViewDataSource isKindOfClass AnnouncementsTableViewDataSource类AnnouncementsTableViewDataSource self tableViewDataSource公告声明,则为NO;如果self tableViewDelegate isKindOfClass AnnouncementsTableViewDelegate类AnnouncementsTableViewDelegate self tableViewDelegate公告声明self tableView reloadData(2)实用标记懒惰的AnnouncementsFetcher访存器,如果fetcher访存器AnnouncementsFetcher分配initWithDelegate自返回访存器结束
1 触发公告获取
2 收到通知列表后,刷新UI

MasterViewController设置其UITableView的数据源并委托给下一个类

完整的ObjectiveC iOS v IntranetClient AnnouncementsTableViewDataSource h
进口属性非原子性强NSArray公告结束
完整的ObjectiveC iOS v IntranetClient AnnouncementsTableViewDataSource m
导入AnnouncementsTableViewDataSource h导入公告h实现AnnouncementsTableViewDataSource实用标记UITableViewDataSource NSInteger tableView UITableView tableView numberOfRowsInSection NSInteger部分返回自身声明计数UITableViewCell tableView UITableView tableView cellForRowAtIndexPaths NSPathPath索引路径UITableViewCell单元格表格对象dequeueI isKindOfClass公告类公告公告公告obj单元格textLabel文本公告标题返回单元格结束
完整的ObjectiveC iOS v IntranetClient AnnouncementsTableViewDelegate h
进口静态NSString kAnnouncementTappedNotification AnnouncementTappedNotification接口AnnouncementsTableViewDelegate NSObject属性非原子性强NSArray公告结束
完整的ObjectiveC iOS v IntranetClient AnnouncementsTableViewDelegate m
import AnnouncementsTableViewDelegate h import Announcements h实现AnnouncementsTableViewDelegate实用标记UITableViewDelegate void tableView UITableView tableView didSelectRowAtIndexPath NSIndexPath indexPath如果自我声明计数indexPath行ID obj自我声明indexPath行,如果obj isKindOfClass公告类NS公告类(1)对象公告userInfo无结束
1 当用户点击公告时,NS通知被举起MasterViewController

详细视图控制器

当用户点击公告时,NS通知已发布,其中包含已窃听的公告prepareForSegue发送MasterViewController我们设置的公告属性DetailViewController

完整的ObjectiveC iOS v IntranetClient MasterViewController m
void prepareForSegue UIStoryboardSegue,如果segue标识符为isEqualToString,则为segue发送者ID发送者;如果发送者isKindOfClass,则为seSectionViewController topViewController;如果发送者为isKindOfClass公告类,则为公告类。
跟随

为了呈现公告,我们使用UILabel和UIWebView,它们将连接到StoryBoard中的IBOutlet,如下所示

连接细节iboutlet

DetailViewController代码不涉及网络代码

完整的ObjectiveC iOS v IntranetClient DetailViewController h
进口导入公告h接口DetailViewController UIViewController属性非原子性强公告公告结束
完整的ObjectiveC iOS v IntranetClient DetailViewController m
导入DetailViewController h导入公告h接口DetailViewController属性非原子性弱IBOutlet UILabel titleLabel属性非原子性弱IBOutlet UIWebView webView属性非原子性弱IBOutlet UIActivityIndi​​catorView activityIndi​​catorView最终实现DetailViewController void configureView如果自告示自我titleLabel文本自告示标题自我activityIndi​​catorView startAnimating自述WebView loadHTMLString自告示主体baseURL更新详细信息的用户界面nil void viewDidLoad super viewDidLoad self webView委托self通常是从笔尖self configureView pragma mark加载视图后,进行任何其他设置管理详细信息项目void setAnnouncement如果公告公告公告公告公告公告,则更新视图self configureView pragma标志UIWebVie wDelegate无效的webViewDidFinishLoad UIWebView的webView自身activityIndi​​catorView stopAnimating无效的webView的UIWebView的webView didFailLoadWithError NSError错误自身的activityIndi​​catorView的stopAnimating结束

API版本

API的第一个版本的问题是,我们在用于显示列表的有效载荷中包含了每个公告主体。公告主体可以是很大的HTML块,用户可能只想检查几个公告即可。如果不在初始请求中发送公告正文,则可以增加带宽并提高应用程序的速度。相反,我们将要求API提供完整的公告,包括身体一旦用户点击公告

版本概述

365bet地区365bet地区 V的变化

我们将使用创建一个新的Controller来处理API的版本。我们将使用带有投影的Criteria查询来仅获取公告的ID和标题

365bet地区应用程序控制器Intranet后端v AnnouncementController groovy
内网后端v 365bet地区 Rest RestfulController
 Intranet后端公告

 公告控制器 延伸RestfulController {
    静态的命名空间''
    静态的responseFormats'json']

    定义NoticeService公告控制器公告定义 指数(整数最大参数最大数学最小最大10, 100)
        定义公告公告announceService findAllIdAndTitleProjections参数响应公告模型: [("${resourceName}计数"toString countResources

我们将查询封装在服务中

365bet地区应用程序服务Intranet后端AnnouncementService groovy
内部网后端 交易事务

交易性只读)
 公告服务 {

    清单<findAllIdAndTitleProjections参数定义c公告createCriteria定义公告c列表参数投影属性'ID'属性'标题'收藏ID: [0], 标题: [1]] }  清单<>
    }
}

我们测试一下

src测试groovy内部网后端AnnouncementServiceSpec groovy
内部网后端 grails测试休眠HibernateSpec
 免费测试服务ServiceUnitTest

 公告服务规格 延伸休眠规范实施ServiceUnitTest {

    定义 "带有投影的测试标准查询返回地图列表"() {

        什么时候: '保存一些公告'
        [公告标题: '365bet地区 Quickcast 365bet地区拦截器'),
        公告标题: '365bet地区 Quickcast JSON视图'),
        公告标题: '365bet地区365bet地区 Quickcast多项目构建'),
        公告标题: '365bet地区365bet地区 Quickcast角形脚手架'),
        公告标题: '365bet地区在365bet地区中检索运行时配置值'),
        公告标题: '365bet地区使用IntelliJ IDEA开发365bet地区应用程序'保存然后: '公告已保存'公告数6

        什么时候: '获取投影'
        定义响应服务findAllIdAndTitleProjections然后: '响应中有六张地图'分别大小6

        : '地图仅包含ID和标题'分别键集'标题', 'ID']  <>
         }

        : '非空值'分别断言 标题断言 ID

网址映射

我们需要映射版本2.0接受标头到名称空间

365bet地区应用程序控制器Intranet后端UrlMappings groovy
得到"公告"(:'2.0', 控制者: '公告', 命名空间:''得到"公告$ID(.$格式)?"(:'2.0', 控制者: '公告', 行动: '', 命名空间:'')

api功能测试

我们要测试Api版本在收到GET请求时不包含body属性公告端点下一个功能测试将验证该行为

家庭travis构建grails指南构建由grails后端提供动力的ios objectc客户端

src集成测试groovy内部网后端AnnouncementControllerSpec groovy
内部网后端 grails插件rest client RestBuilder
 grails测试mixin集成集成
 org springframework bean工厂注释值
 spock lang规格
 javax servlet http HttpServletResponse

积分
 公告控制器规格 延伸规格定义 "测试体存在于Api的json公告有效载荷中"() {
        给定RestBuilder的休息RestBuilder的什么时候: '要求发布版本'
        定义休息休息"HTTP本地主机${服务器端口}公告"标头"接受版本", "2.0")
        }

        然后: '请求成功'响应状态HttpServletResponse SC OK: '响应是JSON有效负载'resp标头获取'内容类型') == ['应用程序json字符集UTF']

        : 'json有效内容包含ID为title的通告数组'分别回复json断言 ID断言 标题断言 !身体(2)
        }
    }

    定义 "公告的测试详细信息包含版本和正文"() {
        给定:
1 serverPort属性是自动注入的,它包含功能测试期间运行365bet地区应用程序的随机端口
2 正文不在JSON有效负载中

365bet地区命令测试应用运行单元集成和功能测试

iOS V变更

首先,我们需要更改在中定义的Api版本常量365bet地区365bet地区Fetcher h

完整的ObjectiveC iOS v IntranetClient 365bet地区Fetcher h
进口静态NSString kServerUrl http静态NSString kApiVersion(1)365bet地区静态NSString kAnnouncementsResourcePath公告静态NSInteger快速时间间隔接口365bet地区Fetcher NSObject属性非原子性强NSURLSession会话NSURLRequest getURLRequestWithUrlString NSString urlString cachePolicy NSURLRequestCachePolicy cachePolicy timeoutInterval NSTimeInterval timeoutInterval end
1 使用Api版本

在版本中,Api不会返回公告的主体,而不是设置公告属性,我们将只在资源标识符主键中设置DetailViewController我们已经改变了prepareForSegue发送方法中MasterViewController如下图所示

完整的ObjectiveC iOS v IntranetClient MasterViewController m
void prepareForSegue UIStoryboardSegue,如果segue标识符为isEqualToString,则为segue发送者ID发送者;如果发送者为isKindOfClass,则为seSectionDestinationViewController topViewController;如果发送者为isKindOfClass,则为公告类。(1)控制器navigationItem leftBarButtonItem自身splitViewController displayModeButtonItem控制器navigationItem leftItemsSupplementBackButton是
1 代替设置对象,我们设置一个NS编号

DetailViewController要求服务器提供完整的公告正文

完整的ObjectiveC iOS v IntranetClient DetailViewController h
进口导入公告h接口DetailViewController UIViewController属性非原子分配NSNumber公告PrimaryKey结束
完整的ObjectiveC iOS v IntranetClient DetailViewController m
导入DetailViewController h导入公告h导入AnnouncementFetcher h接口DetailViewController属性非原子性弱IBOutlet UILabel titleLabel属性非原子性弱IBOutlet UIWebView webView属性非原子性IBOutlet UIActivityIndi​​catorView activityIndi​​catorView属性非原子性强AnnouncementFetcher fetcher属性非原子性强Announcement声明结束实现DetailViewController void configureView如果自声明selftitle则更新详细项目的用户界面self activityIndi​​catorView startAnimating self webView loadHTMLString self公告主体baseURL nil void viewDidLoad super viewDidLoad self webView委托self通常从笔尖self configureView加载视图后进行任何其他设置(如果selfannouncementPrimaryKey self fetcher fetchAnnouncement自助公告PrimaryKey编译标记)他的详细项目void setAnnouncement公告公告,如果公告公告公告公告,则更新视图自身configureView实用程序标记UIWebViewDelegate activityIndi​​catorView stop动画自我公告公告实用标记标记懒惰的AnnouncementFetcher的fetcher,如果fetcher fetcher的AnnouncementFetcher分配inititDelegate自返回fetcher结束

它使用了新的提取程序

完整的ObjectiveC iOS v IntranetClient AnnouncementFetcher h
进口365bet地区import 365bet地区Fetcher h import AnnouncementFetcherDelegate h接口AnnouncementFetcher 365bet地区Fetcher id initWithDelegate id委托无效fetchAnnouncement NSNumber primaryKey结束
完整的Objectivec iOS v IntranetClient AnnouncementFetcher m
import AnnouncementFetcher h import AnnouncementFetcherDelegate h import AnnouncementBuilder h接口AnnouncementFetcher属性非原子性弱ID委托属性非原子性强AnnouncementBuilder构建器最终实现AnnouncementFetcher编译指示mark生命周期ID initWithDelegate IDif自我超级委托,超级委托,self委托,委托委托,自我构建器,AnnouncementBuilder alloc init,返回,返回自我,实用标记自我代表自我代表announcementFetchingFailed返回NSString objectNotation NSString alloc initWithData数据编码NSUTF StringEncoding NSError builderError Announcement公告自我构建者NoticeFromJSON objectNotation error build erError如果builderError如果自我委托自我委托announcementFetchingFailed返回失败,如果自我委托自我委托announcementFetched声明实用标记私有方法NSString urlStr自声明URLString primaryKey返回超级getURLRequestWithUrlString urlStr cachePolicy NSURLRequestReloadIgnoringLocalCacheData timeoutInterval快速间隔NSStri ngannounceURLString NSNumber primaryKey返回NSString stringWithFormat kServerUrl kAnnouncementsResourcePath primaryKey结束

还有一个委托协议,用于指示是否已获取公告

完整的ObjectiveC iOS v IntranetClient AnnouncementFetcherDelegate h
进口类公告协议AnnouncementFetcherDelegate无效公告FetchingFailed无效公告Fetched Announcement公告结束

结论

365bet地区借助365bet地区轻松的API版本控制,我们现在可以支持两个运行不同版本的iOS应用程序

您需要365bet地区帮助吗

365bet地区服务:

免费咨询

OCI 365bet地区团队包括365bet地区联合创始人检查我们的并向发展和维护365bet地区的工程师学习

Grails OCI团队