一、蓝牙

随着蓝牙低功耗技术BLE(Bluetooth Low Energy)的发展,蓝牙技术正在一步步成熟,现在的大部分移动设备都配备有蓝牙4.0,相比之前的蓝牙技术耗电量大大减少。

在iOS中进行蓝牙传输经常使用的框架有例如以下几种:
  1. GameKit.framework

    iOS7之前的蓝牙框架,仅仅可用于同应用之间的蓝牙传输。

  2. MultipeerConnectivity.framework

    iOS7開始引入的蓝牙框架。用于代替GameKit。也有缺陷。仅支持iOS设备之间蓝牙传输。

  3. CoreBluetooth.framework

    功能强大的蓝牙框架。但要求设备必须支持蓝牙4.0。能够支持全部设备蓝牙传输。仅仅要该设备支持蓝牙4.0。

应用的比較多的是CoreBluetooth框架,这里就选择CoreBluetooth框架来讲。

二、CoreBluetooth

当前BLE应用相当广泛。不再仅仅是两个设备之间的传输数据,它还有非常多其它应用市场,比如室内定位、无线支付、智能家居等等,这也使得CoreBluetooth成为当前最热门的蓝牙技术。

我的理解中。CoreBluetooth蓝牙通信过程和网络通信过程比較相似。

CoreBluetooth中。蓝牙传输都分为两个部分:
  1. 外围设备CBPeripheral

    负责公布并广播服务,告诉周围的中央设备它的可用服务和特征。相似于网络通信中的服务端。
  2. 中央设备CBCentral

    负责和外围设备建立连接,一旦连接成功就能够使用外围设备的服务和特征,相似于网络通信中的client

外围设备和中央设备交互的桥梁是服务特征,两个都有一个唯一标识CBUUID来确定一个服务或者特征:

* 服务CBService

中央设备仅仅有通过服务才干与外围设备进行传输数据,相似于client通过网址URL才干与server连接一样

* 特征CBCharacteristic

每一个服务能够拥有多个特征。中央设备必须订阅外围设备服务的特征值。才干获取外围设备的数据,相似于GET请求能够请求获取server数据,POST请求能够向server传输数据一样。

三、设备作为外围设备

设备作为外围设备的创建步骤:
  1. 创建外围设备管理器CBPeripheralManager,并设置代理
  2. 创建一个特征CBCharacteristic。绑定一个CBUUID,设置特征属性
  3. 创建一个服务CBService,绑定一个CBUUID,设置服务的特征
  4. 调用外围设备管理器的对象方法。加入服务到外围设备上
-(void)addService:(CBService *)service;
  1. 外围设备管理器開始广播服务
-(void)startAdvertising:(NSDictionary *)dict;
  1. 在外围设备管理器的代理方法。处理与中央设备的交互

