iOS-FMDB+runtime封装,简单实用,省去复杂的sql语句.

news/2024/11/30 14:32:15/

问题提出:

开发中需要用到Sqlite数据库,当然就要写一堆复杂的sql语句。如下:


创建表:
1CREATE TABLE IF NOT EXISTS BSUser (id integer(11) PRIMARY KEY ,arr text DEFAULT NULL,data text DEFAULT NULL,stu_id long DEFAULT NULL,name text DEFAULT NULL,image text DEFAULT NULL);
(2)CREATE TABLE IF NOT EXISTS BSTeacher (id integer(11) PRIMARY KEY ,name text DEFAULT NULL,depart text DEFAULT NULL);
(3)CREATE TABLE IF NOT EXISTS BSStudent (id integer(11) PRIMARY KEY ,tea_id long DEFAULT NULL,name text DEFAULT NULL);


模糊查询:
select * from YHWorkGroup where id = 2016 and msgContent like '%%' 
更新表:
update YHUserInfo set isRegister = 1,isSelfModel = 1,isOfficial = 1,isFollowed = 1,sex = 1,fromType = 1,dynamicCount = 1,nNewFansCount = 2,fansCount = 0,followCount = 28,likeCount = 4,identity = 1,friShipStatus = 1,addFriStatus = 2,photoCount = 0,updateStatus = 0,id = '201611110',taxAccount = 'accessToken=0',mobilephone = '13570871315',userName = 'userName0',avatarUrl = 'http://www.google.com',oriAvaterUrl = 'http://www.baidu.com',intro = '个人简介好短',industry = '随机行业',job = '高级职位',province = '广东省',workCity = '随机工作城市',workLocation = '广州移动',loginTime = '1479110498.98624',company = '广州移动通信',email = 'qq0.eamil.com',visitTime = '1479110598.98624',jobTags = '(
    "\U968f\U673a\U6807\U7b7e",
    "\U968f\U673a\U6807\U7b7e"
)',workExperiences = '[{"moreDescription":"玛丽黛佳法拉盛借方","endTime":"20164","company":"公司18","workExpId":"10","position":"职位29","beginTime":"20160"},{"moreDescription":"玛丽黛佳法拉盛借方","endTime":"20164","company":"公司33","workExpId":"14","position":"职位22","beginTime":"20160"},{"moreDescription":"玛丽黛佳法拉盛借方","endTime":"20164","company":"公司25","workExpId":"27","position":"职位21","beginTime":"20160"}]',eductaionExperiences = '[{"school":"学校36","major":"会计","beginTime":"20160","educationBackground":"大专","endTime":"20164","moreDescription":"的理解爱了就","eduExpId":"260"},{"school":"学校26","major":"随机专业","beginTime":"20160","educationBackground":"大专","endTime":"20164","moreDescription":"的理解爱了就","eduExpId":"380"},{"school":"学校38","major":"会计","beginTime":"20160","educationBackground":"本科","endTime":"20164","moreDescription":"的理解爱了就","eduExpId":"82"}]' where id = 201611110 ;


      在iOS开发中,为了得到以上SQL语句,如果是手动地添加模型属性,代码就冗余了,也就是增加代码量,可读性差,而且如果改变了模型的某个属性的名称,SQL语句相应的位置要发生改变。增,删,改,查,都要改变。如果是改变了一批属性名,这工作量简直是灾难性啊。还有,如果一个模型的属性嵌套模型,怎么把模型保存到数据库呢,如果属性是UIImage,或者是数组呢?怎么解决。

     那Apple有没有API可以动态的获取属性名,代替这复杂的语句呢?有,那就是runtime。相信大家对runtime已经很熟悉了。如果刚入门runtime,可以阅读标哥的技术博客的runtime专题,在那里帮你快速掌握runtime基本知识。好,现在就利用runtimeFMDB进行封装

      因为最近项目空闲,整理了一个基于FMDB封装了一个简单实用的APP数据管理工具YHFMDB.

       github demo: https://github.com/samuelandkevin/PackaingFMDB



在FMDatabase+YHDatabase.h中,

