引言:
StackMob 是一个轻量级的 Baas 移动后端云存储平台. 为移动App提供了强大的后台云存储能力,其SDK架接在Core Data身上,在不改变Core Data API 使用方式的前提下为Core Data 提供云端存储的能力,此篇专门介绍了 StackMob 在 iOS环境的使用方式.
参考资料:
1:StackMob 的主页
2:StackMob iOS开发文档
http://stackmob.github.io/stackmob-ios-sdk/
3:如何为iOS应用及游戏添加后台网络服务系列1 前言
http://blog.sina.com.cn/s/blog_4b55f6860101b991.html
4:StackMob SDK 官方使用教程
https://developer.stackmob.com/tutorials/ios
5:16小时的诱惑大致的介绍了StackMob从注册到使用的整个过程:
http://www.csdn.net/article/2013-03-19/2814542-build-an-airbnb-clone/1
安装:
StackMob是开源的,托管地址如下:
https://github.com/stackmob/stackmob-ios-sdk
安装的首先方式是CocoaPods.
可能遇到的问题:
1:解决AFNetworkKiting 安装后警告部署问题,详见这篇文章
2:解决 Reachability 类 的冲突问题,代码如下:
3:让 StackMob 连接至 Amazon S3 云存储服务
StackMob需要连接 Amazon S3 以后才拥有二进制文件的存储能力.
本篇博文大致的介绍了一下S3的注册流程,可以稍作参考:
第一步:前往亚马逊Web Services 注册一个开发者账号:
第二步:注册并激活 S3
注册并激活S3需要一张支持外币付费的信用卡,建议使用万事达卡.
在索要卡片的界面填写如下:
类型选择:MasterCard
信用卡卡号
持卡人 拼音名称. (按照信用卡上面填写)
成功以后会扣费一美元. 并收到开通S3服务的邮件提醒.
此时便已经开通了S3的服务,拥有了使用的权利,如果此时进入S3的控制台依旧提示你需要注册的话,是浏览器缓存的问题,清空即可.
第三步:进入 S3的管理控制台 创建一个 Bucket 如下图:
https://console.aws.amazon.com/s3
Region 选择服务器所在的国家,里咱越紧越好. 日本吧
第四步:摘用StackMob官方的连接教程,基本上就搞定了:
http://developer.stackmob.com/tutorials/dashboard/Adding-a-Binary-Field-to-Schemas
在配置最后一步的链接时有一个字段要特别注意,如下图所示:
那就是S3 Path Alias 这个字段的值在设置不对的情况下去使用它生成的访问链接,访问的结果始终是下图中的错误:
如何才能正确设置S3 Path Alias?
首先要了解S3 Path Alias到底是做什么用的,它一个链接地址别名
当我们用StackMob上传一个二进制文件成功以后,StackMob会自动根据S3 Path Alias所给定的值自动生成一个完整的二进制文件下载链接.
如何检验这个下载链接的正确性,我们可以前往S3的控制台,随便找一个已经上传成功的文件,查看其详细信息,如下图所示:
拿图中的Link和StackMob所生成的链接进行对比,看看有哪里不一样了. 如果不一样,那么S3 Path Alias的设置肯定有问题.
从上图来说,正确的S3 Path Alias设置方法应该是: http://s3-ap-northeast-1.amazonaws.com/musicpushtest/
最后S3的定价情况地址如下:(新用户注册免费12个月):
http://aws.amazon.com/cn/pricing/s3/
使用:
不足之处:
1:没有二进制文件上传进度
原因:求解决
2:多次发起查询请求和保存请求,都有可能产生Crash,
原因: 由于线程调用错乱 导致StackMob停止工作甚至Crash,使用前,请熟悉GCD,可以参考这篇教程. 这篇更全面
3:查询和保存请求发起后,无法立刻撤销,必须等待整个请求完成
原因:求解决
4:分页查询起始索引默认必需设置值大于0 才有效果:
原因:我估计代码内部BUG,注释掉 判断大于0 即可修正
5:查询一对多的对象以后在缓存到本地时,写入指定Plist文件时Crash
原因:NSDictionary的key 不是 NSString 所致, 修改了源代码 替换键值对的方法.
6:利用对象层级展开以后,却无法获取子对象数据
原因:求解决
功能要点:
一:关于二进制文件上传
1.设置Core Data 数据模型的字段为字符串类型.
2.手动设置StackMob 的 Schema 里对应的字段为二进制类型.
3.本地数据模型的字段名称和StackMob 的 Schema 的字段名称 关系如下:本地Core Data: userIcon Schema :user_icon
4.如果本地某个字段 对应着服务器的某个二进制字段时,就在上传服务器时必须通过如下代码赋值:
+ (NSString *)convertUploadWithPath:(NSString *)aPath withContentType:(NSString *)aContentType { NSData *data = [NSData dataWithContentsOfFile:aPath]; if (data) { NSString *dataString = [SMBinaryDataConversion stringForBinaryData:data name:[aPath lastPathComponent] contentType:aContentType]; return dataString; }else { return @"file?"; } }
注:任何其他方式的赋值都不允许,否则会出现让人无法理解的BUG.(特别注意)
上传成功的二进制文件字段需要通过执行以下代码才能获取二进制文件的下载链接
[[StackMobManager contextForCurrentThread] refreshObject:self.dmSongTyoe mergeChanges:YES];
但是这个只对 新增的对象启效果,如果你是 更新对象使用上面的代码刷新的话,会变回你之前修改的值. 那又怎么解决呢?
二:数据缓存机制
StackMob的缓存机制默认是关闭的,如果要开启,需要对以下全局变量赋值:
SM_CACHE_ENABLED = YES;
设置以后, StackMob会自动创建一个本地 Core Data数据库自动管理和缓存来自服务器的数据.
针对查询数据机制有一个枚举来决定其取数方式:
typedef enum { SMCachePolicyTryNetworkOnly = 0,//只从网络取 SMCachePolicyTryCacheOnly = 1, //只从缓存取 SMCachePolicyTryNetworkElseCache = 2,//先从网络取,取不到用缓存替代 SMCachePolicyTryCacheElseNetwork = 3,//这个还没研究过 } SMCachePolicy;
如果用户更改了设备的网络环境,可以通过以下Block去修改查询数据机制:
SMClient *client = [[SMClient alloc] initWithAPIVersion:@"0" publicKey:@"XXXX"]; SMCoreDataStore *coreDataStore = [client coreDataStoreWithManagedObjectModel:myModel]; [client.session.networkMonitor setNetworkStatusChangeBlockWithCachePolicyReturn:^SMCachePolicy(SMNetworkStatus status) { if (status == Reachable) { return SMCachePolicyTryNetworkElseCache; } else { return SMCachePolicyTryCacheOnly; } }];
那么在App启动的时候,判断一下当前的网络环境,设置好查询数据机制:
if ([Reachability isEnable3G] || [Reachability isEnableWIFI]) { [self.keyCoreDataStore setCachePolicy:SMCachePolicyTryNetworkElseCache]; }else { [self.keyCoreDataStore setCachePolicy:SMCachePolicyTryCacheOnly]; }
三:关于保存(saveOnSuccess)
对Object的任何增删改都通过saveOnSuccess 来保持云端的数据同步.
用起来蛮简单,不过也有些小细节要注意,否则也非常纠结.
1.saveOnSuccess因为一些网络原因或者保存重复主键等问题导致保存失败,会进入失败的Block.
如果连续进入三,四次左右的失败Block,它~~~~~ 它~丫的~ App就Crash了. 卧槽... 什么@try @catch 全都挡不住这个崩溃.
解决办法是在失败的Block里面执行Core Data上下文删除刚刚需要保存的对象的操作.
[StackMobManager contextForCurrentThread] deleteObject:obj];这样不管你点多少次都不会 Crash了,我觉得这是 StackMob设计上的一些不足,不够我也是菜鸟,不能够做多评论.
2.Updating passwords via this API is disabled for security reasons. Use the resetPassword API instead
这个提示通过控制台打印过来,大意是说你当前的保存数据请求被云端给限制了.
我是怎么触发这个Error的?
当我发起创建一个新User对象的同时,再多保存了一个File对象.File对象依赖于User对象,也就是说File对象的所有权是User对象的,但是你创建User对象的时候,你并没有登录.
处于授权安全机制,本次保存请求就算是失败,(即使数据已经保存到了云端).
解决办法是不要急着一起次保存到云端,只有等登录成功以后,再去发起File对象的保存请求即可.
四:关于查询(executeFetchRequest)
对Object的查询就靠这个函数了,基本雷同CoreData的查询函数,StackMob提供两种发起查询请求的方式.
一种是内部构建多线程运作工作,不会卡住主线程和影响界面,完成后通过主线程告知:
但是,连续多次发起这种请求方式, 有极高的几率导致整个SDK停止工作. 这是个比较严重的问题,应该是StackMob 的BUG,
另外一种则是不构建多线程,如果直接执行,在没返回结果之前会卡住主线程,影响界面体验,但是我们可以自己使用GCD来避免主线程阻塞的这个问题
用这种方式似乎可以避免多次发起请求所产生的BUG,至少暂时没发现.
在发起查询请求之前有一个参数类要特别的注意一下,这个类也是实现个性化查询的一个重要途径之一,
它是SMRequestOptions
它有什么用:
1:是否要求刷新Token? tryRefreshToken
2:以HTPPS加密的方式安全获取数据? isSecure
3:当请求网络超时时,重试几次呢? numberOfRetries
4:返回的数据结构需要展开几个层次?(最多三级) setExpandDepth
5:只是想返回某几个字段的数据而已 restrictReturnedFieldsTo
总结: