一、背景及大纲介绍

 在如今物联网DCM(Device、Connect、Manage)的大框架下,有一个应用层来分析和处理数据,是必备技能。但是,对于一个公司来说,因为研发能力或者研发时间的原因,可能很难短期内完全自己开发出一个适用的App来。写代码、封装通用功能、还要考虑其他多种功能,统统都是很耗费时间的事情。现在很多物联网平台公司,为了帮助开发者解决此类问题,也想出了相应的解决办法,提供相应的SDK就是其中一种。

   今天抽空以基于App SDK完成智能家居App的开发为例。通过这一篇文章,你就能通过创建App SDK、集成SDK、创建家庭、设备配网和设备控制等步骤,完整地完成一款智能家居App的开发。

先列一下开发大纲:

创建App SDK

集成SDK

注册和登录

创建家庭

设备配网

设备控制

我们再来简单介绍一下Tuya App SDK:

涂鸦智能 App SDK 专为 IoT 移动 App 开发打造,提供丰富组件和示例代码,开发者可以快速实现移动 App 对智能设备的连接、控制以及丰富的智能场景应用。

产品的优势在于:

低门槛快速集成:快速集成 SDK,提供示例代码、Demo App、接入案例等,低门槛轻松上手;

开发组件丰富:组件化开发,提供垂直品类 SDK、UI 业务包等功能组件,开发者根据需求灵活组合;

智能功能全面:全面覆盖用户、设备、智能场景等多种功能模块,开发者只需简单实现 UI 层代码;

主流通信协议兼容:同一 App 中支持添加和使用主流通信协议产品,轻松实现 All In One – App;

全球数据安全保障:双通道安全加密,五重安全策略,全球数据安全合规认证,全面保障用户数据隐私安全;

全球服务稳定:全球化智能云部署,让每一个 App 都轻松拥有亿级海量设备和千万级用户并发处理能力。

App SDK的技术架构如下:

二、如何基于 App SDK 开发一个 App

   准备就绪,我们来开始开发!

(一)创建App SDK

  1. 注册开发者账号

    前往 涂鸦智能开发平台 注册开发者账号、创建产品、创建功能点等,具体流程请参考接入流程

  2. 创建SDK应用

    涂鸦 IoT 平台中 “App 工作台” 中点击 “App SDK”,点击“创建 App”。

填写 App 相关信息,点击确认。

  • 应用名称:填写您的 App 名称。
  • iOS 应用包名:填写您的 iOS App 包名(建议格式:com.xxxxx.xxxxx)。
  • 安卓应用包名:填写您的安卓 App 包名(两者可以保持一致,也可以不一致)。
  • 渠道标识符:不是必填项,如果不填写,系统会根据包名自动生成。

您可以根据实际需求选择需要的选择方案,支持多选,然后根据 Podfile 和 Gradle 进行 SDK 的集成。

点击获取密码,获取 SDK 的 AppKey,AppSecret,安全图片等信息。

(二)集成 SDK

  1. 使用 CocoaPods 快速集成

请注意:SDK 最低支持系统版本 9.0

在 Podfile 文件中添加以下内容:

`platform :ios, '9.0'

target 'Your_Project_Name' do

pod "TuyaSmartHomeKit"

end然后在项目根目录下执行pod update` 命令进行集成。

  1. 初始化 SDK

1) 打开项目设置,Target => General,修改 Bundle Identifier 为涂鸦开发者平台对应的 iOS 包名

2) 导入安全图片到工程根目录,重命名为 t_s.bmp,并加入「项目设置 => Target => Build Phases => Copy Bundle Resources」中。

3) 在项目的PrefixHeader.pch文件添加以下内容:

#import <TuyaSmartHomeKit/TuyaSmartKit.h>

4) 打开AppDelegate.m文件,在[AppDelegate application:didFinishLaunchingWithOptions:]方法中初始化SDK。

接口说明

初始化 SDK

  • (void)startWithAppKey:(NSString *)appKey secretKey:(NSString *)secretKey;

    参数说明

实例代码