外围设备管理器启动服务的相关代理方法:
/* 外围设备管理器状态发生改变后调用,比方外围设备打开蓝牙的时候 */
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral;
/* 外围设备管理器加入了服务后调用,一般在这里进行广播服务 */
- (void)peripheralManager:(CBPeripheralManager *)peripheral
didAddService:(CBService *)service /* 加入的服务 */
error:(NSError *)error;/* 加入服务错误信息 */
/* 启动广播服务后调用 */
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral
error:(NSError *)error;/* 启动服务错误信息 */
/* 外围设备恢复状态时调用 */
- (void)peripheralManager:(CBPeripheralManager *)peripheral
willRestoreState:(NSDictionary *)dict;
外围设备管理器和中央设备进行交互的代理方法:
/* 中央设备订阅外围设备的特征时调用 */
- (void)peripheralManager:(CBPeripheralManager *)peripheral /* 外围设备管理器 */
central:(CBCentral *)central /* 中央设备 */
didSubscribeToCharacteristic:(CBCharacteristic *)characteristic;/* 订阅的特征 */
/* 中央设备取消订阅外围设备的特征时调用 */
- (void)peripheralManager:(CBPeripheralManager *)peripheral /* 外围设备管理器 */
central:(CBCentral *)central /* 中央设备 */
didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic;/* 特征 */
/* 外围设备收到中央设备的写请求时调用 */
- (void)peripheralManager:(CBPeripheralManager *)peripheral
didReceiveWriteRequests:(CBATTRequest *)request;/* 写请求 */
外围设备管理器CBPeripheralManager的经常使用对象方法:
/* 加入服务 */
- (void)addService:(CBService *)service;
/* 开启广播服务,dict设置设备信息 */
- (void)startAdvertising:(NSDictionary *)dict;
/* 更新特征值,centrals为空,表示对全部连接的中央设备通知 */
- (void)updateValue:(NSData *)value /* 特征的特征值 */
forCharacteristic:(CBCharacteristic *)characteristic /* 特征 */
onSubscribedCentrals:(NSArray *)centrals;/* 须要通知更新特征值的中央设备 */
以下是设备作为外围设备的实例:
#import "PeripheralViewController.h"
#import <CoreBluetooth/CoreBluetooth.h> #define kPeripheralName @"Liuting's Device" //外围设备名称。自己定义
#define kServiceUUID @"FFA0-FFB0" //服务的UUID,自己定义
#define kCharacteristicUUID @"FFCC-FFDD" //特征的UUID,自己定义 @interface PeripheralViewController ()<CBPeripheralManagerDelegate>
@property (strong, nonatomic) CBPeripheralManager *peripheralManager;/* 外围设备管理器 */
@property (strong, nonatomic) NSMutableArray *centralM;/* 订阅的中央设备 */
@property (strong, nonatomic) CBMutableCharacteristic *characteristicM;/* 特征 */
@end
@implementation PeripheralViewController
- (void)viewDidLoad{
[super viewDidLoad];
self.centralM = [NSMutableArray array];
//创建外围设备管理器
self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self
queue:nil];
}
#pragma mark - UI事件
/* 点击更新特征值 */
- (IBAction)changeCharacteristicValue:(id)sender {
//特征值,这里是更新特征值为当前时间
NSString *valueStr = [NSString stringWithFormat:@"%@",[NSDate date]];
NSData *value = [valueStr dataUsingEncoding:NSUTF8StringEncoding];
//更新特征值
[self.peripheralManager updateValue:value
forCharacteristic:self.characteristicM
onSubscribedCentrals:nil];
}
#pragma mark - 私有方法
/* 创建特征、服务并加入服务到外围设备 */
- (void)addMyService{
/*1.创建特征*/
//创建特征的UUID对象
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID];
/* 创建特征
* 參数
* uuid:特征标识
* properties:特征的属性,比如:可通知、可写、可读等
* value:特征值
* permissions:特征的权限
*/
CBMutableCharacteristic *characteristicM =
[[CBMutableCharacteristic alloc] initWithType:characteristicUUID
properties:CBCharacteristicPropertyNotify
value:nil
permissions:CBAttributePermissionsReadable];
self.characteristicM = characteristicM;
//创建服务UUID对象
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID];
//创建服务
CBMutableService *serviceM = [[CBMutableService alloc] initWithType:serviceUUID
primary:YES];
//设置服务的特征
[serviceM setCharacteristics:@[characteristicM]];
//将服务加入到外围设备
[self.peripheralManager addService:serviceM];
} #pragma mark - CBPeripheralManager代理方法
/* 外围设备状态发生变化后调用 */
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral{
//推断外围设备管理器状态
switch (peripheral.state) {
case CBPeripheralManagerStatePoweredOn:
{
NSLog(@"BLE已打开.");
//加入服务
[self addMyService];
break;
}
default:
{
NSLog(@"此设备不支持BLE或未打开蓝牙功能,无法作为外围设备.");
break;
}
}
}
/* 外围设备恢复状态时调用 */
- (void)peripheralManager:(CBPeripheralManager *)peripheral
willRestoreState:(NSDictionary *)dict
{
NSLog(@"状态恢复");
}
/* 外围设备管理器加入服务后调用 */
- (void)peripheralManager:(CBPeripheralManager *)peripheral
didAddService:(CBService *)service
error:(NSError *)error
{
//设置设备信息dict。CBAdvertisementDataLocalNameKey是设置设备名
NSDictionary *dict = @{CBAdvertisementDataLocalNameKey:kPeripheralName};
//開始广播
[self.peripheralManager startAdvertising:dict];
NSLog(@"向外围设备加入了服务并開始广播...");
}
/* 外围设备管理器启动广播后调用 */
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral
error:(NSError *)error
{
if (error) {
NSLog(@"启动广播过程中错误发生。错误信息:%@",error.localizedDescription);
return;
}
NSLog(@"启动广播...");
}
/* 中央设备订阅特征时调用 */
- (void)peripheralManager:(CBPeripheralManager *)peripheral
central:(CBCentral *)central
didSubscribeToCharacteristic:(CBCharacteristic *)characteristic
{
NSLog(@"中心设备:%@ 已订阅特征:%@.",central,characteristic);
//把订阅的中央设备存储下来
if (![self.centralM containsObject:central]) {
[self.centralM addObject:central];
}
}
/* 中央设备取消订阅特征时调用 */
- (void)peripheralManager:(CBPeripheralManager *)peripheral
central:(CBCentral *)central
didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic
{
NSLog(@"中心设备:%@ 取消订阅特征:%@",central,characteristic);
} /* 外围设备管理器收到中央设备写请求时调用 */
- (void)peripheralManager:(CBPeripheralManager *)peripheral
didReceiveWriteRequests:(CBATTRequest *)request
{
NSLog(@"收到写请求");
}
@end

