1. 值传递与地址传递
值传递:形参和实参占不同内存单元,传递的实际上是实参变量或表达式的一个拷贝副本。形参的值发生变化也不会传回给实参,是单向传递。
地址传递:传递的是实参变量地址的拷贝值,而不是实参变量的值,在被调函数中对地址所指对象的操作会改变实参的值。但是形参的内容即存放的实参变量地址并不会改变。
2. 地址传递与复杂结构的数据model
最近工作内容是验证IoT平台创建场景的功能,写一个demo去请求场景相关接口,并展示场景相关数据。其中创建场景的接口及界面如下:
2.1 创建场景的接口
/*!
@brief 创建场景
@param sceneName 场景名称
@param sceneDescription 场景描述
@param userType 用户类型 user_type=1 表示企业 user_type=2 表示个人用户
@param conditionType 场景触发条件类型: scene_condition_type=1 同时满足 scene_condition_type=2 任意满足
@param triggerCondition 触发条件,为 array 对象的字符串,该列表 是 json 对象数组,json 对象字段详见: trigger_condition 表
@param executeAction 执行动作,为 array 对象的字符串,该列表 是 json 对象数组,json 对象字段详见: execute_action 表
@param extra 业务所需用用户信息参数,数据格式 json , 详见文档
@param handler 回调block
*/
+ (NSURLSessionDataTask *)createSceneWithSceneName:(NSString *)sceneName
sceneDescription:(NSString *)sceneDescription
userType:(NSInteger)userType
sceneConditionType:(NSInteger)conditionType
triggerCondition:(NSString *)triggerCondition
executeAction:(NSString *)executeAction
extra:(NSString *)extra
handler:(QSLNetRequestHandler)handler;
请求参数:
名称 | 类型 | 必选 | 描述 |
---|---|---|---|
scene_name | string | 是 | 场景名称,全局唯一 |
scene_description | string | 否 | 场景描述 |
user_type | int | 是 | 用户类型 user_type=1 表示企业 user_type=2 表示个人用户 |
scene_condition_t ype | int | 是 | 场景触发条件类型: scene_condition_type=1 同时满足 scene_condition_type=2 任意满足 |
trigger_condition | string | 是 | 触发条件,为 array 对象的字符串,该列表 是 json 对象数组,json 对象字段详见: trigger_condition 表 |
execute_action | string | 是 | 执行动作,为 array 对象的字符串,该列表 是 json 对象数组,json 对象字段详见: execute_action 表 |
extra | string | 否 | 业务所需用用户信息参数,数据格式 json , 如 extra= {"qid":"123456","openid":"fq415fqe"}。 json 的 key 和值都是字符串类 型 ,注:对于 To C 用户如果该字段不填写 qid(360 账户 id 或者 openid(其他账户的 id),必须走用户验 证在 http 的 header 中设置 AuthMethod,同 时设置公共参数 auth |
trigger_condition 表
名称 | 类型 | 必选 | 描述 |
---|---|---|---|
trigger_condition_type | int | 是 | 触发条件类型: trigger_condition_type=1 指定设备触发 trigger_condition_type=2 指定时间触发 |
trigger_logic | object | 是 | 触发逻辑 |
- 当 trigger_condition_type=1 时,trigger_logic 的格式为:
其中
-
product_key:产品的唯一标识符
-
device_name:设备的唯一标识符
-
dsl_type:产品物模型的定义类型,值只能为:property, event ,注意区分大
小写
-
dsl_event_identifier:产品物模型中事件的唯一标识符,只有当 dsl_type=event
时,该字段存在
-
opertaion 中的 operator:
表示操作符类型,为数值型,值只能为: operator=1:表示大于(>) operator=2:表示大于等于(>=) operator=3:表示小于(<) operator=4:表示小于等于(<=) operator=5:表示等于(==) operator=6:表示不等于(!=) operator=7:表示 between operator=8:表示 in
-
opertaion 中的 limitValue: 字符串,但字符串中的值必须要物模型定义的类型保持一致。 当操作符为 in 时,value 的值为英文逗号隔开的字符串。
当为 bewteen 时,value 的值为英文逗号隔开的字符串,只能有两个元素 -
operation 中的 identifier:
当 dsl_type=property 时,该字段为物模型属性的唯一表示符 当 dsl_type=event 时,该字段为物模型事件参数的唯一标识符
注意:当 dsl_type=event 时,如果用户没有设置可选参数或者事件不存在参数, operation 字段不存在。
- 当 trigger_condition_type=2 时:
trigger_logic 中的存在 ts_trigger_type 字段,该字段的值为: ts_trigger_type = 1:表示固定时间点触发
ts_trigger_type = 2:表示定时触发
当 ts_trigger_type = 1,trigger_logic 格式为:
{
“ts_trigger_type”:1,
“timestamp”:6753524224 //时间戳,精确到秒
}
当 ts_trigger_type = 2,trigger_logic 格式为:
{
“ts_trigger_type”:2,
“minute”:“0”, //分钟,0-59
“hour”:”0”, //小时 ,0-23 “day_of_month”:”0”, //月中的天数 ,1-31 “month”:”0”,// 1-12
“day_of_week”:”0”,// 0-6
}
trigger_condition 字段格式 Demo:
execute_action 表
名称 | 类型 | 是否必须 | 描述 |
---|---|---|---|
execute_action_type | int | 是 | 执行动作类型: execute_action_type=1 指定设备执行 execute_action_type=2 指定场景执行 |
execute_action_logic | object | 否 | 执行设备动作逻辑 当 execute_action_type=1 时,该字段必填 |
execute_scene_id | string | 否 | 执行场景的 id 当 execute_action_type=2 时,该字段必填, 此时,该场景不能再次包含子场景 |
-
当 execute_action_type=1 时,execute_action_logic 的格式为:
如果为设置设备属性
如果为服务调用属性
其中:
-
product_key:产品的唯一标识符
-
device_name:设备的唯一标识符
-
{identifer}:用大括号括起来表示变量的意思,此字段为产品物模型的唯一
标识符,当 payload.action=”dsl.property.set”时,该变量字段为产品物模型属 性的唯一标识符,当 payload.action=”dsl.service.{identifier}时,此变量为产 品物模型服务的唯一标识符,
-
data:当 payload.action=”dsl.property.set”时,data 为属性的 json kv 对象 ({“propeortyIdentifier”:”propertyValue”})。当 payload.action=”dsl.service.{identifier}时,data 为入参的 json kv 对象 ({“serviceParameterIdentifier”:”parameterValue"}),非必填。
execute_action 字段格式 demo:
2.2 创建场景的过程
2.3 引用传递的应用
在普通的网络请求中,一般传递的参数都比较简单,直接写在一个dictionary里面,借助AFN等三方库发出去。对于这种结构复杂一些的参数,处理过程分多步进行,我们会在不同界面记录不同的参数,并在操作最后将所有记录的参数整合为规定的格式,发送出去。那么我们会先创建并实例化一个数据model:
- 创建场景model
创建的数据模型为SHScene,其中所有的参数都与请求参数结构有相应的对应项,其实这个model是与场景详情model复用的一个类。
#import <Foundation/Foundation.h>
#import "SHDevice.h"
@class SHSceneTriggerCondition;
@class SHSceneTriggerLogic;
@class SHSceneExecuteAction;
@class SHSceneActionLogic;
@class SHScene;
/// 修改、新建场景 回调block
typedef void(^SHProcessSceneBlock)(void);
/// 场景model
@interface SHScene : NSObject
// 用户类型 1: 企业 2:个人
@property (nonatomic, assign) NSInteger userType;
// 场景类型 1:云端场景 2:边缘场景
@property (nonatomic, assign) NSInteger sceneType;
// 场景ID
@property (nonatomic, strong) NSString *sceneId;
// 场景名
@property (nonatomic, strong) NSString *sceneName;
// 场景描述
@property (nonatomic, strong) NSString *sceneDesc;
// 场景状态
@property (nonatomic, assign) NSInteger sceneStatus;
// 是否包含子场景 1 包含 2 不包含
@property (nonatomic, assign) NSInteger hasChild;
// 创建时间戳,精确到秒
@property (nonatomic, strong) NSString *create_ts;
// 修改时间戳,精确到秒
@property (nonatomic, strong) NSString *modify_ts;
// 场景触发类型 1同时满足 2任意满足
@property (nonatomic, assign) NSInteger sceneConditionType;
// 触发条件,为 array 对象,array 中为 json
@property (nonatomic, strong) NSMutableArray<SHSceneTriggerCondition *> *triggerConditionArr;
// 执行动作,为 array 对象,array 中为 json
@property (nonatomic, strong) NSMutableArray<SHSceneExecuteAction *> *executeActionArr;
- (instancetype)initWithDict:(NSDictionary *)dict;
+ (NSArray<SHScene *> *)sceneListWithWithList:(NSArray *)list;
@end
/// 触发条件
@interface SHSceneTriggerCondition : NSObject
// 触发条件类型 1:设备触发 2:时间触发
@property (nonatomic, assign) NSInteger triggerConditionType;
// 触发逻辑
@property (nonatomic, strong) SHSceneTriggerLogic *triggerLogic;
- (instancetype)initWithDict:(NSDictionary *)dict;
@end
@interface SHSceneTriggerLogic : NSObject
// 时间触发 1:固定时间点触发 2:定时触发
@property (nonatomic, assign) NSInteger tsTriggerType;
// 时间戳(固定时间点 - 秒)
@property (nonatomic, assign) NSInteger timestamp;
// 定时参数
@property (nonatomic, strong) NSString *minute;
@property (nonatomic, strong) NSString *hour;
@property (nonatomic, strong) NSString *dayOfWeek;
@property (nonatomic, strong) NSString *dayOfMonth;
@property (nonatomic, strong) NSString *month;
// 设备触发
@property (nonatomic, strong) NSString *productKey;
@property (nonatomic, strong) NSString *deviceName;
@property (nonatomic, strong) NSString *dslType;
@property (nonatomic, strong) NSString *dslEventIdentifer;
@property (nonatomic, strong) NSDictionary *operation;
- (instancetype)initWithDict:(NSDictionary *)dict;
@end
/// 执行动作
@interface SHSceneExecuteAction : NSObject
// 1:设备执行 2:场景执行
@property (nonatomic, assign) NSInteger executeActionType;
@property (nonatomic, strong) NSString *executeSceneId;
@property (nonatomic, strong) SHSceneActionLogic *actionLogic;
- (instancetype)initWithDict:(NSDictionary *)dict;
@end
@interface SHSceneActionLogic : NSObject
@property (nonatomic, strong) NSString *productKey;
@property (nonatomic, strong) NSString *deviceName;
@property (nonatomic, strong) NSDictionary *payload;
- (instancetype)initWithDict:(NSDictionary *)dict;
@end
- 传递过程
1)实例化界面间传递的用于记录参数的变量
// 1.如果为创建场景,则重新初始化; 2. 如果为修改场景,则有初始值。
SHScene *processScene;
选择触发条件
2)实例化SHSceneTriggerCondition、SHSceneTriggerLogic,在点击确认按钮时追加至processScene。
// 实例化
_triggerCondition = [[SHSceneTriggerCondition alloc] init];
_triggerCondition.triggerConditionType = 2;
_triggerLogic = [[SHSceneTriggerLogic alloc] init];
_triggerLogic.tsTriggerType = 1;
_triggerCondition.triggerLogic = _triggerLogic;
// 处理后追加至processScene
[_processScene.triggerConditionArr addObject:_triggerCondition];
选择触发条件-定时
3)该处我们选择某设备来执行一个动作
4)实例化SHSceneTriggerCondition、SHSceneExecuteAction,注意,该界面内并没有直接追加至processScene,只是加以处理并向后传递。
// 实例化
_triggerCondition = [[SHSceneTriggerCondition alloc] init];
_triggerCondition.triggerConditionType = 1;
_executeAction = [[SHSceneExecuteAction alloc] init];
_executeAction.executeActionType = 1;
SHSceneActionLogic *actionLogic = [[SHSceneActionLogic alloc] init];
_executeAction.actionLogic = actionLogic;
// 加以处理,并传递
- (void)handleConditionWithIndex:(NSIndexPath *)indexPath {
SHSceneTriggerLogic *triggerLogic = [[SHSceneTriggerLogic alloc] init];
triggerLogic.dslType = indexPath.section == 0 ? @"property" : @"event";
triggerLogic.productKey = _device.productKey;
triggerLogic.deviceName = _device.deviceName;
_triggerCondition.triggerLogic = triggerLogic;
SHParamValueController *pvController = [[SHParamValueController alloc] init];
pvController.device = _device;
pvController.processScene = _processScene;
pvController.processSceneBlock = _processSceneBlock;
pvController.triggerCondition = _triggerCondition;
if (indexPath.section == 0) {
SHDslAttributeItem *attribute = [_dslInfo.attributes objectAtIndex:indexPath.row];
pvController.attribute = attribute;
}
else {
SHDslEventItem *event = [_dslInfo.events objectAtIndex:indexPath.row];
pvController.event = event;
triggerLogic.dslEventIdentifer = event.identifier;
}
[self.navigationController pushViewController:pvController animated:YES];
}
- (void)handleActionWithIndex:(NSIndexPath *)indexPath {
SHSceneActionLogic *actionLogic = [[SHSceneActionLogic alloc] init];
actionLogic.productKey = _device.productKey;
actionLogic.deviceName = _device.deviceName;
_executeAction.actionLogic = actionLogic;
SHParamValueController *pvController = [[SHParamValueController alloc] init];
pvController.device = _device;
pvController.processScene = _processScene;
pvController.processSceneBlock = _processSceneBlock;
pvController.executeAction = _executeAction;
if (indexPath.section == 0) {
SHDslAttributeItem *attribute = [_dslInfo.attributes objectAtIndex:indexPath.row];
pvController.attribute = attribute;
}
else {
SHDslServiceItem *service = [_dslInfo.services objectAtIndex:indexPath.row];
pvController.service = service;
}
[self.navigationController pushViewController:pvController animated:YES];
}
5)处理triggerLogic、actionLogic的逻辑
6)最后点击“确定”之后生成的参数格式为:
{
"extra" : "",
"execute_action" : "[{\"execute_action_logic\":{\"device_name\":\"2435cc0d7468\",\"product_key\":\"001d65593c9d\",\"payload\":{\"data\":{\"SpeedGear\":\"6\"},\"action\":\"dsl.property.set\"}},\"execute_action_type\":1}]",
"trigger_condition" : "[{\"trigger_condition_type\":2,\"trigger_logic\":{\"ts_trigger_type\":1,\"timestamp\":1583848140}}]",
"scene_condition_type" : 2,
"scene_name" : "Wdce",
"scene_description" : "",
"user_type" : 2
}
由于自定义类的实例化对象在传递过程中,始终都是引用传递,所以,在点击确定之后新建智能界面可以直接根据processScene刷新界面,并生成最终的请求参数。因为创建场景过程分支较多,为了便于及时刷新界面,因此我们在传递过程中也传递了一个processSceneBlock回调,其参数为空,主要起了通知的作用。
注意:
- 在一个参数中如果包含多级json格式的字符串,需要根据服务端规定,是分级转化,还是一次性转化为json字符串;
- processScene传递的全过程都是引用传递,因此,在回调block中,直接处理当前类中的processScene这个实例中的参数即可。
网友评论