[[TuyaSmartSDK sharedInstance] startWithAppKey:<#your_app_key#> secretKey:<#your_secret_key#>];

3. 打开 Debug 模式

在开发的过程中可以开启 Debug 模式,打印一些日志用于分析问题,开发结束上线后建议关闭。

`#ifdef DEBUG

[[TuyaSmartSDK sharedInstance] setDebugMode:YES];

else

endif`

(三)注册和登录

涂鸦云支持多种用户体系:手机、邮箱、UID。其中手机支持验证码登录和密码登录两种方式,UID 登录主要用于已经有自己账号体系的场景。我们这里采用手机验证码注册登录。

在注册登录方法中,需要提供 countryCode 参数(国家区号),用于就近选择涂鸦云的可用区。各个可用区的数据是相互独立的,因此在 中国大陆(86) 注册的账号,在 美国(1) 无法使用(用户不存在)。

  1. 手机密码注册

手机号密码注册流程分为以下两步: 获取手机验证码 - 注册账号

`// 发送验证码

[[TuyaSmartUser sharedInstance] sendVerifyCode:@"86" phoneNumber:@"1300****" type:1 success:^{

[TPDemoProgressUtils showSuccess:@"Verification code sent successfully" toView:nil];

} failure:^(NSError *error) {

[TPDemoProgressUtils showError:error.localizedDescription];

}];

// 通过验证码注册账号

[[TuyaSmartUser sharedInstance] registerByPhone:@"86" phoneNumber:@"1300*" password:@"" code:@"code" success:^{

// 注册成功,跳转到首页

[[TYDemoApplicationImpl sharedInstance] resetRootViewController:[TYDemoTabBarViewController class]];

} failure:^(NSError *error) {

[TPDemoProgressUtils showError:error.localizedDescription];

}];`

2. 判断是否已经登录

在程序启动后,如果登录过了就不需要重复登录,session的有效期是45天,直接到设备列表页面。如果没有登录过,就先到登录页进行登录,登录成功后再跳转到设备列表页。

`// 判断是否已经登录

if ([TuyaSmartUser sharedInstance].isLogin) {

// 首页

[self resetRootViewController:[TYDemoTabBarViewController class]];

} else {

// 登录页

[[TYDemoRouteManager sharedInstance] openRoute:kTYDemoPopLoginVC withParams:nil];

}`

  1. Session 失效处理

长期未登录或者密码修改后的账号,在访问服务端接口的时候会返回 Session 过期的错误,需要监听 TuyaSmartUserNotificationUserSessionInvalid 通知,跳转至登录页面重新登录。

`- (void)loadNotification {

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sessionInvalid) name:TuyaSmartUserNotificationUserSessionInvalid object:nil];

}

  • (void)sessionInvalid {

      NSLog(@"sessionInvalid");
    
      //跳转至登录页面
    
      MyLoginViewController *vc = [[MyLoginViewController alloc] init];
    
      self.window.rootViewController = vc;
    
    [self.window makeKeyAndVisible];

}`

(四) 创建家庭

用户登录成功后需要通过 TuyaSmartHomeManager 去获取整个家庭列表的信息,然后初始化其中的一个家庭TuyaSmartHome,获取家庭详情信息,就可以对家庭中的设备进行操作控制。

  1. 家庭列表获取

在设备列表页面,我们先获取用户下的家庭列表,如果没有家庭,我们创建一个默认家庭。因为设备激活的时候,需要把设备添加到家庭里面。

获取到家庭列表之后,我们就可以初始化一个家庭,然后从云端获取家庭的详情,刷新首页的设备列表。

`- (void)initData {

_homeManager = [[TuyaSmartHomeManager alloc] init];

_homeManager.delegate = self;

// 获取本地的当前家庭

NSString *homeId = [[NSUserDefaults standardUserDefaults] objectForKey:kDefaultCurrentHomeId];

if ([homeId longLongValue] > 0) {

    self.home = [TuyaSmartHome homeWithHomeId:[homeId longLongValue]];

    if (self.home) {

        self.home.delegate = self;

        self.topBarView.leftItem.title = [NSString stringWithFormat:@"%@ ∨", self.home.homeModel.name];

        [TYDemoSmartHomeManager sharedInstance].currentHomeModel = self.home.homeModel;

        // 刷新设备列表数据

        [self reloadDataFromCloud];

    } else {

        // 如果没有,获取第一个家庭

        [self loadFirstHomeData];

    }

} else {

    // 如果没有,获取第一个家庭

    [self loadFirstHomeData];

}

}

  • (void)reloadDataFromCloud {

    WEAKSELF_AT

    [self.refreshControl beginRefreshing];

    // 获取当前家庭的详情,并刷新列表

    [self.home getHomeDetailWithSuccess:^(TuyaSmartHomeModel *homeModel) {

      [weakSelf_AT reloadData];

    } failure:^(NSError *error) {

      if ([error.localizedFailureReason isEqualToString:@"PERMISSION_DENIED"]) {
    
          [weakSelf_AT loadFirstHomeData];
    
      }
    
      [weakSelf_AT.refreshControl endRefreshing];

    }];

}`

2. 新增一个家庭

`// add home

  • (void)rightBtnAction {

    NSString *homeName = [NSString stringWithFormat:@"Home_%@", @(self.homeManager.homes.count)];

    WEAKSELF_AT

    [self.homeManager addHomeWithName:homeName geoName:@"hangzhou" rooms:@[@"room1"] latitude:0 longitude:0 success:^(long long homeId) {

      [TPDemoProgressUtils showSuccess:@"Add Success" toView:nil];
    
      // 切换到新增家庭
    
      TuyaSmartHome *home = [TuyaSmartHome homeWithHomeId:homeId];
    
      [weakSelf_AT swithCurrentHomeIdWithHomeModel:home.homeModel];

    } failure:^(NSError *error) {

      [TPDemoProgressUtils showError:error.localizedDescription];

    }];

}`

3. 家庭列表信息变化回调

实现 TuyaSmartHomeManagerDelegate 代理协议后,可以在家庭列表更变的回调中进行处理。

`#pragma mark - TuyaSmartHomeManagerDelegate

// 添加一个家庭

  • (void)homeManager:(TuyaSmartHomeManager *)manager didAddHome:(TuyaSmartHomeModel *)home {

    NSLog(@"Add a home %@", home.name);

}

// 删除一个家庭

  • (void)homeManager:(TuyaSmartHomeManager *)manager didRemoveHome:(long long)homeId {

    // 如果删除的家庭是当前家庭,当前家庭切换到另外一个

    if ([TYDemoSmartHomeManager sharedInstance].currentHomeModel.homeId == homeId) {

      [self loadFirstHomeData];

    }

}

// MQTT连接成功

  • (void)serviceConnectedSuccess {

    // 去云端获取当前家庭的详情,然后去刷新 UI

    [self reloadDataFromCloud];

}`

  1. 单个家庭信息变化的回调

实现 TuyaSmartHomeDelegate 代理协议后,可以在单个家庭信息更变的回调中进行处理。

`#pragma mark - TuyaSmartHomeDelegate

// 家庭的信息更新,例如name

  • (void)homeDidUpdateInfo:(TuyaSmartHome *)home {

    [self.tableView reloadData];

}

// 添加一个房间

  • (void)home:(TuyaSmartHome *)home didAddRoom:(TuyaSmartRoomModel *)room {

    [self.tableView reloadData];

}

// 删除一个房间

  • (void)home:(TuyaSmartHome *)home didRemoveRoom:(long long)roomId {

    [self.tableView reloadData];

}

// 我收到的共享设备列表变化

  • (void)homeDidUpdateSharedInfo:(TuyaSmartHome *)home {

    [self.tableView reloadData];

}

// 房间信息变更,例如name

  • (void)home:(TuyaSmartHome *)home roomInfoUpdate:(TuyaSmartRoomModel *)room {

    [self.tableView reloadData];

}

// 房间与设备,群组的关系变化

  • (void)home:(TuyaSmartHome *)home roomRelationUpdate:(TuyaSmartRoomModel *)room {

    [self.tableView reloadData];

}

// 添加设备

  • (void)home:(TuyaSmartHome *)home didAddDeivice:(TuyaSmartDeviceModel *)device {

    [self.tableView reloadData];

}

// 删除设备

  • (void)home:(TuyaSmartHome *)home didRemoveDeivice:(NSString *)devId {

    [self.tableView reloadData];

}

// 设备信息更新,例如name

  • (void)home:(TuyaSmartHome *)home deviceInfoUpdate:(TuyaSmartDeviceModel *)device {

    [self.tableView reloadData];

}

// 设备dp数据更新

  • (void)home:(TuyaSmartHome *)home device:(TuyaSmartDeviceModel *)device dpsUpdate:(NSDictionary *)dps {

    [self.tableView reloadData];

}

// 添加群组

  • (void)home:(TuyaSmartHome *)home didAddGroup:(TuyaSmartGroupModel *)group {

    [self.tableView reloadData];

}

// 群组dp数据更新

  • (void)home:(TuyaSmartHome *)home group:(TuyaSmartGroupModel *)group dpsUpdate:(NSDictionary *)dps {

    [self.tableView reloadData];

}

// 删除群组

  • (void)home:(TuyaSmartHome *)home didRemoveGroup:(NSString *)groupId {

    [self.tableView reloadData];

}

// 群组信息更新,例如name

  • (void)home:(TuyaSmartHome *)home groupInfoUpdate:(TuyaSmartGroupModel *)group {

    [self.tableView reloadData];

}`

(五) 设备配网

设备配网是指设备在云端进行激活注册。

  1. 相关类

  1. EZ 配网

这里主要介绍下 EZ 模式开发,又称快连模式(SmartConfig)。

`

  • (void)addDeviceWithEZMode {

    // 获取token

    WEAKSELF_AT

    id impl = [[TYDemoConfiguration sharedInstance] serviceOfProtocol:@protocol(TYDemoDeviceListModuleProtocol)];

    long long homeId = [impl currentHomeId];

    [[TuyaSmartActivator sharedInstance] getTokenWithHomeId:homeId success:^(NSString *token) {

      // 开始配网
    
      [weakSelf_AT commitEZModeActionWithToken:token];

    } failure:^(NSError *error) {

      info = [NSString stringWithFormat:@"%@: token fetch failed, error message is %@",NSStringFromSelector(_cmd),error.localizedDescription];
    
      [weakSelf_AT appendConsoleLog:info];

    }];

}

// 开始配网

  • (void)commitEZModeActionWithToken:(NSString *)token {

    [TuyaSmartActivator sharedInstance].delegate = self;

    [[TuyaSmartActivator sharedInstance] startConfigWiFi:TYActivatorModeEZ ssid:self.ssidField.text password:self.passwordField.text token:token timeout:timeout];

}

pragma mark - TuyaSmartActivatorDelegate

  • (void)activator:(TuyaSmartActivator *)activator didReceiveDevice:(TuyaSmartDeviceModel *)deviceModel error:(NSError *)error {

    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(countDown) object:nil];

    timeout = timeLeft;

    [self hideProgressView];

    NSString *info = [NSString stringWithFormat:@"%@: Finished!", NSStringFromSelector(_cmd)];

    [self appendConsoleLog:info];

    if (error) {

      // 配网失败
    
      info = [NSString stringWithFormat:@"%@: Error-%@!", NSStringFromSelector(_cmd), error.localizedDescription];
    
      [self appendConsoleLog:info];

    } else {

      // 配网成功
    
      info = [NSString stringWithFormat:@"%@: Success-You've added device %@ successfully!", NSStringFromSelector(_cmd), deviceModel.name];
    
      [self appendConsoleLog:info];

    }

}`

智能设备配网成功后就有了联网能力,就可以进行远程控制了。

(六)设备控制

设备激活后,就可以进行智能设备的控制,然后监听设备控制变化的回调。

  1. 相关类

在进行设备控制之前,我们先了解下设备功能点的概念。

  1. 设备功能点

功能点是对产品功能的抽象表示,是具体智能设备功能的抽象,用于描述产品功能及其参数。

• 功能点 ID:功能点的编码。设备与云端的功能数据通过功能点 ID 进行传输。

• 功能点名称:自定义的功能名称。

• 标识名:功能点 Code 值,用于 App 显示功能名称的多语言管理。支持字母、数字和下划线,以字母开头。

• 数据类型:

• 数据传输类型:

 |-可下发可上报:指令数据可以发送给设备,设备数据可以传输给云端。

 |- 只上报:数据只支持从设备传输给云端。

 |- 只下发:数据只支持从云端发送给设备。

TuyaSmartDeviceModel 类的 dps 属性(NSDictionary 类型)定义了当前设备的状态,称作数据点(DP 点)或功能点

dps 字典里的每个 key 对应一个功能点的 dpId,value 对应一个功能点的 dpValue,dpValue 为该功能点的值

产品功能点定义参见涂鸦开发者平台的产品功能,如下图所示:

发送控制指令按照以下格式:

{"":""}

根据后台该产品的功能点定义,如下:

示例代码

`- (void)publishDps {

// self.device = [TuyaSmartDevice deviceWithDeviceId:@"your_device_id"];

// self.device.delegate = self;

NSDictionary *dps;

//设置dpId为1的布尔型功能点示例 作用:开关打开

dps = @{@"1": @(YES)};

//设置dpId为4的字符串型功能点示例 作用:设置RGB颜色为ff5500

dps = @{@"4": @"ff5500"};

//设置dpId为5的枚举型功能点示例 作用:设置档位为2档

dps = @{@"5": @"2"};

//设置dpId为6的数值型功能点示例 作用:设置温度为20°

dps = @{@"6": @(20)};

//设置dpId为15的透传型(byte数组)功能点示例 作用:透传红外数据为1122

dps = @{@"15": @"1122"};

//多个功能合并发送

dps = @{@"1": @(YES), @"4": @(ff5500)};

[self.device publishDps:dps success:^{

    NSLog(@"publishDps success");

    //下发成功,状态上报通过 deviceDpsUpdate方法 回调

} failure:^(NSError *error) {

    NSLog(@"publishDps failure: %@", error);

}];

}`

注意事项

• 控制命令的发送需要特别注意数据类型

比如功能点的数据类型是数值型(value),那控制命令发送的应该是 @{@"2": @(25)} 而不是 @{@"2": @"25"}

• 透传类型传输的 byte 数组是字符串格式(16 进制字符串)、字母需小写并且必须是偶数位

比如正确的格式是: @{@"1": @"011f"} 而不是 @{@"1": @"11f"}

功能点更多概念参见快速入门-功能点相关概念

  1. 设备初始化和设备变化代理监听

需要通过 TuyaSmartHome 初始化一个 home 实例,然后调用接口 getHomeDetailWithSuccess:failure: 获取家庭的详情,同步过家庭的详情后,初始化设备才能成功。错误的设备 id 可能会导致初始化失败,此时设备的实例返回 nil。

`- (void)publishDps {

self.device = [TuyaSmartDevice deviceWithDeviceId:@"your_device_id"];

self.device.delegate = self;

[self.device publishDps:@{@"1" : @{YES}} success:^{

    NSLog(@"publishDps success");

    //下发成功,状态上报通过 deviceDpsUpdate方法 回调

} failure:^(NSError *error) {

    NSLog(@"publishDps failure: %@", error);

}];

}

pragma mark - TuyaSmartDeviceDelegate

/// dp数据更新

  • (void)device:(TuyaSmartDevice *)device dpsUpdate:(NSDictionary *)dps {

    [self.tableView reloadData];

}

/// 设备信息更新

  • (void)deviceInfoUpdate:(TuyaSmartDevice *)device {

}

/// 设备被移除

  • (void)deviceRemoved:(TuyaSmartDevice *)device {

}`

三、总结

我们已经完成了一个 IoT App 对智能硬件设备的激活入网,设备控制等主要环节,通过上述的流程说明,相信你已经可以基于App SDK完成一个智能家居App的开发,感兴趣就去试试吧,有问题可以评论或者私聊!

​​​​​​​四、参考

IoT App SDK 简介

Tuya Home SDK

Demo 链接

如何基于App SDK快速地开发一个IoT App?的更多相关文章

  1. 【如何快速的开发一个完整的iOS直播app】(原理篇)

    原文转自:袁峥Seemygo    感谢分享.自我学习 目录 [如何快速的开发一个完整的iOS直播app](原理篇) [如何快速的开发一个完整的iOS直播app](播放篇) [如何快速的开发一个完整的 ...

  2. 如何快速的开发一个完整的iOS直播app(原理篇)

    目录 [如何快速的开发一个完整的iOS直播app](原理篇) [如何快速的开发一个完整的iOS直播app](播放篇) [如何快速的开发一个完整的iOS直播app](采集篇) 前言 大半年没写博客了,但 ...

  3. 抖音短视频爆火的背后到底是什么——如何快速的开发一个完整的直播app

    前言 今年移动直播行业的兴起,诞生了一大批网红,甚至明星也开始直播了,因此不得不跟上时代的步伐,由于第一次接触的原因,因此花了很多时间了解直播,今天我来教你从零开始搭建一个完整的直播app,希望能帮助 ...

  4. 【如何快速的开发一个完整的iOS直播app】(美颜篇)

    原文转自:袁峥Seemygo    感谢分享.自我学习 前言 在看这篇之前,如果您还不了解直播原理,请查看这篇文章如何快速的开发一个完整的iOS直播app(原理篇) 开发一款直播app,美颜功能是很重 ...

  5. 【如何快速的开发一个完整的iOS直播app】(播放篇)

    原文转自:袁峥Seemygo    感谢分享.自我学习 前言 在看这篇之前,如果您还不了解直播原理,请查看上篇文章如何快速的开发一个完整的iOS直播app(原理篇) 开发一款直播app,集成ijkpl ...

  6. 【如何快速的开发一个完整的 iOS 直播 app】(美颜篇)

    来源:袁峥Seemygo 链接:http://www.jianshu.com/p/4646894245ba 前言 在看这篇之前,如果您还不了解直播原理,请查看这篇文章如何快速的开发一个完整的iOS直播 ...

  7. 【如何快速的开发一个简单的iOS直播app】(代码篇)

    开篇([如何快速的开发一个完整的iOS直播app](原理篇)) 好久没写简书,因为好奇的我跑去学习直播了,今天就分享一下我的感慨. 目前为止直播还是比较热点的技术的,简书,git上有几篇阅读量和含金量 ...

  8. 如何快速的开发一个完整的iOS直播app(美颜篇)

    前言 在看这篇之前,如果您还不了解直播原理,请查看这篇文章如何快速的开发一个完整的iOS直播app(原理篇) 开发一款直播app,美颜功能是很重要的,如果没有美颜功能,可能分分钟钟掉粉千万,本篇主要讲 ...

  9. 【如何快速的开发一个完整的iOS直播app】(采集篇)

    原文转自:袁峥Seemygo    感谢分享.自我学习 前言 在看这篇之前,如果您还不了解直播原理,请查看这篇文章如何快速的开发一个完整的iOS直播app(原理篇) 开发一款直播app,首先需要采集主 ...

随机推荐

  1. unordered_set

    用哈希表实现的 https://blog.csdn.net/dream_you_to_life/article/details/46785741

  2. exe打包成安装文件(界面美观)

    前言 在开发windows桌面应用过程中,软件交付时,一般都是交付安装包. 安装文件的优点 显得更正规,安装界面也可展示软件特点介绍,可自动生成桌面图标等: 安装包体积要比软件小,方便下载. 探索之路 ...

  3. python开发基础(二)运算符以及数据类型之tuple(元组)

    # encoding: utf-8 # module builtins # from (built-in) # by generator 1.147 """ Built- ...

  4. 构建者模式(Builder pattern)

    构建者模式应用场景: 主要用来构建一些复杂对象,这里的复杂对象比如说:在建造大楼时,需要先打牢地基,搭建框架,然后自下向上地一层一层盖起来.通常,在建造这种复杂结构的物体时,很难一气呵成.我们需要首先 ...

  5. CSP-S 2020全国开放赛前冲刺模拟训练题1 T4 二维码

    组合 首先可以考虑一个状态合法的条件,可以发现的是最后得到的矩阵一定是至少有一行或是有一列全$0$或$1$,如果把这一列或这一行删掉那么将剩下的子矩阵拼接起来又是一个子问题,同样的也是至少有一列或一行 ...

  6. ubunutu16.04 更改普通用户权限注销后只有guest身份 没有用户身份

    第一次踩进百度经验的坑..... 之前对百度经验百信不疑,现在怀疑人生.. 网上搜了很多,也变得小心翼翼,最后姑且相信,但还是有点出入,以下是我的实践: (1)重启ubuntu系统,长按shift进入 ...

  7. SpringBoot的外部化配置最全解析!

    目录 SpringBoot中的配置解析[Externalized Configuration] 本篇要点 一.SpringBoot官方文档对于外部化配置的介绍及作用顺序 二.各种外部化配置举例 1.随 ...

  8. 微信小程序开发实战(云开发)--资产管理工具

    添加首页 menu页面 截图展示 menu.js源码 // pages/menu/menu.js Page({ /** * 页面的初始数据 */ data: { }, /** * 生命周期函数--监听 ...

  9. C# 集合类(三)

    C# 集合类自己经常用到: 数组(Array).动态数组(ArrayList).列表(List).哈希表(Hashtable).字典(Dictionary),对于经常使用的这些数据结构,做一个总结,便 ...

  10. 十个Pycharm快捷键——提升效率

    一些比较实用的Pycharm的快捷键,提升编写开发效率. 1.解除语法限制 默认情况下,Pycharm会对代码进行检查,包括但不仅限于代码是否有语法错误,是否符合PEP8规范. 如命名检查,如下图 变 ...