四、设备作为中央设备

很多其它的时候,我们须要的是一个中央设备,外围设备不一定是iOS设备,所以上面外围设备的创建不一定会用到。比方外围设备是GPS导航仪、心率仪等。这些仅仅要遵循BLE4.0的规范,中央设备就能够与之连接并寻找服务和订阅特征。

设备作为中央设备的创建步骤:
  1. 创建中央设备管理器对象CBCentralManager,设置代理
  2. 扫描外围设备,发现外围设备CBPeripheral进行连接,保持连接的外围设备
  3. 在连接外围设备成功的代理方法中,设置外围设备的代理。调用外围设备的对象方法寻找服务
  4. 查找外围设备的服务和特征。查找到可用特征,则读取特征数据。

    • **记住这里是外围设备对象CBPeripheral

      不是上面的外围设备管理器对象CBPeripheralManager**
中央设备管理器的代理方法:
/* 中央设备管理器状态改变后调用,比方蓝牙的打开与关闭 */
- (void)centralManagerDidUpdateState:(CBCentralManager *)central;
/* 开启扫描后。中央设备管理器发现外围设备后调用 */
- (void)centralManager:(CBCentralManager *)central
didDiscoverPeripheral:(CBPeripheral *)peripheral /* 外围设备 */
advertisementData:(NSDictionary *)advertisementData /* 设备信息 */
RSSI:(NSNumber *)RSSI; /* 信号强度 */
/* 中央设备管理器成功连接到外围设备后调用 */
- (void)centralManager:(CBCentralManager *)central
didConnectPeripheral:(CBPeripheral *)peripheral;/* 外围设备 */
/* 中央设备管理器连接外围设备失败后调用 */
- (void)centralManager:(CBCentralManager *)central
didFailToConnectPeripheral:(CBPeripheral *)peripheral /* 外围设备 */
error:(NSError *)error;/* 连接失败的错误信息 */
中央设备管理器的对象方法:
/* 扫描外围设备,能够指定含有指定服务的外围设备 */
- (void)scanForPeripheralsWithServices:(NSArray<CBUUID *> *)services
options:(NSDictionary *)options;
/* 停止扫描 */
- (void)stopScan;
/* 连接外围设备 */
- (void)connectPeripheral:(CBPeripheral *)peripheral
options:(NSDictionary *)options;
/* 断开外围设备 */
- (void)cancelPeripheralConnection:(CBPeripheral *)peripheral;
外围设备的代理方法【和上面的外围设备管理器代理不一样】
/**
* 1.成功订阅外围设备的服务后调用,在该代理方法中寻找服务的特征
* @param peripheral 连接到的设备
* @param error 错误信息
*/
- (void)peripheral:(CBPeripheral *)peripheral
didDiscoverServices:(NSError *)error;
/**
* 2.成功找到外围设备服务的特征后调用,在该代理方法中设置订阅方式
* @param peripheral 连接的设备
* @param service 拥有的服务
* @param error 错误信息
*/
- (void)peripheral:(CBPeripheral *)peripheral
didDiscoverCharacteristicsForService:(CBService *)service
error:(NSError *)error;
/**
* 3.外围设备读取到特征值就会调用
* @param peripheral 连接的设备
* @param characteristic 改变的特征
* @param error 错误信息
*/
- (void)peripheral:(CBPeripheral *)peripheral
didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error;
/**
* 4.向外围设备的特征对象写操作完毕后调用
* 特别:当写操作为CBCharacteristicWriteWithoutResponse时不会调用
* @param peripheral 连接的设备
* @param characteristic 要写入的特征
* @param error 错误信息
*/
- (void)peripheral:(CBPeripheral *)peripheral
didWriteValueForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error;
外围设备CBPeripheral的经常使用对象方法:
/* 寻找服务,传入的是服务的唯一标识CBUUID */
- (void)discoverServices:(NSArray<CBUUID *> *)services;
/* 寻找指定服务下的特征。特征数组也是传入特征的唯一标识CBUUID */
- (void)discoverCharacteristics:(NSArray<CBUUID *> *)characteristics
forService:(CBService *)service;/* 服务 */
/* 设置是否向特征订阅数据实时通知,YES表示会实时多次会调用代理方法读取数据 */
- (void)setNotifyValue:(BOOL)value
forCharacteristic:(CBCharacteristic *)characteristic;
/* 读取特征的数据,调用此方法后会调用一次代理方法读取数据 */
- (void)readValueForCharacteristic:(CBCharacteristic *)characteristic;
/* 向特征写入数据,看type类型。决定调不调用写入数据后回调的代理方法 */
- (void)writeValue:(NSData *)value /* 写入数据 */
forCharacteristic:(CBCharacteristic *)characteristic /* 特征 */
type:(CBCharacteristicWriteType)type;/* 写入类型 */
写入类型眼下仅仅有2种方式:
/* 写入类型,决定要不要调用代理方法 */
typedef NS_ENUM(NSInteger, CBCharacteristicWriteType) {
CBCharacteristicWriteWithResponse = 0, //有回调的写入
CBCharacteristicWriteWithoutResponse //没回调的写入
};
以下是设备作为中央设备的实例:
#import "CentralViewController.h"
#import <CoreBluetooth/CoreBluetooth.h> #define kPeripheralName @"Liuting's Device" //外围设备名称
#define kServiceUUID @"FFA0-FFB0" //服务的UUID
#define kCharacteristicUUID @"FFCC-FFDD" //特征的UUID @interface CentralViewController ()<CBCentralManagerDelegate,CBPeripheralDelegate>
@property (strong, nonatomic) CBCentralManager *centralManager;/* 中央设备管理器 */
@property (strong, nonatomic) NSMutableArray *peripherals;/* 连接的外围设备 */
@end
@implementation CentralViewController
#pragma mark - UI事件
- (void)viewDidLoad{
[super viewDidLoad];
self.peripherals = [NSMutableArray array];
//创建中心设备管理器并设置当前控制器视图为代理
self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
#pragma mark - CBCentralManager代理方法
/* 中央设备管理器状态更新后调用 */
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
switch (central.state) {
case CBPeripheralManagerStatePoweredOn:
NSLog(@"BLE已打开.");
//扫描外围设备
[central scanForPeripheralsWithServices:nil options:nil];
break;
default:
NSLog(@"此设备不支持BLE或未打开蓝牙功能,无法作为中央设备.");
break;
}
}
/*
* 发现外围设备调用
* @param central 中央设备管理器
* @param peripheral 外围设备
* @param advertisementData 设备信息
* @param RSSI 信号质量(信号强度)
*/
- (void)centralManager:(CBCentralManager *)central
didDiscoverPeripheral:(CBPeripheral *)peripheral
advertisementData:(NSDictionary *)advertisementData
RSSI:(NSNumber *)RSSI
{
NSLog(@"发现外围设备...");
//连接指定的外围设备。匹配设备名
if ([peripheral.name isEqualToString:kPeripheralName]) {
//加入保存外围设备,由于在此方法调用完外围设备对象就会被销毁
if(![self.peripherals containsObject:peripheral]){
[self.peripherals addObject:peripheral];
}
NSLog(@"開始连接外围设备...");
[self.centralManager connectPeripheral:peripheral options:nil];
}
}
/* 中央设备管理器成功连接到外围设备后调用 */
- (void)centralManager:(CBCentralManager *)central
didConnectPeripheral:(CBPeripheral *)peripheral
{
NSLog(@"连接外围设备成功!"); //停止扫描
[self.centralManager stopScan];
//设置外围设备的代理为当前视图控制器
peripheral.delegate = self;
//外围设备開始寻找服务
[peripheral discoverServices:@[[CBUUID UUIDWithString:kServiceUUID]]];
}
/* 中央设备管理器连接外围设备失败后调用 */
- (void)centralManager:(CBCentralManager *)central
didFailToConnectPeripheral:(CBPeripheral *)peripheral
error:(NSError *)error
{
NSLog(@"连接外围设备失败!");
}
#pragma mark - CBPeripheral 代理方法
/* 外围设备寻找到服务后调用 */
- (void)peripheral:(CBPeripheral *)peripheral
didDiscoverServices:(NSError *)error
{
NSLog(@"已发现可用服务...");
//遍历查找到的服务
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID];
for (CBService *service in peripheral.services) {
if([service.UUID isEqual:serviceUUID]){
//外围设备查找指定服务中的特征,characteristics为nil。表示寻找全部特征
[peripheral discoverCharacteristics:nil forService:service];
}
}
}
/* 外围设备寻找到特征后调用 */
- (void)peripheral:(CBPeripheral *)peripheral
didDiscoverCharacteristicsForService:(CBService *)service
error:(NSError *)error
{
NSLog(@"已发现可用特征...");
//遍历服务中的特征
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID];
if ([service.UUID isEqual:serviceUUID]) {
for (CBCharacteristic *characteristic in service.characteristics) {
if ([characteristic.UUID isEqual:characteristicUUID]) {
//情景一:通知
/* 找到特征后设置外围设备为已通知状态(订阅特征):
* 调用此方法会触发代理方法peripheral:didUpdateValueForCharacteristic:error:
* 调用此方法会触发外围设备管理器的订阅代理方法
*/
[peripheral setNotifyValue:YES forCharacteristic:characteristic]; //情景二:读取
//调用此方法会触发代理方法peripheral:didUpdateValueForCharacteristic:error:
//[peripheral readValueForCharacteristic:characteristic];
}
}
}
}
/* 外围设备读取到特征值后调用 */
- (void)peripheral:(CBPeripheral *)peripheral
didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error
{
if (characteristic.value) {
NSString *value = [[NSString alloc] initWithData:characteristic.value
encoding:NSUTF8StringEncoding];
NSLog(@"读取到特征值:%@",value);
}else{
NSLog(@"未发现特征值.");
}
}
@end

