iOS开发之蓝牙业务封装
因为公司做智能家居开发,有很多蓝牙的智能硬件。因此项目中经常需要和蓝牙打交道。为此为了提高开发效率,就把蓝牙的公共业务进行了封装。
本文将对封装的思路做一个简单的阐述。
首先我们需要一个头文件。在这个头文件中定义全局的宏,和结构体。看起来大概是这样的。
//包长相关的宏
#define MAX_PACK_LEN 2048
#define MAX_SEND_LEN 1024
#define MAX_SINGLE_PACKET_LEN 20 /* 新协议 命令字 begin */
/* 请求和应答协议版本命令字*/
#define REQUEST_PROTOCOL_VERSION 0X4001
#define RESPONSE_PROTOCOL_VERSION 0X0001 #define REQUEST_BIND_BLE_DEVICE 0X4002 // 请求绑定设备
#define RESPONSE_BIND_BLE_DEVICE 0X0002 // 应答 #define REQUEST_SYNC_DATA 0X4006 // 请求同步数据
#define RESPONSE_SYNC_DATA 0X0006 // 应答 #define REQUEST_KEY_DATA 0X4008 // 请求数据
#define RESPONSE_KEY_DATA 0X0008 // 应答 #define REQUEST_DELETE_DATA 0X4010 // 请求删除数据
#define RESPONSE_DELETE_DATA 0X0010 // 应答 #define REQUEST_UPGRADE_FIREWARE 0X4012 // 请求升级固件
#define RESPONSE_UPGRADE_FIREWARE 0X0012 // 应答
/* 新协议 命令字 end */ /* 协议类型 */
#define PROTOCOL_TYPE_UPGRADE 0x10 // 升级协议
#define PROTOCOL_TYPE_BUSINESS 0x00 // 业务协议
#define PROTOCOL_TYPE_BIND 0x02 // 绑定协议 //新的蓝牙协议包数据结构
typedef struct
{
uint8_t startflag; //起始标志 0XF2
uint8_t protocol_type; //协议类型 升级协议:0x10 业务协议:0x00 绑定协议:0x02
uint8_t protocol_version; //协议版本号
uint8_t reserved; //保留字节
uint8_t time[]; //协议时间 年以2010为基数往上累加
uint8_t timezone; //时区
UInt16 frame_control; //操作命令字
uint16_t body_length; //数据长度
} Ble_Protocol_Head_New; typedef struct{
Ble_Protocol_Head_New* head;
uint8_t *body; //包体
uint16_t packet_fcs; //FCS校验
}Ble_Protocol_Packet_New;
然后我们需要一个类来处理一些与具体业务无关的逻辑。比如错误处理,蓝牙数据收发,拆包和组包等这些。
我们姑且叫这个类为BleBaseApi吧。在我们的项目中这个只暴露了两个接口。看起来大概是这样的:
@class CLBLEBaseApi;
typedef NS_ENUM (NSUInteger, CLBLEState){
CLBLEStateIdle,
CLBLEStateSending,
CLBLEStateReceiving,
}; typedef void (^BLEScanDiscoverPeripheralsCallback) (NSArray *peripherals); @protocol CLBLEPacketHandle <NSObject>
-(NSInteger)receivedPacketDataLength;
-(NSInteger)totalPacketDataLength; -(NSData*)singlePacketDataDeviceResponse; //设备收到app的数据后,要给app回复一个数据,告诉app我已经收到数据 -(NSData*)singlePacketDataAppResponse; //同理App也需要回复 -(NSData*)fetchCompletePacketData; //完整的数据包 /**
* 根据需要发送的数据包,做拆分,确定每一个包的数据内容
*
* @return 单数数据包的内容
*/
-(NSData*)fetchSinglePacketData; //拆包后的数据 /**
* 解析收到的蓝牙数据
*
* @param data 收到的数据
* @param error error信息
*
* @return 如果解析完成,返回解析之后的值,如果解析失败返回空,error有值
* 如果解析没有完成,返回空,error也是空
*/
-(NSData*)receiveAndParseData:(NSData*)data error:(NSError**)error; -(id)apiManager:(CLBLEBaseApi*)manager reformData:(NSData*)data;
@end @protocol CLBLEDataSource <NSObject> @required -(NSArray*)scanServiceArray; //扫描到的服务 -(NSString*)readSeriveID; //读取数据的服务ID -(NSString*)readCharacteristicID; //读取数据的特征ID -(NSString*)writeSeriveID; -(NSString*)writeCharacteristicID; -(LGPeripheral*)connectedPeripheral; //连接到的外设 -(NSString *)broadName; //广播名 @end typedef void (^BLEProgressiveDownLoadBlock) (NSInteger totalBytesRead, NSInteger totalBytesExpected); typedef void (^BLESuccessBlock) (NSData *data); typedef void (^BLEFailBlock) (NSError* error); typedef void (^BleStateBlock)(CBCentralManagerState state); @interface CLBLEBaseApi : NSObject @property (nonatomic,weak) NSObject<CLBLEDataSource>* child; @property (nonatomic,assign) CLBLEState state; @property (nonatomic,assign) BOOL bleIsReady; -(void)setProgressiveBlock:(BLEProgressiveDownLoadBlock)progressBlock;
-(void)sendBLEDataWithDataPacketProtocol:(id<CLBLEPacketHandle>)packetDelegate
Success:(BLESuccessBlock)successBlock
fail:(BLEFailBlock)failBlock;
其中 sendBLEDataWithDataPacketProtocol 方法处理蓝牙数据的发送接收,它的实现大概是这样子的
-(void)sendBLEDataWithDataPacketProtocol:(id<CLBLEPacketHandle>)packetDelegate
Success:(BLESuccessBlock)successBlock
fail:(BLEFailBlock)failBlock{
if (self.state!= CLBLEStateIdle) {
NSError* error=[NSError errorWithDomain:kCLBLEManagerErrorDomain code:kBLEBusyErrorCode userInfo:@{@"message":kBLEBusyErrorCodeErrorMessage}];
failBlock(error);
return;
}
self.child=(id <CLBLEDataSource>)self; if (!self.child.connectedPeripheral) {
NSError* error=[NSError errorWithDomain:kCLBLEManagerErrorDomain code:kBLEObjErrorCode userInfo:@{@"message":kBLEObjErrorCodeErrorMessage}];
failBlock(error);
return;
}
if (self.child.connectedPeripheral.cbPeripheral.state!=CBPeripheralStateConnected) {
//NSError* error=[NSError errorWithDomain:kCLBLEManagerErrorDomain code:kBLECommunConnectErrorCode userInfo:@{@"message":@"设备没有连接,发个毛啊!"}];
NSError* error=[NSError errorWithDomain:kCLBLEManagerErrorDomain code:kBLECommunConnectErrorCode userInfo:@{@"message":kBLECommunConnectErrorCodeErrorMessage}];
failBlock(error);
return;
}
self.dataPacketHandleDelegate=packetDelegate;
[self sendBLEDataWithData:[self.dataPacketHandleDelegate fetchCompletePacketData]
Success:successBlock
fail:failBlock];
}
在BleBaseApi中声明了一个protocal用来获取数据包的长度以及各种数据包等,所以我们创建一个名为BleProtocal的类来负责这个事情
typedef NSData* (^fetchSinglePacketDataBlock)();
typedef NSData* (^receiveAndParseDataBlock)(NSData*data,NSError**error);
typedef id (^reformDataBlock)(NSData*data); @interface CLBLEBaseProtocol : NSObject<CLBLEPacketHandle> @property(nonatomic,strong)NSData* singleDeviceResponsePacketData;
@property(nonatomic,strong)NSData* singleAppResponsePacketData; @property(nonatomic,strong)NSData* packetData;
@property(nonatomic,copy)fetchSinglePacketDataBlock SinglePacketDataBlock;
@property(nonatomic,copy)receiveAndParseDataBlock receiveAndParseDataBlock;
@property(nonatomic,copy)reformDataBlock reformDataBlock;
@property(nonatomic,assign) NSInteger singlePacketTotalSend;
@property(nonatomic,assign) NSInteger packetDataLength;
@property(nonatomic,assign) NSInteger receiveBufferLength;
@property(nonatomic,strong) NSMutableData* mutableReceiveData;
这是BleProtocal的头文件,诸如 singleDeviceResponsePacketData ,packetData 这些数据都是外界传进来的。这个文件的实现大概是这样的
-(receiveAndParseDataBlock)receiveAndParseDataBlock
{
__weak CLBLEBaseProtocol * weakself = self;
receiveAndParseDataBlock block = ^NSData*(NSData*data,NSError**error){ if (!data) {
*error=[NSError errorWithDomain:@"BLEReceiveDataHelper" code: userInfo:@{@"errorInfo":@"解析数据不能传空值"}];
return nil; }
if (data.length<=) {
*error=[NSError errorWithDomain:@"BLEReceiveDataHelper" code: userInfo:@{@"errorInfo":@"解析数据不能传空值"}];
return nil;
} if (weakself.receiveBufferLength==) {
uint8_t startFlag=;
[data getBytes:&startFlag length:];
if (startFlag!=0xf2) {
[self clear];
*error=[NSError errorWithDomain:@"BLEReceiveDataHelper" code: userInfo:@{@"errorInfo":@"起始不是0xf2"}];
return nil;
}
}
if (!weakself.mutableReceiveData) {
weakself.mutableReceiveData=[[NSMutableData alloc] initWithCapacity:];
}
[weakself.mutableReceiveData appendData:data];
weakself.receiveBufferLength+=data.length; if (weakself.receiveBufferLength>=sizeof(Ble_Protocol_Head_T)) { Ble_Protocol_Head_T bleProtocolHeaderT={}; int offset = (int)((size_t)&(bleProtocolHeaderT.body_length)-(size_t)&bleProtocolHeaderT); typeof (weakself.packetDataLength) length;
[[weakself.mutableReceiveData subdataWithRange:NSMakeRange(offset, )] getBytes:&length length:]; weakself.packetDataLength = length;
weakself.packetDataLength=htons(weakself.packetDataLength);
weakself.packetDataLength=sizeof(Ble_Protocol_Head_T)++weakself.packetDataLength; if (weakself.receiveBufferLength>=weakself.packetDataLength) { NSData* resultPacketData=[weakself.mutableReceiveData subdataWithRange:NSMakeRange(, weakself.packetDataLength)]; uint8_t endFlag=;
[[weakself.mutableReceiveData subdataWithRange:NSMakeRange(weakself.packetDataLength-, )] getBytes:&endFlag length:]; if (endFlag==0xf3) {
if (weakself.receiveBufferLength==weakself.packetDataLength) {
// [weakself clear];
}
*error=nil;
//接收完成
return resultPacketData;
}
else{
*error=[NSError errorWithDomain:@"BLEReceiveDataHelper" code: userInfo:@{@"errorInfo":@"结束标志不是0xf3"}];
return nil;
}
}
}
//接收 ing
*error=nil;
return nil;
};
return [block copy];
} -(fetchSinglePacketDataBlock)SinglePacketDataBlock
{ __weak CLBLEBaseProtocol * weakself = self;
fetchSinglePacketDataBlock block = ^NSData*(){ if ( weakself.singlePacketTotalSend >= weakself.packetData.length)
{
return nil;
}
int cur_send = ((self.packetData.length - _singlePacketTotalSend) > MAX_SINGLE_PACKET_LEN)? MAX_SINGLE_PACKET_LEN: (int)(self.packetData.length - self.singlePacketTotalSend);
NSData* singleData=[self.packetData subdataWithRange:NSMakeRange(self.singlePacketTotalSend, cur_send)];
self.singlePacketTotalSend += cur_send; return singleData; }; return [block copy];
} #pragma mark- BLEDataReformer
-(id)apiManager:(CLBLEBaseApi *)manager reformData:(NSData *)data
{
return self.reformDataBlock?self.reformDataBlock(data):nil;
} #pragma mark- CLBLEPacketHandle
-(NSInteger)receivedPacketDataLength
{
return self.receiveBufferLength;
}
-(NSInteger)totalPacketDataLength
{
return self.packetDataLength;
}
-(NSData*)singlePacketDataDeviceResponse
{
return self.singleDeviceResponsePacketData;
}
-(NSData*)singlePacketDataAppResponse
{
return self.singleAppResponsePacketData;
}
/**
* 一个完整包的数据内容
*
* @return 完整数据包的内容
*/
-(NSData*)fetchCompletePacketData
{
return self.packetData;
} /**
* 根据需要发送的数据包,做拆分,确定每一个包的数据内容
*
* @return 单数数据包的内容
*/
-(NSData*)fetchSinglePacketData
{
return self.SinglePacketDataBlock?self.SinglePacketDataBlock():nil;
} /**
* 解析收到的蓝牙数据
*
* @param data 收到的数据
* @param error error信息
*
* @return 如果解析完成,返回解析之后的值,如果解析失败返回空,error有值
* 如果解析没有完成,返回空,error也是空
*/
-(NSData*)receiveAndParseData:(NSData*)data error:(NSError**)error
{
return self.receiveAndParseDataBlock?self.receiveAndParseDataBlock(data,error):nil;
}
因为继承了<CLBLEPacketHandle> 所以实现了他的代理,通过这样将需要的数据包和数据长度传递给BleBaseApi。
现在假设我们有一个智能床垫是蓝牙设备。我们会创建两个类分别继承自BleBaseApi和BleProtocal
我们先看看BLEMattressProtocol。它的头文件大概如下:
@interface BLEMattressProtocol :CLBLEBaseProtocol uint8_t ble_currentTimeOffset(); void ble_gmtTimeString(uint8_t* timeValue); void ble_gmtTimeString_new(uint8_t* timeValue);
void Init_Ble_Protocol_Head(uint8_t *packetArray,short comdNo,uint16_t dataLength,uint8_t* uniqueID,NSString *deviceVersion);
void Init_Ble_Protocol_Head_New(uint8_t *packetArray,short comdNo,uint16_t dataLength,uint8_t* uniqueID);
//获取统计数据的数据包
+(BLEMattressProtocol*)getRequestStatisticalPacketData:(NSString*)uinqueIDString; //通知设备清除统计数据的数据包
+(BLEMattressProtocol*)getDeleteStatisticalPacketData:(NSString*)uinqueIDString; /**
* 获取实时数据数据包
*
* @param uinqueIDString 唯一ID
*
* @return 返回获取实时数据的数据包
*/
+(BLEMattressProtocol*)getRequestRealTimePacketData:(NSString*)uinqueIDString; /**
* 确认蓝牙升级的数据包
*
* @param uinqueIDString 唯一ID
*
* @return 返回获取蓝牙升级的数据包
*/
+(BLEMattressProtocol *)getRequestConfirmUpgrade:(NSString *)uinqueIDString; @end
再看看实现文件:
//获取统计数据的数据包
+(BLEMattressProtocol*)getRequestStatisticalPacketData:(NSString*)uinqueIDString{
uint8_t packetHead[sizeof(Ble_Protocol_Head_T)]={};
// uint8_t uinqueID[6]={0};
uint8_t* uinqueID=(uint8_t*)[uinqueIDString UTF8String]; Init_Ble_Protocol_Head(packetHead, REQUEST_GET_DATA_COMMAND, ,uinqueID,nil); NSMutableData* packetData=[[NSMutableData alloc] initWithCapacity:];
NSData* packetHeadData=[NSData dataWithBytes:packetHead length:sizeof(Ble_Protocol_Head_T)];
[packetData appendData:packetHeadData]; uint8_t endCommand=BLE_PROTOCOL_END_FLAG;
[packetData appendBytes:&endCommand length:]; BLEMattressProtocol* obj= [[self alloc] init];
uint8_t byte[]={}; // obj.singleAppResponsePacketData = [NSData dataWithBytes:byte length:1];
obj.singleDeviceResponsePacketData = [NSData dataWithBytes:byte length:]; //这里就是给BleProtocal里的那些属性赋值
obj.packetData = packetData;
return obj; // return packetData;
}
我们再看看 MattressBLEManagerApi。下面是他的头文件。
@interface MattressBLEManagerApi : CLBLEBaseApi<CLBLEDataSource> @property (nonatomic,strong) LGPeripheral* currentPeripheral;
@property (nonatomic,strong) NSString* currentBroadName;
@property (nonatomic,assign) BOOL BLEIsPowerOn;
//固件升级时候版本号,如1.9.0
@property (nonatomic,assign) NSString* DeviceUpgradeVersion;
-(void)fetchHistoryDataWithSuccessBlock:(void(^)(NSData* data))success
FailBlock:(void(^)(NSError* error))fail; -(void)fetchRealTimeDataSuccessBlock:(void(^)(NSData* data))success
FailBlock:(void(^)(NSError* error))fail; -(void)fetchRealTimeDataWithInterVal:(NSTimeInterval)interval
WithTimes:(NSTimeInterval)times
SuccessBlock:(void(^)(NSData* data))success
FailBlock:(void(^)(NSError* error))fail; -(void)fetchBLEHandShakeSuccessBlock:(void(^)(NSData* data))success
FailBlock:(void(^)(NSError* error))fail; //还没有调用
-(void)deleteStatisticalDataWithSuccessBlock:(void(^)(NSData* data))success
FailBlock:(void(^)(NSError* error))fail; -(void)fetchProtocolVersionSuccessBlock:(void(^)(NSData* data))success
FailBlock:(void(^)(NSError* error))fail; -(void)stopFetchRealTimeData;
-(void)resumeFetchRealTimeData;
-(void)suspendFetchRealTimeData; @end
MattressBLEManagerApi继承了 CLBLEBaseApi<CLBLEDataSource>。通过实现 CLBLEDataSource里的代理提供了广播名,服务ID,特征ID等数据。
这个类里面我们就开始了与具体业务逻辑相关的操作了。下面看看他的实现文件。
-(void)fetchHistoryDataWithSuccessBlock:(void(^)(NSData* data))success
FailBlock:(void(^)(NSError* error))fail{ NSLog(@"fetchHistoryDataWithSuccessBlock0");
NSLog(@"CLBLEStateIdle == %d",CLBLEStateIdle);
NSLog(@"self.state == %d",self.state); //不相等说明蓝牙繁忙
if ( self.state != CLBLEStateIdle) {
NSError* error=[NSError errorWithDomain:kCLBLEManagerErrorDomain code:kBLEBusyErrorCode userInfo:@{@"message":kBLEBusyErrorCodeErrorMessage}];;
fail(error);
return ;
}
__weak MattressBLEManagerApi* weakSelf=self;
if (self.connectedPeripheral.cbPeripheral.state==CBPeripheralStateConnected) {
sendRealTimeData =[BLEMattressProtocol getRequestStatisticalPacketData:self.uniqueID];
[self sendBLEDataWithDataPacketProtocol:sendRealTimeData
Success:^(NSData *data) {
/*历史数据比较简单,获取历史数据,上传到服务器,然后通知设备,清除数据。
然后告诉外面结果就说成功了,
业务接口自己去服务器拉取数据,整个上传数据流程完毕。
*/
success(data);
NSLog(@"data is %@",data);
} fail:^(NSError *error) {
NSLog(@"error is %@",error);
fail(error);
}];
}
else{
NSLog(@"fetchHistoryDataWithSuccessBlock11");
self.currentPeripheral=nil;
[[CLBLEManager sharedInstance] conntectPeripheralWithBLEDataSource:self
withResultBlock:^(LGPeripheral *peripheral, NSError *error) {
NSLog(@"fetchHistoryDataWithSuccessBlock1");
if (error) {
fail(error);
}
else{
weakSelf.currentPeripheral=peripheral;
sendRealTimeData =[BLEMattressProtocol getRequestStatisticalPacketData:self.uniqueID];
[weakSelf sendBLEDataWithDataPacketProtocol:sendRealTimeData
Success:^(NSData *data) {
/*历史数据比较简单,获取历史数据,上传到服务器,然后通知设备,清除数据。
然后告诉外面结果就说成功了,
业务接口自己去服务器拉取数据,整个上传数据流程完毕。
*/
success(data);
NSLog(@"data is %@",data);
} fail:^(NSError *error) {
NSLog(@"error is %@",error);
fail(error);
}];
}
}];
} }
这一段代码是获取历史数据的接口。
除开上面那些,我们还需要对蓝牙的扫描,连接,探索,读写数据,断开等操作进行封装。所以我们创建了CLBLEManager类。他来管理这些操作。
头文件大概如下:
@protocol CLBLEManagerDelegate <NSObject> -(void)scanAllPeripherals:(NSArray *)allLGPeripherals; @end @interface CLBLEManager : NSObject @property (strong, nonatomic) LGPeripheral *currentLGPeripheral;
@property (strong, nonatomic) CBCentralManager *manager;
+(CLBLEManager *)sharedInstance; //初始化蓝牙并设置读取数据的回调,自动扫描,如果扫描设备名字broadName为空,则扫描所有设备并返回列表,如果broadName不为空则返回连接上的蓝牙设备
-(void)scanbleWithObject:(id<CLBLEDataSource>)child
withScanTimeOut:(NSInteger)timeOut;
//scanPeripheralBlock:(void (^)(NSArray *peripherals,NSError *error))scanPeripheralBlock;
//连接蓝牙
//-(void)conntectPeripheral:(LGPeripheral *)peripheral withResultBlock:(void(^)(NSError *error))connectResultBlock; -(void)conntectPeripheralWithBLEDataSource:(id<CLBLEDataSource>)child
withResultBlock:(void(^)(LGPeripheral* peripheral,NSError *error))connectResultBlock;
//OAD空中升级的时候必须先扫描后连接
-(void)oadConntectPeripheralWithBLEDataSource:(id<CLBLEDataSource>)child
withResultBlock:(void(^)(LGPeripheral* peripheral,NSError *error))connectResultBlock; //发送数据
-(void)sendData:(NSData *)data peripheral:(LGPeripheral *)peripheral;
//设置Notify
-(void)setNotify:(LGPeripheral *)peripheral WithCBUUID:(CBUUID *)sCBUUID cCBUUID:(CBUUID *)cCBUUID withResultBlock:(void(^)(NSError *error))resultBlock withResultBlock:(void(^)(NSData *data,NSError *error))readDataBlock;
//断开蓝牙
-(void)disconntectPeripheral:(LGPeripheral *)peripheral withResultBlock:(void(^)(NSError *error))aCallback;
实现文件大体如下:
-(void)scanbleWithObject:(id<CLBLEDataSource>)child
withScanTimeOut:(NSInteger)timeOut
{ self.broadName=nil;
if ([child respondsToSelector:@selector(broadName)]) {
self.broadName=[child broadName];
}
if ([child connectedPeripheral].name) {
self.broadName=child.connectedPeripheral.name;
}
self.scanServiceArray=child.scanServiceArray;
self.readServiceUUID=child.readSeriveID;
self.readCharacteristic=child.readCharacteristicID;
self.writeServiceUUID=child.writeSeriveID;
self.writeCharacteristic=child.writeCharacteristicID;
if(self.readServiceUUID.length==||self.readCharacteristic.length==||self.writeServiceUUID.length==||self.writeCharacteristic.length==)
{
[self.multicasetDelegate scanAllPeripherals:nil];
return;
}
__weak CLBLEManager *weakself=self;
if([LGCentralManager sharedInstance].centralReady)
{
[weakself scanWithTimeout:timeOut scanFinishBlock:^(NSArray *peripherals)
{
[weakself.multicasetDelegate scanAllPeripherals:peripherals];
}]; }
self.hasConnectedPeripherals=[[NSMutableArray alloc]init];
self.retrievePeripheralsWithIdentifiers=[[NSMutableArray alloc]init];
self.scanPeripheralsCallback=nil;
// Custom initialization [LGCentralManager sharedInstance].updateStateBlock =^(CBCentralManagerState state)
{
if (state == CBCentralManagerStatePoweredOn)
{
if (![LGCentralManager sharedInstance].isScanning)
{
[weakself scanWithTimeout:timeOut scanFinishBlock:^(NSArray *peripherals)
{ [weakself.multicasetDelegate scanAllPeripherals:peripherals];
}];
}
}
}; }
好了,到这里就结束了。以上就是我们在项目中对蓝牙业务进行封装的一个大致思路。
iOS开发之蓝牙业务封装的更多相关文章
- iOS开发之蓝牙通讯
iOS开发之蓝牙通讯 一.引言 蓝牙是设备近距离通信的一种方便手段,在iPhone引入蓝牙4.0后,设备之间的通讯变得更加简单.相关的蓝牙操作由专门的CoreBluetooth.framework进行 ...
- iOS开发之--蓝牙开发实战
转载自:http://www.cnblogs.com/zyjzyj/p/6029968.html ,感谢英杰 前言 最近一直在开发关于蓝牙的功能,本来是不想写这一篇文章,因为网上关于ios蓝牙开发的文 ...
- iOS开发之蓝牙
// // ViewController.m // 13-蓝牙 // // Created by hongqiangli on 2017/7/21. // Copyright © 李洪强. A ...
- ios开发抽屉效果的封装使用
#import "DragerViewController.h" #define screenW [UIScreen mainScreen].bounds.size.width @ ...
- iOS开发之蓝牙通信
一.引言 蓝牙是设备近距离通信的一种方便手段,在iPhone引入蓝牙4.0后,设备之间的通讯变得更加简单.相关的蓝牙操作由专门的 CoreBluetooth.framework进行统一管理.通过蓝牙进 ...
- iOS开发短信验证码封装 方便好用
---恢复内容开始--- 1.RootViewControler// Copyright © 2016年 Chason. All rights reserved.// #import "V ...
- iOS开发之蓝牙使用-建立连接的
1.大佬笔记 CSDN 2.代码 github
- 文顶顶iOS开发博客链接整理及部分项目源代码下载
文顶顶iOS开发博客链接整理及部分项目源代码下载 网上的iOS开发的教程很多,但是像cnblogs博主文顶顶的博客这样内容图文并茂,代码齐全,示例经典,原理也有阐述,覆盖面宽广,自成系统的系列教程 ...
- iOS蓝牙原生封装,助力智能硬件开发
代码地址如下:http://www.demodashi.com/demo/12010.html 人工智能自1956年提出以来,一直默默无闻,近年来人工智能的发展得到重视逐渐发展起步,智能硬件.智能手环 ...
随机推荐
- 2015 Noip提高组 Day2
P2678 跳石头 [题目背景] 一年一度的“跳石头”比赛又要开始了! [题目描述] 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选择好了两块岩石作为比赛起点和终点.在起点和 ...
- Vue实现选项卡效果
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8& ...
- IT兄弟连 Java语法教程 Java语言的其他特性
Java语言中除了非常重要的跨平台特性外,还有如下几个关键特性: ● 语法简单易学 Java语言的语法简单明了,容易掌握,而且是纯面向对象(OOP)的语言,Java语言的简单性主要体现在以下几个方面 ...
- How to generate a CSR in Microsoft IIS 7
How to generate a CSR in Microsoft IIS 7 To help you generate your CSR for Microsoft IIS 7 we've pre ...
- jvm 默认字符集
最近在读取第三方上传的文件时,遇到一个问题,就是采用默认字符集读取,发现个别中文乱码,找到乱码的字,发现是生僻字:碶. 由于在window是环境下做的测试,并没有报错,但是在linux服务器上执行,发 ...
- JQuery序列化表单serialize() 以及 serializeArray()
都是利用form表单传递数据的 1.serialize()方法 描述:序列化表单内容为字符串,用于Ajax请求. 数据类似于这种: FirstName=Bill&LastName=Gates ...
- python序列化模块 json&&pickle&&shelve
#序列化模块 #what #什么叫序列化--将原本的字典.列表等内容转换成一个字符串的过程叫做序列化. #why #序列化的目的 ##1.以某种存储形式使自定义对象持久化 ##2.将对象从一个地方传递 ...
- [Android]简略的Android消息机制源码分析
相关源码 framework/base/core/java/andorid/os/Handler.java framework/base/core/java/andorid/os/Looper.jav ...
- bearBaby loves sleeping(BFS)
时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 131072K,其他语言262144K 64bit IO Format: %lld 题目描述 Sleeping is a favorit ...
- NET full stack framework
NFX UNISTACK 介绍 学习.NET Core和ASP.NET Core,偶然搜索到NFX UNISTACK,现翻译一下Readme,工程/原文:https://github.com/aumc ...