/** 保存一个模型 */
- (void )yh_saveDataWithModel:(id )model userInfo:(NSDictionary *)userInfo option:(YHSaveOption )option;
/** 删除一个模型 */
- (void)yh_deleteDataWithModel:(id )model userInfo:(NSDictionary *)userInfo option:(YHDeleteOption )option;
/** 查询某个模型数据 */
- (id )yh_excuteDataWithModel:(id )model  userInfo:(NSDictionary *)userInfo fuzzyUserInfo:(NSDictionary *)fuzzyUserInfo option:(YHExcuteOption )option;
/** 查询某种所有的模型数据 */
- (void)yh_excuteDatasWithModel:(id )model userInfo:(NSDictionary *)userInfo fuzzyUserInfo:(NSDictionary *)fuzzyUserInfo option:(YHAllModelsOption )option;#pragma mark -- PrimaryKey
/** 保存一个模型 */
- (void )yh_saveDataWithModel:(id )model  primaryKey:(NSString *)primaryKey userInfo:(NSDictionary *)userInfo option:(YHSaveOption )option;
/** 删除一个模型 */
- (void)yh_deleteDataWithModel:(id )model  primaryKey:(NSString *)primaryKey userInfo:(NSDictionary *)userInfo option:(YHDeleteOption )option;
/** 查询某个模型数据 */
- (id )yh_excuteDataWithModel:(id )model  primaryKey:(NSString *)primaryKey userInfo:(NSDictionary *)userInfo fuzzyUserInfo:(NSDictionary *)fuzzyUserInfo option:(YHExcuteOption )option;
/** 查询某种所有的模型数据 */
- (void)yh_excuteDatasWithModel:(id )model  primaryKey:(NSString *)primaryKey userInfo:(NSDictionary *)userInfo fuzzyUserInfo:(NSDictionary *)fuzzyUserInfo option:(YHAllModelsOption )option;

//在NSObject+YHDBRuntime.h中
//
//  NSObject+Runtime.h
//  
//
//  Created by YHIOS002 on 16/11/9.
//  Copyright © 2016年 YHSoft. All rights reserved.
//#import <Foundation/Foundation.h>#import "MJExtension.h"@interface YHDBRuntimeIvar : NSObject/** 模型属性的名称 */
@property (nonatomic, copy) NSString *name;/** 模型属性的类型值 */
@property(nonatomic,assign) NSInteger type;/** 模型属性类型名称 */
@property(nonatomic,copy)   NSString  *typeName;@end/** ivar_name:属性名,如果符合主键声明条件会自动替换成主键:YHDB_PrimaryKey */
#define YHDB_EqualsPrimaryKey(ivar_name)         if ([[[model class] yh_primaryKey] isEqualToString:ivar_name]) ivar_name = YHDB_PrimaryKey;
/** 模型属性,建表时字段所加的后缀 */
extern NSString *const YHDB_AppendingID;
/** 所有表的主键默认设置 */
extern NSString *const YHDB_PrimaryKey;typedef enum{/** 字符串类型 */RuntimeObjectIvarTypeObject = 64,/** 浮点型 */RuntimeObjectIvarTypeDoubleAndFloat = 100,/** 数组 */RuntimeObjectIvarTypeArray = 65,/** 流:data */RuntimeObjectIvarTypeData = 66,/** 图片:image */RuntimeObjectIvarTypeImage = 67,/** 其他(在数据库中使用long进行取值) */RuntimeObjectIvarTypeOther = -1
}RuntimeObjectIvarType;typedef void(^RuntimeObjectIvarsOption)(YHDBRuntimeIvar *ivar);@interface NSObject (YHDBRuntime)/*** 实现该方法,则必须实现:yh_replacedKeyFromPropertyName* 设置主键:能够唯一标示该模型的属性**/
+ (NSString *)yh_primaryKey;/***  将属性为数组**/
+ (NSDictionary *)yh_propertyIsInstanceOfArray;/***  将属性为NSDATA**/
+ (NSDictionary *)yh_propertyIsInstanceOfData;/***  将属性为UIImage**/
+ (NSDictionary *)yh_propertyIsInstanceOfImage;/***  只有这个数组中的属性名才允许*/
+ (NSArray *)yh_allowedPropertyNames;/***  这个数组中的属性名将会被忽略:不进行*/
+ (NSArray *)yh_ignoredPropertyNames;/***  将属性名换为其他key**/
+ (NSDictionary *)yh_replacedKeyFromPropertyName;/***  将属性是一个模型对象:字典再根据属性名获取value作为字段名**/
+ (NSDictionary*)yh_replacedKeyFromDictionaryWhenPropertyIsObject;
/***  key : 模型对象的名字*  通过key获取类名*/
+ (NSDictionary *)yh_getClassForKeyIsObject;/** 获取对象的属性名和属性类型 */
+ (void)yh_objectIvar_nameAndIvar_typeWithOption:(RuntimeObjectIvarsOption )option;+ (void)yh_replaceKeyWithIvarModel:(YHDBRuntimeIvar *)model option:(RuntimeObjectIvarsOption )option ;/** 创表*/
+ (NSString *)yh_sqlForCreateTableWithPrimaryKey:(NSString *)primaryKey ;/**创表:除模型的属性之外, 有多余的字段 */
+ (NSString *)yh_sqlForCreateTableWithPrimaryKey:(NSString *)primaryKey  extraKeyValues:(NSArray <YHDBRuntimeIvar *> *)extraKeyValues;//条件查询语句
+ (NSString *)yh_sqlForExcuteWithPrimaryKey:(NSString *)primaryKey userInfo:(NSDictionary *)userInfo fuzzyUserInfo:(NSDictionary *)fuzzyUserInfo value:(id )value;@end