五、蓝牙后台执行

除非去申请后台权限,否则 app 都是仅仅在前台执行的,程序在进入后台不久便会切换到挂起状态。挂起后,程序将无法再接收不论什么蓝牙事件。

中央设备管理器连接外围设备的方法中的options属性,能够设置例如以下字典值:
  • CBConnectPeripheralOptionNotifyOnConnectionKey

    在连接成功后。程序被挂起。给出系统提示。
  • CBConnectPeripheralOptionNotifyOnDisconnectionKey

    在程序挂起,蓝牙连接断开时,给出系统提示。
  • CBConnectPeripheralOptionNotifyOnNotificationKey

    在程序挂起后,收到 peripheral 数据时。给出系统提示。

设置蓝牙后台模式:
  • 加入info.plist字段Required background nodes
  • 在该字段下加入字符串值:
    • App communicates using CoreBluetooth:表示支持设备作为中央设备后台执行
    • App shares data using CoreBluetooth:表示支持设备作为外围设备后台执行

设备作为中央设备的后台执行和前台执行差别:
  • 会将发现的多个外围设备的广播数据包合并为一个事件,然后每找到一个外围设备都会调用发现外围设备的代理方法
  • 假设全部的应用都在后台搜索外围设备。那么每次搜索的时间间隔会更大。这会导致搜索到外围设备的时间变长
