美文网首页
关于地址传递的一处笔记

关于地址传递的一处笔记

作者: 大成小栈 | 来源:发表于2020-03-10 21:38 被阅读0次

    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 的格式为:

    其中

    1. product_key:产品的唯一标识符

    2. device_name:设备的唯一标识符

    3. dsl_type:产品物模型的定义类型,值只能为:property, event ,注意区分大

      小写

    4. dsl_event_identifier:产品物模型中事件的唯一标识符,只有当 dsl_type=event

      时,该字段存在

    5. opertaion 中的 operator:

      表示操作符类型,为数值型,值只能为: operator=1:表示大于(>) operator=2:表示大于等于(>=) operator=3:表示小于(<) operator=4:表示小于等于(<=) operator=5:表示等于(==) operator=6:表示不等于(!=) operator=7:表示 between operator=8:表示 in

    6. opertaion 中的 limitValue: 字符串,但字符串中的值必须要物模型定义的类型保持一致。 当操作符为 in 时,value 的值为英文逗号隔开的字符串。
      当为 bewteen 时,value 的值为英文逗号隔开的字符串,只能有两个元素

    7. 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 的格式为:

      如果为设置设备属性

    如果为服务调用属性

    其中:

    1. product_key:产品的唯一标识符

    2. device_name:设备的唯一标识符

    3. {identifer}:用大括号括起来表示变量的意思,此字段为产品物模型的唯一

      标识符,当 payload.action=”dsl.property.set”时,该变量字段为产品物模型属 性的唯一标识符,当 payload.action=”dsl.service.{identifier}时,此变量为产 品物模型服务的唯一标识符,

    4. 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回调,其参数为空,主要起了通知的作用。

    注意:

    1. 在一个参数中如果包含多级json格式的字符串,需要根据服务端规定,是分级转化,还是一次性转化为json字符串;
    2. processScene传递的全过程都是引用传递,因此,在回调block中,直接处理当前类中的processScene这个实例中的参数即可。

    相关文章

      网友评论

          本文标题:关于地址传递的一处笔记

          本文链接:https://www.haomeiwen.com/subject/blmgdhtx.html