//在ViewController中调用如下:

//
//  ViewController.m
//  FMDBDemo
//
//  Created by YHIOS002 on 16/11/2.
//  Copyright © 2016年 YHSoft. All rights reserved.
//#import "ViewController.h"
#import "SqliteManager.h"
#import "TestData.h"@interface ViewController ()//控件
@property (weak, nonatomic) IBOutlet UILabel *lbResult;
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityView;
@property (strong,nonatomic) UIButton *btnSel;//数据
@property (nonatomic,strong) NSMutableArray *maDynList;
@property (nonatomic,strong) NSMutableArray *maMyFrisList;
@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view, typically from a nib.self.maDynList = [[TestData generateDynData] mutableCopy];self.maMyFrisList = [[TestData generateMyFris] mutableCopy];self.activityView.hidden = YES;
}- (void)setBtnSel:(UIButton *)btnSel{for (UIView *subView in self.view.subviews) {if ([subView isKindOfClass:[UIButton class]] && subView.tag>100 && subView.tag<210) {UIButton *btn = (UIButton *)subView;btn.backgroundColor = [UIColor colorWithRed:103/255.0 green:152/255.0 blue:255/255.0 alpha:1];}}btnSel.backgroundColor = [UIColor yellowColor];
}#pragma mark - Action
//更新动态列表
- (IBAction)updateDynList:(UIButton *)sender {self.btnSel = sender;[[SqliteManager sharedInstance] updateDynList:self.maDynList complete:^(BOOL success, id obj) {if (success) {NSLog(@"更新动态列表成功");[self _showResultWithTitle:@"更新动态列表" obj:@"更新动态列表成功"];}else{NSLog(@"更新动态列表失败");[self _showResultWithTitle:@"更新动态列表" obj:@"更新动态列表失败"];}}];
}//查询动态表
- (IBAction)queryDynTable:(UIButton *)sender {self.btnSel = sender;//无搜索条件,整个动态表查询[[SqliteManager sharedInstance] queryDynTableWithUserInfo:nil fuzzyUserInfo:nil complete:^(BOOL success, id obj) {if (success) {NSLog(@"查询动态表成功,所有动态为\n%@",obj);[self _showResultWithTitle:@"查询动态表成功" obj:obj];}else{NSLog(@"查询动态表失败");[self _showResultWithTitle:@"查询动态表失败" obj:obj];}}];
}//条件查询
- (IBAction)queryByCondition:(UIButton *)sender {self.btnSel = sender;//设置搜索的条件NSDictionary *userInfo = @{@"publishTime":@"2016-10-5"};[[SqliteManager sharedInstance] queryDynTableWithUserInfo:userInfo fuzzyUserInfo:nil complete:^(BOOL success, id obj) {if (success) {NSLog(@"按条件查询动态表成功,搜索结果为\n%@",obj);[self _showResultWithTitle:@"按条件查询动态表成功" obj:obj];}else{NSLog(@"按条件查询动态表失败");[self _showResultWithTitle:@"按条件查询动态表失败" obj:obj];}}];}- (IBAction)fuzzyQueryDyn:(UIButton *)sender {self.btnSel = sender;//设置模糊搜索NSDictionary *fuzzyUserInfo = @{@"msgContent":@"我"};//查找动态内容包含我的搜索内容[[SqliteManager sharedInstance] queryDynTableWithUserInfo:nil fuzzyUserInfo:fuzzyUserInfo complete:^(BOOL success, id obj) {if (success) {NSLog(@"模糊查询动态表成功,搜索结果为\n%@",obj);[self _showResultWithTitle:@"模糊查询动态表成功" obj:obj];}else{NSLog(@"模糊查询动态表失败");[self _showResultWithTitle:@"模糊查询动态表失败" obj:obj];}}];}//查询多条动态
- (IBAction)queryDynList:(id)sender {self.btnSel = sender;//eg1:查询动态idNSArray *dynIdArray = @[@"2016",@"2017",@"20165044",@"20167044"];NSMutableArray *queryDynArray = [NSMutableArray arrayWithCapacity:dynIdArray.count];for(int i= 0;i<dynIdArray.count;i++ ){YHWorkGroup *model = [YHWorkGroup new];model.dynamicId = dynIdArray[i];[queryDynArray addObject:model];}[[SqliteManager sharedInstance] queryDynList:queryDynArray complete:^(BOOL success, id obj) {NSLog(@"查询动态结果:%@",obj);[self _showResultWithTitle:@"查询动态结果" obj:obj];}];//eg2:查询所有动态
//    [[SqliteManager sharedInstance] queryDynList:self.maDynList complete:^(BOOL success, id obj) {
//        NSLog(@"查询动态结果:%@",obj);
//    }];}//更新某条动态
- (IBAction)updateOneDyn:(id)sender {self.btnSel = sender;//先查找动态IdYHWorkGroup *model = [YHWorkGroup new];model.dynamicId = @"2016";//设置搜索的条件NSDictionary *userInfo = @{@"publishTime":@"2016-10-1"};[[SqliteManager sharedInstance] queryaDyn:model userInfo:userInfo complete:^(BOOL success, id obj) {if (success) {if(obj){YHWorkGroup *model = obj;//修改动态内容model.msgContent = @"我变成消息了";dispatch_async(dispatch_get_global_queue(0, 0), ^{[[SqliteManager sharedInstance] updateaDyn:model complete:^(BOOL success, id obj) {if (success) {NSLog(@"更新某条动态成功");[self _showResultWithTitle:@"更新某条动态成功" obj:obj];}else{NSLog(@"更新某条动态失败");[self _showResultWithTitle:@"更新某条动态失败" obj:obj];}}];});}else{NSLog(@"搜索结果为0");[self _showResultWithTitle:@"搜索结果为0" obj:obj];}}else{NSLog(@"搜索某条动态失败");[self _showResultWithTitle:@"搜索某条动态失败" obj:obj];}}];}//删除动态表
- (IBAction)deleteDynTable:(id)sender {self.btnSel = sender;[[SqliteManager sharedInstance] deleteDynTableComplete:^(BOOL success, id obj) {if (success) {NSLog(@"delete dynTable success");[self _showResultWithTitle:@"delete dynTable success" obj:obj];}else{NSLog(@"delete dynTable fail");[self _showResultWithTitle:@"delete dynTable fail" obj:obj];}}];
}//更新多个好友信息
- (IBAction)updateMyFris:(id)sender {self.btnSel = sender;[[SqliteManager sharedInstance] updateMyFrisList:self.maMyFrisList complete:^(BOOL success, id obj) {if (success) {NSLog(@"更新多个好友信息成功");[self _showResultWithTitle:@"更新多个好友信息成功" obj:obj];}else{[self _showResultWithTitle:@"更新多个好友信息失败" obj:obj];}}];
}//更新某个好友信息
- (IBAction)updateOneFri:(id)sender {self.btnSel = sender;//先查找好友IdYHUserInfo *model = [YHUserInfo new];model.uid = @"201611111";[[SqliteManager sharedInstance] queryaFri:model userInfo:nil complete:^(BOOL success, id obj) {if (success && obj) {YHUserInfo *model = obj;//修改好友简介model.intro = @"我的简介改变了。。。。。";dispatch_async(dispatch_get_global_queue(0, 0), ^{[[SqliteManager sharedInstance] updateaFri:model userInfo:nil complete:^(BOOL success, id obj) {if (success) {NSLog(@"更新某个好友信息成功");[self _showResultWithTitle:@"更新某个好友信息成功" obj:obj];}else{NSLog(@"更新某个好友信息失败");[self _showResultWithTitle:@"更新某个好友信息失败" obj:obj];}}];});}}];}//删除我的好友表
- (IBAction)deleteMyFrisTable:(id)sender {self.btnSel = sender;[[SqliteManager sharedInstance] deleteMyFrisTableComplete:^(BOOL success, id obj) {if (success) {NSLog(@"delete MyFris table success");[self _showResultWithTitle:@"delete MyFris table success" obj:obj];}else{NSLog(@"delete MyFris table fail");[self _showResultWithTitle:@"delete MyFris table fail" obj:obj];}}];
}//查询多个好友
- (IBAction)queryMyFrisArray:(id)sender {self.btnSel = sender;//eg1:查询好友idNSArray *frisIdArray = @[@"2016",@"20161",@"2016111",@"201611111"];NSMutableArray *queryFrisArray = [NSMutableArray arrayWithCapacity:frisIdArray.count];for(int i= 0;i<frisIdArray.count;i++ ){YHUserInfo *model = [YHUserInfo new];model.uid = frisIdArray[i];[queryFrisArray addObject:model];}[[SqliteManager sharedInstance] queryFrisList:queryFrisArray userInfo:nil complete:^(BOOL success, id obj) {NSLog(@"查询多个好友结果:%@",obj);[self _showResultWithTitle:@"查询多个好友结果" obj:obj];}];//eg2:查询所有我的好友
//    [[SqliteManager sharedInstance] queryDynList:self.maDynList complete:^(BOOL success, id obj) {
//        NSLog(@"查询动态结果:%@",obj);
//    }];
}//查询我的好友表
- (IBAction)queryMyFrisTable:(id)sender {self.btnSel = sender;//全文搜索[[SqliteManager sharedInstance] queryMyFrisTableWithUserInfo:nil fuzzyUserInfo:nil complete:^(BOOL success, id obj) {if (success) {NSLog(@"查询好友表成功,所有动态为\n%@",obj);[self _showResultWithTitle:@"查询好友表成功" obj:obj];}else{NSLog(@"查询好友表失败");[self _showResultWithTitle:@"查询好友表失败" obj:obj];}}];}//条件查询好友
- (IBAction)queryMyFrisByCondition:(id)sender {self.btnSel = sender;//设置搜索的条件NSDictionary *userInfo = @{@"userName":@"userName1"};[[SqliteManager sharedInstance] queryMyFrisTableWithUserInfo:userInfo fuzzyUserInfo:nil complete:^(BOOL success, id obj) {if (success) {NSLog(@"条件查询好友表成功,搜索结果为\n%@",obj);[self _showResultWithTitle:@"条件查询好友表成功" obj:obj];}else{NSLog(@"条件查询好友表失败");[self _showResultWithTitle:@"条件查询好友表失败" obj:obj];}}];}//模糊查询好友
- (IBAction)fuzzyQueryMyFris:(id)sender {self.btnSel = sender;//设置模糊搜索NSDictionary *fuzzyUserInfo = @{@"sex":@"1"};//查找动态内容包含我的搜索内容[[SqliteManager sharedInstance] queryMyFrisTableWithUserInfo:nil fuzzyUserInfo:fuzzyUserInfo complete:^(BOOL success, id obj) {if (success) {NSLog(@"模糊查询好友,搜索结果为\n%@",obj);[self _showResultWithTitle:@"模糊查询好友表成功" obj:obj];}else{NSLog(@"模糊查询好友表失败");[self _showResultWithTitle:@"模糊查询好友表失败" obj:obj];}}];}#pragma mark - Private
- (void)_showResultWithTitle:(NSString *)title obj:(id)obj{WeakSelfdispatch_async(dispatch_get_main_queue(), ^{weakSelf.activityView.hidden = NO;[weakSelf.activityView startAnimating];NSString *context = [NSString stringWithFormat:@"操作类型:\n\t%@",title];context = [context stringByAppendingString:@"\n\n结果:\n\t"];if ([obj isKindOfClass:[NSString class]]) {NSString *objResult = obj;context =  [context stringByAppendingString:objResult];}else if([obj isKindOfClass:[NSArray class]]){NSArray *objArr = obj;if (!objArr.count) {context = [context stringByAppendingString:[NSString stringWithFormat:@"没有搜索到相应的j结果"]];}else{context = [context stringByAppendingString:[NSString stringWithFormat:@"共(%lu)个",(unsigned long)objArr.count]];}for (id oneObj in objArr) {if ([oneObj isKindOfClass:[YHWorkGroup class]]) {YHWorkGroup *model = oneObj;context = [context stringByAppendingString:[NSString stringWithFormat:@"\n动态ID是:%@",model.dynamicId]];}else if([oneObj isKindOfClass:[YHUserInfo class]]){YHUserInfo *model = oneObj;context = [context stringByAppendingString:[NSString stringWithFormat:@"\n用户ID是:%@",model.uid]];}}}weakSelf.lbResult.text = context;[weakSelf.activityView stopAnimating];weakSelf.activityView.hidden = YES;});}- (void)didReceiveMemoryWarning {[super didReceiveMemoryWarning];// Dispose of any resources that can be recreated.
}@end


//效果图:




http://www.ppmy.cn/news/708304.html

相关文章

python学习笔记(五)—— 字典(1)

上集回顾&#xff1a; python学习笔记&#xff08;四&#xff09;——if语句 python学习笔记&#xff08;三&#xff09;——列表&#xff08;2&#xff09; python学习笔记&#xff08;二&#xff09;——列表&#xff08;1&#xff09; python学习笔记&#xff08;一&#xf…

Hbase详解

HBase架构图理解 18.png HMaster链接Zookeeper的目得&#xff1a;HMaster需要知道哪些HRegionServere是活的及HRegionServer所在的位置&#xff0c;然后管理HRegionServer。HBase内部是通过DFS client把数据写到HDFS上的每一个HRegionServer有多个HRegion&#xff0c;每一个HRe…

[Hbase]HBase架构详解和数据的读写流程

HBase架构图理解 18.png HMaster链接Zookeeper的目得&#xff1a;HMaster需要知道哪些HRegionServere是活的及HRegionServer所在的位置&#xff0c;然后管理HRegionServer。HBase内部是通过DFS client把数据写到HDFS上的每一个HRegionServer有多个HRegion&#xff0c;每一个HR…

2019年安大计算机专业分数线,2019年安徽

校考也就是各大美院或独立院校组织的单招专业考试&#xff0c;校考又叫单招。校考成绩其它学校是不认可的&#xff0c;所以要针对一些学校去进行专业的训练。一般校考时间都在美术联考过后进行&#xff0c;直到三月份中旬中央美院校考收尾。校考是艺术生在省外学校单独去进行报…

HBase架构原理详解和数据的读写流程

HBase架构详解和数据的读写流程 HBase架构图理解 HMaster链接Zookeeper&#xff1a;HMaster需要知道哪些HRegionServere是活的及HRegionServer所在的位置&#xff0c;然后管理HRegionServer。HBase内部是通过DFSclient把数据写到HDFS上的每一个HRegionServer有多个HRegion&…

HBase Shell

当HBase集群配置好启动后&#xff0c;就可以使用HBase的Shell对HBase进行各种操作&#xff0c;如建表、添加记录、添加列族和删除表等。需使用HBase的bin目录下的HBase命令才能进入&#xff0c;具体操作如下&#xff1a; 进入HBase [gzncmaster ~]$ cd /home/gznc/hbase-0.98.…

hbase 二进制数据写入_HBase架构详解和数据的读写流程

HBase架构图理解 18.png HMaster链接Zookeeper的目得&#xff1a;HMaster需要知道哪些HRegionServere是活的及HRegionServer所在的位置&#xff0c;然后管理HRegionServer。 HBase内部是通过DFS client把数据写到HDFS上的 每一个HRegionServer有多个HRegion&#xff0c;每一个H…

【雕爷学编程】Arduino动手做(148)---MD-PS002压力传感器模块

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…