设备作为外围设备的后台执行和前台执行差别:
  • 在广播时,广播数据将不再包括外围设备的名字
  • 外围设备仅仅能被明白标识了搜索服务UUID的iOS设备找到
  • 假设全部应用都在后台发起广播,那么发起频率会减少

关于后台执行的细节。能够參考:CoreBluetooth8 后台执行蓝牙服务

上面的代码Demo点这里:LearnDemo里面的BluetoothDemo

有什么问题在下方评论区中提出!O(∩_∩)O哈。

iOS学习笔记30-系统服务(三)蓝牙的更多相关文章

  1. iOS学习笔记14-网络(三)WebView

    一.WebView WebView就是一个内嵌浏览器控件,在iOS中主要有两种WebView:UIWebView和WKWebView,UIWebView是iOS2之后开始使用,WKWebView是在i ...

  2. iOS学习笔记-精华整理

    iOS学习笔记总结整理 一.内存管理情况 1- autorelease,当用户的代码在持续运行时,自动释放池是不会被销毁的,这段时间内用户可以安全地使用自动释放的对象.当用户的代码运行告一段 落,开始 ...

  3. iOS学习笔记总结整理

    来源:http://mobile.51cto.com/iphone-386851_all.htm 学习IOS开发这对于一个初学者来说,是一件非常挠头的事情.其实学习IOS开发无外乎平时的积累与总结.下 ...

  4. IOS学习笔记48--一些常见的IOS知识点+面试题

      IOS学习笔记48--一些常见的IOS知识点+面试题   1.堆和栈什么区别? 答:管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制:对于堆来说,释放工作由程序员控制,容易产生memor ...

  5. iOS学习笔记——AutoLayout的约束

    iOS学习笔记——AutoLayout约束 之前在开发iOS app时一直以为苹果的布局是绝对布局,在IB中拖拉控件运行或者直接使用代码去调整控件都会发上一些不尽人意的结果,后来发现iOS在引入了Au ...

  6. iOS学习笔记10-UIView动画

    上次学习了iOS学习笔记09-核心动画CoreAnimation,这次继续学习动画,上次使用的CoreAnimation很多人感觉使用起来很繁琐,有没有更加方便的动画效果实现呢?答案是有的,那就是UI ...

  7. iOS学习笔记之ARC内存管理

    iOS学习笔记之ARC内存管理 写在前面 ARC(Automatic Reference Counting),自动引用计数,是iOS中采用的一种内存管理方式. 指针变量与对象所有权 指针变量暗含了对其 ...

  8. IOS学习笔记(四)之UITextField和UITextView控件学习

    IOS学习笔记(四)之UITextField和UITextView控件学习(博客地址:http://blog.csdn.net/developer_jiangqq) Author:hmjiangqq ...

  9. IOS学习笔记06---C语言函数

    IOS学习笔记06---C语言函数 --------------------------------------------  qq交流群:创梦技术交流群:251572072              ...

  10. [置顶] iOS学习笔记47——图片异步加载之EGOImageLoading

    上次在<iOS学习笔记46——图片异步加载之SDWebImage>中介绍过一个开源的图片异步加载库,今天来介绍另外一个功能类似的EGOImageLoading,看名字知道,之前的一篇学习笔 ...

随机推荐

  1. Spring MVC表单处理

    以下示例演示如何编写一个简单的基于Web的应用程序,它使用Spring Web MVC框架使用HTML表单. 首先使用Eclipse IDE,并按照以下步骤使用Spring Web Framework ...

  2. unsigned int与int相加的问题-----C/C++小知识 区别

    http://blog.csdn.net/thefutureisour/article/details/8147277 #include "stdafx.h" int _tmain ...

  3. 关于U盘启动操作系统《30天自制操作系统》

    原本的启动是从img启动的,并且这个img是用FAT12文件系统进行格式化的(详细去搜索FAT12文件格式,这里给大家推荐一篇http://www.doc88.com/p-646605198560.h ...

  4. Drawable的getIntrinsicHeight()和getIntrinsicWidth()

    版权声明:本文为博主原创文章,未经博主允许不得转载. 今天遇到一个问题,一个Bitmap封装到BitmapDrawable中 ,BitmapDrawable drawable = new Bitmap ...

  5. TeX系列: MATLAB和LaTeX结合绘图

    目的是在MATLAB中绘图,在LaTeX中利用PGFPlots实现对图的修饰,比如坐标系.坐标轴标记.标题等等.这样能够保证图的中标记与正文文本的一致性,同时又可利用MATLAB强大的数据处理和丰富的 ...

  6. 在pycharm中进行nosetests并输出测试报告

    1.首先配置

  7. Android NDK开发----- JNI多线程

    一.概述 JNI编程和Linux上的C/C++编程还是挺相似的,每次java调用JNI中的函数时都会传入有关JVM的一些参数(如JNIEnv,jobject),每次JNI回调java中的方法时都要通过 ...

  8. [Todo] Nodejs学习及Spider实验(包括php入门学习、React入门学习)

    /Users/baidu/Documents/Data/Interview/Web-Server开发 深入浅出Node.js-f46c http://blog.csdn.net/u012273376/ ...

  9. IP addr命令

    我们都知道Windows上查看IP地址是ipconfig, Linux上是ifconfig,但是Linux上还有一个命令叫ip addr可以查看IP地址. 如上图所示命令显示了机器上的所有网卡,大部分 ...

  10. jquery的$.each()

    each()方法能使DOM循环结构简洁,不容易出错.each()函数封装了十分强大的遍历功能,使用也很方便,它可以遍历一维数组.多维数组.DOM, JSON 等等在javaScript开发过程中使用$ ...