首先从main.m文件的main函数开始执行的。
创新互联建站长期为千余家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为青海企业提供专业的成都网站设计、成都网站制作,青海网站改版等技术服务。拥有10多年丰富建站经验和众多成功案例,为您定制开发。
int main(int argc, char * argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
//1、principalClassName:应用程序对象的类名(UIApplication或其子类)
//2、delegateClassName:应用程序delegate的类名。(任何接受了UIApplicationDelegate的类)
UIApplicationMain根据上述两个类名创建应用程序实例、应用程序代理实例。然后建立事件循环(runloop),检测程序的各种事件(程序开始启动,接收到触摸等等)
在执行UIApplicationMain函数时做了跳转,转到了AppDelete中。应用程序代理,主要检测应用程序的状态并做出相应的处理。应用程序的状态有很多,比如:程序启动、进入活跃状态、进到后台、内存警告、收到远程消息等等。任何接受了UIApplicationDelegate协议的对象都可以成为应用程序代理。一旦应用程序的某种状态触发,就会执行相应的代理方法。UIApplicationDelegate是一个OC的协议。里面声明了一堆方法,这些方法都与应用程序运行状态有关,它们由应用程序代理实现。UIApplication对象负责调用。
application:didFinishLaunchingWithOptions:告诉delegate程序启动即将完成,程序准备要运行。(delegate实现这个方法时,要创建window对象,将程序内容通过window呈现给用户。),在该方法中为我们应用程序创建window等必要的界面
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
一、搭建开发环境
1. 打开Xcode, 新建一个工程
选择:IOS - Application - Single View Application模板
输入工程名称和基本信息,勾选“UseStoryboards”,然后创建
2. 添加必要的框架
在“Build Phases”中,添加三个框架
3. 修改viewController。h
添加 “#import”,并将它修改为继承"GLKViewController"
4. 修改“view”的类
双击“MainStoryboard.storyboard”展开,选择"view"
然后,在“Identity Inspector"中,将它的类改为”GLKView“
好了,OpenGL的环境基本上搭建出来了。
二、增加自己代码
基本上,所有的代码都是加到ViewController.m文件中
1、添加全局属性声明
@interface ViewController ()@property(strong,nonatomic)EAGLContext*
context;@property(strong,nonatomic)GLKBaseEffect* effect;@end@implementation
ViewController@synthesize context, effect;
2、 添加一组顶点数据
这是一个正方形顶点数组。实际上它是二个三角形接合而成的
GLfloat squareVertexData[48] ={ 0.5f, 0.5f, -0.9f, 0.0f, 0.0f, 1.0f, 1.0f,
1.0f, -0.5f, 0.5f, -0.9f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.5f, -0.5f, -0.9f,
0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.5f, -0.5f, -0.9f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.9f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, -0.5f, -0.5f, -0.9f, 0.0f,
0.0f, 1.0f, 1.0f, 1.0f,};
每行顶点数据的排列含义是:
顶点X、顶点Y,顶点Z、法线X、法线Y、法线Z、纹理S、纹理T。
在后面解析此数组时,将参考此规则。
顶点位置用于确定在什么地方显示,法线用于光照模型计算,纹理则用在贴图中。
一般约定为“顶点以逆时针次序出现在屏幕上的面”为“正面”。
世界坐标是OpenGL中用来描述场景的坐标,Z+轴垂直屏幕向外,X+从左到右,Y+轴从下到上,是右手笛卡尔坐标系统。我们用这个坐标系来描述物体及光源的位置。
三、初始化OpenGL环境
1、 基本的初始化代码
在ViewController.m中有个函数(void)viewDidLoad,它是程序运行时,初始化回调函数。在viewDidLoad函数内补充我们自己的初始化代码。
// 使用“ES2”创建一个“EAGLEContext”实例 self.context = [[[EAGLContext
alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2]autorelease]; //
将“view”的context设置为这个“EAGLContext”实例的引用。并且设置颜色格式和深度格式。 GLKView* view =
(GLKView*)self.view; view.context = self.context; view.drawableColorFormat =
GLKViewDrawableColorFormatRGBA8888; view.drawableDepthFormat =
GLKViewDrawableDepthFormat24; //
将此“EAGLContext”实例设置为OpenGL的“当前激活”的“Context”。这样,以后所有“GL”的指令均作用在这个“Context”上。随后,发送第一个“GL”指令:激活“深度检测”。
[EAGLContext setCurrentContext:context]; glEnable(GL_DEPTH_TEST); //
创建一个GLK内置的“着色效果”,并给它提供一个光源,光的颜色为绿色。 self.effect = [[[GLKBaseEffect
alloc]init]autorelease]; self.effect.light0.enabled = GL_TRUE;
self.effect.light0.diffuseColor = GLKVector4Make(0.0f, 1.0f, 0.0f, 1.0f);
2、 运行。现在应该是粉红色屏幕了(目前场景仍是空的),说明初始化过程没问题
四、 将项点数据写入能用的顶点属性存储区
1、 写入过程
首先将数据保存进GUP的一个缓冲区中,然后再按一定规则,将数据取出,复制到各个通用顶点属性中。
注:如果顶点数据只有一种类型(如单纯的位置坐标),换言之,在读数据时,不需要确定第一个数据的内存位置(总是从0开始),则不必事先保存进缓冲区。
2、 顶点数组保存进缓冲区
//
声明一个缓冲区的标识(GLuint类型)让OpenGL自动分配一个缓冲区并且返回这个标识的值.绑定这个缓冲区到当前“Context”.最后,将我们前面预先定义的顶点数据“squareVertexData”复制进这个缓冲区中。
// 注:参数“GL_STATIC_DRAW”,它表示此缓冲区内容只能被修改一次,但可以无限次读取。 GLuint buffer;
glGenBuffers(1, buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(squareVertexData), squareVertexData,
GL_STATIC_DRAW);
3、将缓冲区的数据复制进能用顶点属性中
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 4*8,
(char*)NULL + 0);
首先,激活顶点属性(默认它的关闭的)。“GLKVertexAttribPosition”是顶点属性集中“位置Position”属性的索引。
顶点属性集中包含五种属性:位置、法线、颜色、纹理0,纹理1。
它们的索引值是0到4。
激活后,接下来使用“glVertexAttribPointer”方法填充数据。
首先,让我们看看为什么要使用delegate。
一个典型的ios应用程序会有各种类型的对象:windows,tables,buttons,input boxes等等。在一个特定的应用程序中,你会让每个对象做特定的事情。比如说当用户点击一个按钮的时候,会执行一个特定的操作或者使用一个table显示特定的数据。
每个对象实例会有处理 特定 的事情。比如说我们有一个UITableView的实例,我们可能会让它以特定的方式来显示特定的 数据,同样的,我们对table的每一行进行tapping或者swiping操作的时候,它们也会做出自己特有的事件处理方式。为了避免为达到某一个特定的目的(actions or events)而创建一个子类(如果有多种不同的特定目的就会创建多个子类),你可以写出响应这些操作或者事件的方法,它们会在这些操作或者事件发生的时候被调用,为了达到此目的,你只需要给这个对象一个delegate(一个对象)。你可以使一个类作为其他一个对象或者多个对象的delegate。
简单的说代理就是在类外,让特定的人对该类做特定的操作的一种实现方法。
1、统一收键盘的方法
[[[UIApplication sharedApplication] keyWindow] endEditing:YES];
2、提示框
BBAlertView *alert = [[BBAlertView alloc] initWithStyle:BBAlertViewStyleDefault
Title:@"删除订单"
message:@"是否删除订单,"
customView:nil
delegate:self
cancelButtonTitle:L(@"取消")
otherButtonTitles:L(@"确认")];
[alert setCancelBlock:^{
}];
[alert setConfirmBlock:^{
[self orderDidRemovePressDown:tempDic Index:index.section];
}];
[alert show];
3、图片的自适应功能
self.brandImage.contentMode = UIViewContentModeScaleAspectFit;
4、cocoaPods清除缓存问题
$ sudo rm -fr ~/.cocoapods/repos/master
$ pod setup
5、设置显示键盘的样式
textView.keyboardType =UIKeyboardTypeDefault;
//设置键盘右下角为完成(中文输入法下)
textView.returnKeyType=UIReturnKeyDone;
6、输出当前时间
NSDateFormatter * dateFormatter=[[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"];
NSLog(@"当前毫秒时间1==%@",[dateFormatter stringFromDate:[NSDate date]]);
7、显示两秒然后消失
UILabel * lab=[[UILabel alloc]initWithFrame:CGRectMake(60,Main_Screen_Height-64-49-60, Main_Screen_Width-120, 50)];
lab.backgroundColor=[UIColor grayColor];
ViewRadius(lab, 20);
lab.textAlignment=NSTextAlignmentCenter;
lab.text=@"请先进行实名制验证";
[self.view addSubview:lab];
[UILabel animateWithDuration:2 animations:^{
lab.alpha=0;
}completion:^(BOOL finished) {
[lab removeFromSuperview];
}];
8、设置placeholder属性的大小和颜色
[_phoneFie setValue:[UIColor grayColor] forKeyPath:@"_placeholderLabel.textColor"];
[_phoneFie setValue:[UIFont boldSystemFontOfSize:15] forKeyPath:@"_placeholderLabel.font"];
_phoneFie.returnKeyType=UIReturnKeyDone;
9、设置cell的交互完全不可以使用
//[cellTwo setUserInteractionEnabled:NO];
//设置cell不可以点击,但是上面的子控件可以交互
cellTwo.selectionStyle=UITableViewCellSelectionStyleNone;
10、将textField的placeholder 属性的字体向右边移动5
_field.leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10*Width_375, _field.frame.size.height)];
_field.leftViewMode = UITextFieldViewModeAlways;
11、开新线程使按钮上的时间变化
-(void)startTime{
__block int timeout=60; //倒计时时间
UIButton * btn=(UIButton *)[self.view viewWithTag:1000];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,queue);
dispatch_source_set_timer(_timer,dispatch_walltime(NULL, 0),1.0*NSEC_PER_SEC, 0); //每秒执行
dispatch_source_set_event_handler(_timer, ^{
if(timeout=0){
dispatch_source_cancel(_timer);
dispatch_async(dispatch_get_main_queue(), ^{
[btn setTitle:@"发送验证码" forState:UIControlStateNormal];
btn.enabled = YES;
});
}else{
// int minutes = timeout / 60;
int miao = timeout % 60;
if (miao==0) {
miao = 60;
}
NSString *strTime = [NSString stringWithFormat:@"%.2d", miao];
dispatch_async(dispatch_get_main_queue(), ^{
[btn setTitle:[NSString stringWithFormat:@"剩余%@秒",strTime] forState:UIControlStateNormal];
btn.enabled = NO;
});
timeout--;
}
});
dispatch_resume(_timer);
}
12、隐藏TableView 中多余的行
UIView * view=[[UIView alloc]initWithFrame:CGRectZero];
[_tabelView setTableFooterView:view];
13、UIView添加背景图片
UIImage * image=[UIImage imageNamed:@"friend750"];
headSeV.layer.contents=(id)image.CGImage;
14、UITableView取消选中状态
[tableView deselectRowAtIndexPath:indexPath animated:YES];// 取消选中
15、带属性的字符串
NSFontAttributeName 字体
NSParagraphStyleAttributeName 段落格式
NSForegroundColorAttributeName 字体颜色
NSBackgroundColorAttributeName 背景颜色
NSStrikethroughStyleAttributeName 删除线格式
NSUnderlineStyleAttributeName 下划线格式
NSStrokeColorAttributeName 删除线颜色
NSStrokeWidthAttributeName 删除线宽度
NSShadowAttributeName 阴影
1. 使用实例
UILabel *testLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 100, 320, 30)];
testLabel.backgroundColor = [UIColor lightGrayColor];
testLabel.textAlignment = NSTextAlignmentCenter;
NSMutableAttributedString *AttributedStr = [[NSMutableAttributedString alloc]initWithString:@"今天天气不错呀"];
[AttributedStr addAttribute:NSFontAttributeName
value:[UIFont systemFontOfSize:16.0]
range:NSMakeRange(2, 2)];
[AttributedStr addAttribute:NSForegroundColorAttributeName
value:[UIColor redColor]
range:NSMakeRange(2, 2)];
testLabel.attributedText = AttributedStr;
[self.view addSubview:testLabel];
16、加大按钮的点击范围
把UIButton的frame 设置的大一些,然后给UIButton设置一个小些的图片
[tmpBtn setImageEdgeInsets:UIEdgeInsetsMake(5, 5, 5, 5)];
// 注意这里不能用setBackgroundImage
[tmpBtn setImage:[UIImage imageNamed:@"testBtnImage"] forState:UIControlStateNormal];
17、//避免self的强引用
__weak ViewController *weakSelf = self;
18、//类别的创建
command +n ——Objective-C File———(File Type 选择是类别还是扩展)———(Class 选择为哪个控件写类别)
19、修改UITableview 滚动条颜色的方法
self.tableView.indicatorStyle=UIScrollViewIndicatorStyleWhite;
20、利用UIWebView显示pdf文件
webView = [[UIWebView alloc]initWithFrame:CGRectMake(0, 0, 320, 480)];
[webView setDelegate:self];
[webView setScalesPageToFit:YES];
[webViewsetAutoresizingMask:UIViewAutoresizingFlexibleWidth |UIViewAutoresizingFlexibleHeight];
[webView setAllowsInlineMediaPlayback:YES];
[self.view addSubview:webView];
NSString *pdfPath = [[NSBundle mainBundle]pathForResource:@"ojc" ofType:@"pdf"];
NSURL *url = [NSURLfileURLWithPath:pdfPath];
NSURLRequest *request = [NSURLRequestrequestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:5];
[webView loadRequest:request];
21、将plist文件中的数据赋给数组
NSString *thePath = [[NSBundle mainBundle]pathForResource:@"States" ofType:@"plist"];
NSArray *array = [NSArrayarrayWithContentsOfFile:thePath];
22、隐藏状态栏
[[UIApplication shareApplication]setStatusBarHidden: YES animated:NO];
23、给navigation Bar 设置title颜色
UIColor *whiteColor = [UIColor whiteColor];
NSDictionary *dic = [NSDictionary dictionaryWithObject:whiteColor forKey:NSForegroundColorAttributeName];
[self.navigationController.navigationBar setTitleTextAttributes:dic];
24、使用AirDrop 进行分享
NSArray *array = @[@"test1", @"test2"];
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:array applicationActivities:nil];
[self presentViewController:activityVC animated:YES
completion:^{
NSLog(@"Air");
}];
25、把tableview里面Cell的小对勾的颜色改成别的颜色
_mTableView.tintColor = [UIColor redColor];
26、UITableView去掉分割线
_tableView.separatorStyle = NO;
27、正则判断手机号码地址格式
- (BOOL)isMobileNumber:(NSString *)mobileNum {
// 电信号段:133/153/180/181/189/177
// 联通号段:130/131/132/155/156/185/186/145/176
// 移动号段:134/135/136/137/138/139/150/151/152/157/158/159/182/183/184/187/188/147/178
// 虚拟运营商:170
NSString *MOBILE = @"^1(3[0-9]|4[57]|5[0-35-9]|8[0-9]|7[06-8])\\d{8}$";
NSPredicate *regextestmobile = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", MOBILE];
return [regextestmobile evaluateWithObject:mobileNum];
}
28、控制交易密码位数
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
if (textField.text.length =6){
[MBProgressHUD showMessage:@"密码为6位" afterDelay:1.8];
return NO;
}
return YES;
}
29、判断是不是空
if ([real_name isKindOfClass:[NSNull class]] ) {
return NO;}
30、点击号码拨打电话
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"tel://400966220"]];
31、控制UITabbar的选择哪一个
[self.tabBarController setSelectedIndex:1];
32、获取当前App的版本号
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
CFShow(infoDictionary);
// app名称
NSString *app_Name = [infoDictionary objectForKey:@"CFBundleDisplayName"];
// app版本
NSString *app_Version = [infoDictionary objectForKey:@"CFBundleShortVersionString"];
// app build版本
NSString *app_build = [infoDictionary objectForKey:@"CFBundleVersion"];
33、苹果app权限NSPhotoLibraryUsageDescriptionApp需要您的同意,才能访问相册NSCameraUsageDescriptionApp需要您的同意,才能访问相机NSMicrophoneUsageDescriptionApp需要您的同意,才能访问麦克风NSLocationUsageDescriptionApp需要您的同意,才能访问位置NSLocationWhenInUseUsageDescriptionApp需要您的同意,才能在使用期间访问位置NSLocationAlwaysUsageDescriptionApp需要您的同意,才能始终访问位置NSCalendarsUsageDescriptionApp需要您的同意,才能访问日历NSRemindersUsageDescriptionApp需要您的同意,才能访问提醒事项NSMotionUsageDescriptionApp需要您的同意,才能访问运动与健身NSHealthUpdateUsageDescriptionApp需要您的同意,才能访问健康更新NSHealthShareUsageDescriptionApp需要您的同意,才能访问健康分享NSBluetoothPeripheralUsageDescriptionApp需要您的同意,才能访问蓝牙NSAppleMusicUsageDescriptionApp需要您的同意,才能访问媒体资料库
34、控件设置边框
_describText.layer.borderColor = [[UIColor colorWithRed:215.0 / 255.0 green:215.0 / 255.0 blue:215.0 / 255.0 alpha:1] CGColor];
_describText.layer.borderWidth = 1.0;
_describText.layer.cornerRadius = 4.0;
_describText.clipsToBounds = YES;
35、//隐藏电池条的方法
-(BOOL)prefersStatusBarHidden{
return YES;
}
36、延时操作
[NSThread sleepForTimeInterval:2];
方法二:
[self performSelector:@selector(delayMethod) withObject:nil afterDelay:1.5];
37、系统风火轮:
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO; //隐藏
38、//didSelectRowAtIndexPath:方法里面找到当前的Cell
AssessMentCell * cell = [tableView cellForRowAtIndexPath:indexPath];
39、navigation上返回按钮的颜色以及返回按钮后面文字去掉
//返回按钮后边文字去掉
[[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -60)
forBarMetrics:UIBarMetricsDefault];
//设置左上角返回按钮的颜色
self.navigationController.navigationBar.tintColor = UIColorFromRGB(0x666666);
40、lineBreakMode //设置文字过长时的显示格式
label.lineBreakMode = NSLineBreakByCharWrapping;以字符为显示单位显
示,后面部分省略不显示。
label.lineBreakMode = NSLineBreakByClipping;剪切与文本宽度相同的内
容长度,后半部分被删除。
label.lineBreakMode = NSLineBreakByTruncatingHead;前面部分文字
以……方式省略,显示尾部文字内容。
label.lineBreakMode = NSLineBreakByTruncatingMiddle;中间的内容
以……方式省略,显示头尾的文字内容。
label.lineBreakMode = NSLineBreakByTruncatingTail;结尾部分的内容
以……方式省略,显示头的文字内容。
label.lineBreakMode = NSLineBreakByWordWrapping;以单词为显示单位显
示,后面部分省略不显示。
蓝牙开发说简单也简单,说不简单也有点难,开发人员在首次开发蓝牙前首先需要搞清楚蓝牙开发的概念,还要了解掌握蓝牙开发的一整套流程,这样才能快速上手开发蓝牙。
蓝牙开发分为两种模式:管理者模式和中心者模式。管理者模式基本很少用到,相当于iPhone手机作为外设,自己创建服务和特性,然后用其他设备连接iPhone手机;中心者模式一般是大部分情况下都会使用的,使用中心者模式开发相当于iPhone手机作为主机,连接蓝牙外设,下面介绍蓝牙开发的例子就是使用的中心者模式来讲解的。
在这里我还是要推荐下我自己建的iOS开发学习群:680565220,群里都是学ios开发的,如果你正在学习ios ,我欢迎你加入,今天分享的这个案例已经上传到群文件,大家都是软件开发党,不定期分享干货(只有iOS软件开发相关的),包括我自己整理的一份2018最新的iOS进阶资料和高级开发教程
一、关于蓝牙开发的一些重要的理论概念:
1、服务(services):蓝牙外设对外广播的时候一定会有一个服务,有些时候也可以是有多个服务,服务下面包含一些特性,服务可以理解成一个模块的窗口;
2、特征(characteristic):特征存在于服务下面的,一个服务下面可以有多个特征,特征可以理解成具体实现功能的窗口,一般的特性都会有value,也就是特征值,是特征和外界交互的最小单位;
3、UUID:蓝牙上的唯一标示符,为了区分不同服务和特征,就用UUID来表示。
二、蓝牙连接的主要步骤
1、创建一个CBCentralManager实例来进行蓝牙管理;
2、搜索扫描外围设备;
3、连接外围设备;
4、获得外围设备的服务;
5、获得服务的特征;
6、从外围设备读取数据;
7、给外围设备发送(写入)数据。
三、蓝牙连接和数据读写的具体步骤
1、导入苹果系统蓝牙框架
#import
2、遵循两个蓝牙框架相关的协议
3、新建两个实例属性,一个特征属性
@property (nonatomic, strong) CBCentralManager *centralManager; //中心管理者
@property (nonatomic, strong) CBPeripheral *peripheral; //连接到的外设
@property (nonatomic, strong) CBCharacteristic *characteristic; //特征
4、初始化CBCentralManager,进行蓝牙管理
- (void)viewDidLoad {
[super viewDidLoad];
self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()]; //创建实例进行蓝牙管理
}
//若中心管理者初始化之后 就会触发下面这个代理方法 该代理方法是用来判断手机蓝牙的状态的
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
// 蓝牙可用,开始扫描外设
if (central.state == CBManagerStatePoweredOn) {
NSLog(@"蓝牙可用");
//在中心管理者成功开启之后再进行一些操作
//搜索扫描外设
// 根据SERVICE_UUID来扫描外设,如果不设置SERVICE_UUID,则扫描所有蓝牙设备
// [self.centralManager startAdvertising:@{CBAdvertisementDataServiceUUIDsKey:@[[CBUUID UUIDWithString:SERVICE_UUID]]}];
[central scanForPeripheralsWithServices:nil options:nil];
}
if(central.state == CBManagerStateUnsupported) {
NSLog(@"该设备不支持蓝牙");
}
if (central.state == CBManagerStatePoweredOff) {
NSLog(@"蓝牙已关闭");
}
if (central.state == CBManagerStateUnknown) {
NSLog(@"蓝牙当前状态不明确");
}
if (central.state == CBManagerStateUnauthorized) {
NSLog(@"蓝牙未被授权");
}
}
5、搜索外围设备
//执行扫描动作之后,如果扫描到外设了,就会自动回调下面的协议方法
/** 发现符合要求的外设,回调 */
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
NSLog(@"%@====",peripheral.name);
//根据外设名字有选择性的筛选连接蓝牙设备
if ([peripheral.name hasPrefix:@"TEAMOSA"]) {
//在这里对外设携带的广播数据进行进一步的处理
if ([self.peripheraNames containsObject:peripheral.name]) {
//如果数组中包含了就不再添加
return;
}
//添加到外设名字数组中
[self.peripheraNames addObject:peripheral.name];
//标记外设,让它的生命周期与控制器的一致
self.peripheral = peripheral;
// 可以根据外设名字来过滤外设
// [central connectPeripheral:peripheral options:nil];
}
// 连接外设
// [central connectPeripheral:peripheral options:nil];
}
6、连接外围设备
//连接外围设备,中心管理者连接外设成功,如果连接成功就会回调这个协议方法
/** 连接成功 */
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
//连接成功之后,可以进行服务和特性的发现。 停止中心管理设备的扫描动作,要不然在你和已经连接好的外设进行数据沟通时,如果又有一个外设进行广播且符合你的连接条件,那么你的iOS设备也会去连接这个设备(因为iOS BLE4.0是支持一对多连接的),导致数据的混乱。
//停止扫描动作
[self.centralManager stopScan];
// 设置外设的代理
peripheral.delegate = self;
// 根据UUID来寻找服务
// [peripheral discoverServices:@[[CBUUID UUIDWithString:SERVICE_UUID]]];
//外设发现服务,传nil代表不过滤,一次性读出外设的所有服务
[peripheral discoverServices:nil];
NSLog(@"%s, line = %d, %@=连接成功", __FUNCTION__, __LINE__, peripheral.name);
}
//外设连接失败
/** 连接失败的回调 */
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
NSLog(@"%s, line = %d, %@=连接失败", __FUNCTION__, __LINE__, peripheral.name);
}
//丢失连接 掉线
/** 断开连接 */
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error {
NSLog(@"%s, line = %d, %@=断开连接", __FUNCTION__, __LINE__, peripheral.name);
// 断开连接可以设置重新连接
[central connectPeripheral:peripheral options:nil];
}
7、获取外围设备服务和特征
/** 发现服务 */
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
// 遍历出外设中所有的服务
for (CBService *service in peripheral.services) {
// NSLog(@"所有的服务:%@",service);
}
// 这里仅有一个服务,所以直接获取
CBService *service = peripheral.services.lastObject;
// 根据UUID寻找服务中的特征
// [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:CHARACTERISTIC_UUID]] forService:service];
// [peripheral discoverCharacteristics:@[service.UUID] forService:service];
[peripheral discoverCharacteristics:nil forService:service];
}
8、从外围设备读取数据
// 更新特征的value的时候会调用 (凡是从蓝牙传过来的数据都要经过这个回调,简单的说这个方法就是你拿数据的唯一方法) 你可以判断是否 从外围设备读数据
/** 接收到数据回调 */
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
// if (characteristic == @"你要的特征的UUID或者是你已经找到的特征") {
// //characteristic.value就是你要的数据
// }
if ([peripheral.name hasPrefix:@"TEAMOSA"]){
NSData *data = characteristic.value;
NSString *value = [self hexadecimalString:data];
// NSLog(@"characteristic(读取到的): %@, data : %@, value : %@", characteristic, data, value);
}
// 拿到外设发送过来的数据
// NSData *data = characteristic.value;
// self.textFild.text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
9、向外围设备发送(写入)数据
//这个方法你可以放在button的响应里面,也可以在找到特征的时候就写入,具体看你业务需求怎么用
//[self.peripherale writeValue:_batteryData forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];//第一个参数是已连接的蓝牙设备; 第二个参数是要写入到哪个特征; 第三个参数是通过此响应记录是否成功写入 需要注意的是特征的属性是否支持写数据
/** 写入数据回调 */
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error {
/*
typedef NS_OPTIONS(NSUInteger, CBCharacteristicProperties) {
CBCharacteristicPropertyBroadcast = 0x01,
CBCharacteristicPropertyRead = 0x02,
CBCharacteristicPropertyWriteWithoutResponse = 0x04,
CBCharacteristicPropertyWrite = 0x08,
CBCharacteristicPropertyNotify = 0x10,
CBCharacteristicPropertyIndicate = 0x20,
CBCharacteristicPropertyAuthenticatedSignedWrites = 0x40,
CBCharacteristicPropertyExtendedProperties = 0x80,
CBCharacteristicPropertyNotifyEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0) = 0x100,
CBCharacteristicPropertyIndicateEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0) = 0x200
};
打印出特征的权限(characteristic.properties),可以看到有很多种,这是一个NS_OPTIONS的枚举,可以是多个值
常见的又read,write,noitfy,indicate.知道这几个基本够用了,前俩是读写权限,后俩都是通知,俩不同的通知方式
*/
// NSLog(@"%s, line = %d, char.pro = %d", __FUNCTION__, __LINE__, characteristic.properties);
// 此时由于枚举属性是NS_OPTIONS,所以一个枚举可能对应多个类型,所以判断不能用 = ,而应该用包含
NSLog(@"write value success(写入成功) : %@", characteristic);
}
10、具体调用给蓝牙外设写入数据方法,这里的例子是以按钮点击事件里面来调用处理
//发送按钮点击事件
- (void)sendClick {
if (!self.characteristic) {
return;
}
_tempValue = [NSString stringWithFormat:@"%.0f", progressView.centigradeDegree];
_timeValue = [NSString stringWithFormat:@"%.0ld", (long)progressView1.timeDegree];
NSString *ttData = [NSString stringWithFormat:@"%@,%@U", _tempValue, _timeValue];
// NSString *aaa = [DataCoverTool coverFromStringToHexStr:ttData];
// 用NSData类型来写入
// NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arry];
NSData *data = [ttData dataUsingEncoding:NSUTF8StringEncoding];
// NSData *data = [self dataWithString:ttData];
// 根据上面的特征self.characteristic来写入数据
[self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];