iOS--block再学习

news2024/11/23 22:38:19

block再学习

  • 什么是block
    • block是带有自动变量的匿名函数
    • block语法
  • block的实现
    • block的实质
    • 截获自动变量
    • __blcok说明符
    • Block存储域
    • __block变量存储域
      • 使用__block变量用结构体成员变量__forwarding的原因
    • 截获对象

什么是block

Block时c语言的扩充功能,它允许开发者定义一段可重用的代码,并在需要时像变量一样使用这段代码。
对于block最重要的几个特点,总结如下:

  • Block本质上是一个OC对象,具有自己的isa指针。
  • 它可以看作是带有自动捕获变量能力的匿名函数。
  • Block可以捕获和存储它所在的环境中的变量和常量。

首先我们先从它可以看作是带有自动捕获变量能力的匿名函来了解和分析block ;

block是带有自动变量的匿名函数

首先我们先来了解一下自动变量的概念 ;

在 Objective-C(OC)中,自动变量(Automatic Variables)通常指的是在函数或方法内部定义的局部变量,这些变量在函数或方法被调用时自动在栈(stack)上分配内存,并在函数或方法执行完毕后自动释放内存。这些变量的作用域仅限于定义它们的函数或方法内部。

其实在这个地方我们可以把自动变量理解为局部变量 ;
在Objective-C中,Block可以捕获其定义范围内可见的局部变量,但是它们捕获这些变量的方式取决于这些变量的存储类型修饰符。修饰符之后仔讲 ;

匿名函数如它的名称一样,是一种没有名称的函数。

那我们为什么要用block,而不直接用函数呢,明明普通函数能实现,
以下是使用Block的一些主要原因:

  • 闭包(Closure)特性:
    Block可以捕获其定义范围内的变量和常量,包括外部函数的局部变量和全局变量。这使得Block可以访问和操作这些变量,就像它们是Block自己的局部变量一样。这种闭包特性使得Block能够封装和保存函数的状态,从而实现更复杂的逻辑。

  • 匿名性:
    Block没有名称,因此它们可以作为参数传递给其他函数或方法,或者作为属性存储在对象中。这使得Block可以方便地在代码之间传递和使用,而无需担心命名冲突或额外的命名空间管理。

  • 类型安全:
    虽然Block在语法上类似于C函数,但它们是Objective-C的类型,并且支持类型检查。这意味着可以在编译时捕获与Block类型相关的错误,从而提高代码的质量和可维护性。

  • 简洁性: Block可以内联定义在需要使用它们的代码块中,无需单独声明和定义函数。这使得代码更加简洁和易读,同时减少了函数调用的开销。

  • 异步编程:
    在Objective-C中,异步编程通常涉及到回调函数的使用。使用Block作为回调函数可以简化代码结构,并减少嵌套回调的复杂性。例如,使用Grand
    Central Dispatch (GCD)进行异步任务时,可以使用Block作为任务完成后的回调处理程序。

  • 响应式编程:
    Block可以与响应式编程模式结合使用,以处理异步事件和流数据。通过使用Block来处理事件和数据流,可以创建更加灵活和可响应的应用程序。

  • 与Objective-C对象的集成:
    Block可以与Objective-C对象无缝集成,并且可以轻松地在Block内部访问和操作对象属性和方法。这使得Block成为处理Objective-C对象和集合类的强大工具。

  • 内存管理:
    在Objective-C中,Block的内存管理可以通过__block修饰符和ARC(自动引用计数)来管理。这减少了手动管理内存的需要,并降低了内存泄漏和野指针的风险。

    简单的说,block提供了更多的灵活性和便利性,特别是在与Objective-C对象交互的上下文中。

    顺便说一下:带有自动变量的匿名函数这一概念并不指blocks,它还存在于许多其他程序语言中;

block语法

Block 声明和定义:

returnType (^blockName)(parameters) = ^(parameters) {  
    // Block 的实现代码  
};

  • returnType:Block 返回的类型,如果 Block 没有返回值,则为 void。
  • blockName:Block 的名称,可选,通常省略以创建匿名 Block。
  • parameters:Block 接收的参数列表,如果没有参数则为空。
  • ^:这是 Block 的字面量语法,用于开始定义 Block。

如:

int (^addBlock)(int, int) = ^(int a, int b) {  
    return a + b;  
};

使用 Block:

int sum = addBlock(3, 4); // sum 现在为 7

Block 类型声明:
当不使用 typedef 来声明 Block 变量类型时:

// 声明一个返回 int 类型,接受两个 int 类型参数的 Block 变量  
int (^addBlock)(int, int) = ^(int a, int b) {  
    return a + b;  
};  
  
// 调用 Block  
int result = addBlock(3, 4);  
NSLog(@"The result is: %d", result); // 输出 "The result is: 7"

使用 typedef 来声明 Block 变量类型时:

// 使用 typedef 声明 Block 类型别名  
typedef int (^IntToIntBlock)(int, int);  
  
// 使用类型别名声明 Block 变量  
IntToIntBlock multiplyBlock = ^(int a, int b) {  
    return a * b;  
};  
  
// 调用 Block  
int product = multiplyBlock(3, 4);  
NSLog(@"The product is: %d", product); // 输出 "The product is: 12"

第二种声明很简单,主要注意一下第一种声明,或者两者间的区别 ;
如:

int (^ func ()) (int) {
    
}

上面这个形式看起来就挺怪的,但实际上这是一个返回值为block类型的函数func;

block的实现

block的实质

block实际上是作为普通的c语言代码来处理的 ;
原代码:
在这里插入图片描述

通过clang转换后的可读源代码:
在这里插入图片描述

通过block使用的匿名函数实际上被作为简单的语言函数来处理;
_cself为指向block得变量 ;
从上面转换过来的源码可以看出block在c语言中的结构就是一个结构体 ;
结构体的声明如下:
在这里插入图片描述

这事一个嵌套的结构体,这里就顺便给出其中的两个结构体的声明 ;
在这里插入图片描述

在这里插入图片描述

isa指针在对象,类,元类中就了解了,这也说明了block是一种对象;flag是一种标志,具体不太清楚;Reserved是版本升级所需要的区域;FuncPtr是指向函数的指针,实际上这个函数也是block中的具体实现 ;
Block——size是Block的大小,也是结构体的大小 ;

在这里插入图片描述

这里的构造函数初始化了Block结构体的成员变量,Blcok中自动变量的捕获也在这里完成 ;
这里会想下面这样初始化在:
在这里插入图片描述

isa指向了这个对象的类;FuncPtr和Desc分别指向了它们的构造函数,完成成员变量的初始化 ;

主函数中的
在这里插入图片描述

转换后:
在这里插入图片描述

这段代码将在栈上生成的__main_block_impl_0结构体实例的指针赋值给变量blk ;
对应了:
在这里插入图片描述

而:
在这里插入图片描述

则对应着blk();

截获自动变量

先给出转换后的源代码:
在这里插入图片描述

对比一下前面的源代码,这里只有结构体和使用时调用的函数不一样 ;
先看结构体:
在这里插入图片描述

其实从这个结构我们也可以猜到Block对自动变量的捕捉是通过成员变量赋值实现的 ;

这里也解答了,为什么Block无法捕获c语言中的数组 ,因为在c语言中数组是无法直接赋值的,但可以通过指针实现 ;

顺便注意一下,Blcok语法表达式中没有使用的自动变量是不会被捕获的,甚至在Block结构体中都不会声明它的成员变量 ;

在这里插入图片描述

这里相当于setting方法;
在这里插入图片描述

这个相当于getting方法 ;

总的来说,“截获自动变量”意味着在执行Block语法时,Block表达式所使用的自动变量被保存到Block结构体中去了 ;

__blcok说明符

一般来说,Blcok会截获Block语法中使用过的自动变量,即使在Block外对这些自动变量进行重写,也不会改变Block中已经捕获的值;如果尝试在Block内部进行重写 ,编译器在编译时会自动检测并抛出错误;
这也意味着不便,有什么办法能在Block中直接改写Block中的自动变量呢 ;

这里有两种方法:
1.c语言中有部分变量是允许Block改写值的;

  • 静态变量
  • 全局变量
  • 静态全局变量

具体可以看看两端代码转换前后的对比:
在这里插入图片描述

在这里插入图片描述

这里发现全局变量的使用与c语言中无二,甚至不会有Block的捕获机制;

但静态变量在结构体中是以指针捕获的;至于为什么用指针,这是超出作用域使用变量的最简单方法 ;
那为什么普通的自动变量为什么不采用指针捕获;这是因为静态变量与其他变量之前生命周期的差别 ;

2.使用__block说明符:
和它类似的还有

  • static
  • auto
  • regist
    其中auto表示作为自动变量存储在栈中,static表示作为静态变量存储在数据区中 ;
    只有__block得存储域待会讲;
    先来看看使用__Block的自动变量在Block中的具体实现:
    在这里插入图片描述

在这里插入图片描述

对比之前的,我们发现多了一个__block_byref_val_0结构体,它和block的结构体很像,但多了一个forwarding指针指向自身 ;
看起来就是把val变量转换为一个结构体变量来捕获 ;
在这里插入图片描述

这里结构体的结构可以参考下图:
在这里插入图片描述

当使用Block时:
在这里插入图片描述

这里看起来有点复杂;那为什么有成员变量__forwarding?虽然后面讲,但我猜是通过它来延长自动变量的生命周期之类的 ;

另外要注意一点,__block变量的____block_byref_val_0结构体对象并不在__main_block_impl_0结构体中,__main_block_impl_0结构体中的是它的指针,而对象在主函数中,这样做就可以在多个Block中使用__blcok变量 ;

Block存储域

Block转换为Block的结构体类型的自动变量,__block变量转换为__block变量的结构体类型的自动变量,所谓结构体类型的自动变量,即栈上生成的该结构体的实例 ;
但我们知道,除了栈以外,存储域还有数据区域和堆 ;
所以Block对象的存储域也不仅仅在栈 ;
下面给出Block对象的类和存储域间的关系:
在这里插入图片描述

平时用到的Block对象大多在栈,当

  • 记述全局变量的地方有Block语法时
  • Block语法的表达式中不使用应截获的自动变量时

时,Block为——NSConcreteGlobalBlock类对象;

#import "ViewController.h"
#import <objc/runtime.h>
typedef int(^blk_t)(int);
blk_t glbblk  = ^(int count){return count ;} ;
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
            for (int rate = 0; rate < 10; ++rate) {
                blk_t blk = ^(int count){return count ;} ;
                Class blockClass = object_getClass((__bridge id _Nullable)((__bridge void *)(glbblk)));
                NSLog(@"%@",NSStringFromClass(blockClass)) ;
                printf("%d\n",blk(1)) ;
            }
    
        }
#import "ViewController.h"
#import <objc/runtime.h>
typedef int(^blk_t)(int);
blk_t glbblk  = ^(int count){return count ;} ;
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
            for (int rate = 0; rate < 10; ++rate) {
                blk_t blk = ^(int count){return count ;} ;
                Class blockClass = object_getClass((__bridge id _Nullable)((__bridge void *)(blk)));
                NSLog(@"%@",NSStringFromClass(blockClass)) ;
                printf("%d\n",blk(1)) ;
            }
    
        }

配置在全局变量上的Block,从变量作用域外也可以通过指针安全使用,但设置在栈上的Block,如果其所属的作用域结束,该Block就被废弃;同上,配置在栈上的__block变量也是如此 ;
那么我们在使用中,Block时如何超出变量作用域存在的:
Blocks提供了讲Block和__block变量从栈上复制到堆上的方法 ;这样就能保证Block不被废弃 ;
当Block被复制到堆上时,isa指针也就是类会被赋为_NSConcrete MallocBlock,__block变量也是如此,但它的成员变量forwarding可以同时访问栈上和堆上的__block变量 ;

这个所谓的复制方法,其实就是oc中经常使用的copy,当我们对一个Block对象使用copy时有三种情况:
在这里插入图片描述

不过在提到使用copy方法前,我们要知道,但ARC有效时,大多数情形下编译器都会恰当地进行判断,自动生成讲Block从栈上复制到堆上的代码 ;

除此之外的情形就必须手动复制了,比如像方法或函数的参数中传递Block时;但如果在方法或函数中适当地复制了传递过来的参数,那也不必手动复制了,如:

  • Cocoa框架的方法切方法名中含有usingBlock等时
  • GCD的API

书上讲的必须手动复制的例子:

NSArray* array = [self getBlockArray] ;
    typedef void(^blk01_t)(void);
    blk01_t blk = [array objectAtIndex:0] ;
    blk () ;



- (id) getBlockArray {
    int val = 10 ;
    return [[NSArray alloc] initWithObjects:^{NSLog(@"%d",val);},^{NSLog(@"%d",val);}, nil];
}

但不太清楚的一点是我在实际运行的时候程序不会异常,而是会正常执行;

再回到调用copy方法,我们会发现不管Block配置在何处,用copy方法都不会引起任何问题,在不确定时调用copy方法即可 ;不过将Block从栈上复制到堆上是相当消耗cpu的;

如下:

 blk = [[[[blk copy] copy] copy] copy] ;

多次调用copy方法进行复制在ARC下是没有任何问题的 ;

__block变量存储域

当把使用了__block变量的Block从栈上复制到堆上时,__block
变量也会产生影响:
在这里插入图片描述

当把栈上的Block从栈上复制到堆上时,Block中使用的__block变量也会一并复制到堆上;当该Block已经复制到堆上时,复制Block对__block变量没有任何影响 ;
在这里插入图片描述
当多个Block中使用相同的__block变量时,任何一个Block从栈复制到堆,都会把__block变量也复制到堆上,即使其他Block再复制到堆上,也只会增加__blockde1引用计数;这和oc的内存管理是一样的 ;

在这里插入图片描述

同理,废弃Block也是一样的:
在这里插入图片描述

使用__block变量用结构体成员变量__forwarding的原因

不管__block变量配置在栈上还是在堆上,都能正确地访问变量
即通过Block的复制,__block变量也从栈复制到堆。此时可同时访问栈上的和堆上的__block变量。对于这句话,看

__block int val = 0 ;
    void (^blk) (void) = [^{ ++ val ;} copy] ;
    ++val ;
    blk () ;
    NSLog(@"%d",val) ;

其中Block中的val为复制到堆上的__block变量用结构体实例 ;
而外面的val为栈上的结构体实例 ;

当复制到堆上时,成员变量的forwarding的值替换为目标堆上的__block变量用结构体实例的地址;

所以其实void (^blk) (void) = [^{ ++ val ;} copy] ;
++val ;
这两句都可以转换为:

++ (val.__forwarding->val) ;

在这里插入图片描述

无论是在Block语法中,Block语法外使用__block变量,还是__block变量配置在栈上还是堆上,都可以顺利的访问同一个__block变量 ;

截获对象

书上的例子大概都是基于MRC实现的,不过我在手动管理时也没有成功,所以这部分和内存管理息息相关 ;

typedef void(^blk_t)(id);
    blk_t blk ;
    
    {
        id array = [[NSMutableArray alloc] init] ;
        blk = [^(id obj) {
            [array addObject:obj] ;
            NSLog(@"%ld",[array count] ) ;
        } copy] ;
    }
    
    blk([[NSObject alloc] init]) ;
    blk([[NSObject alloc] init]) ;
    blk([[NSObject alloc] init]) ;

这里的array,当在调用blk时,已经超出了他的作用域,按理来说应该被废弃,但这时发生了截获对象,可能类似于前面截获自动变量的值,但也有些不一样 ;与前者相比,最明显的区别在于:
在这里插入图片描述

因为涉及到了对象,简单的c语言结构体中不能含有__strong修饰的变量 ;但是oc可以通过引用计数进行内存管理 ;
所以在__main_block_desc_0结构体中增加的成员变量copy和dispose以及作为指针赋值给该成员变量的__main_block_copy_0函数(copy函数)和__main_block_dispose_0函数 (dispose函数);

这个时候代入内存管理来看 ;
copy函数使用_Blokc_object-assign函数(相当于retain)将对象类型对象赋值给Block用结构体成员变量array中并持有该对象 ;

dispose函数使用_Block_object_dispose函数(相当于release),释放赋值在Block用结构体成员变量array中的对像 ;

那么这些函数什么时候调用呢:在Block从栈复制到堆时,以及堆上的Block被废弃时会调用 ;
在这里插入图片描述

什么时候栈上的Block会复制到堆:

  • 调用Block的copy实例方法时
  • Block作为函数返回值返回时
  • 将Block赋值给附有__strong修饰符id类型的类或Block类型成员变量时
  • 在方法名中含有usingBlock的Cocoa框架方法或GCD的API中传递Block时 ;

上面的这些情况下,栈上的Block被复制到堆上,但其实可以总结为_Block_copy函数被调用时Block从栈复制到堆上 ;
相对的,在释放复制到堆上的Block后,谁都不持有Block,而使其被废弃时调用dispose函数,这相当于对象的dealloc实例方法 ;

通过这种构造,通过使用附有__strong修饰符的自动变量,Block截获的对象能够超出变量作用域存在 ;也就是引用计数管理 ;

因此,Block中使用对象类型成员变量时,除了一下情形外,推介调用Block的copy实例方法 ;

  • Block作为函数返回值返回时
  • 将Block赋值给附有__strong修饰符id类型的类或Block类型成员变量时
  • 在方法名中含有usingBlock的Cocoa框架方法或GCD的API中传递Block时

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1807360.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

图像处理方向信息

前言 Exif 规范 定义了方向标签&#xff0c;用于指示相机相对于所捕获场景的方向。相机可以使用该标签通过方向传感器自动指示方向&#xff0c;也可以让用户通过菜单开关手动指示方向&#xff0c;而无需实际转换图像数据本身。 在图像处理过程中&#xff0c;若是原图文件包含…

中间件学习-RocketMQ-从零到一学习-2RocketMQ 的工作原理

中间件学习-RocketMQ-从零到一学习-2RocketMQ 的工作原理 RocketMQ 工作原理 1. 启动 NameServer 启动 NameServer。NameServer 启动后监听端口&#xff0c;等待 Broker、Producer、Consumer 连接&#xff0c;相当于一个路由控制中心。 2. 启动 Broker 启动 Broker。与所有…

ansible.cfg forks参数

在Ansible的配置文件ansible.cfg中&#xff0c;forks参数是一个非常关键的设置&#xff0c;它控制了Ansible执行任务时的并发连接数&#xff0c;直接影响到Ansible执行 playbook 或 ad-hoc 命令时的速度和效率。 意义与作用 并发控制&#xff1a;当你使用Ansible来管理多台主…

VRRP基础配置(华为)

#交换设备 VRRP基础配置 VRRP (Virtual Router Redundancy Protocol) 全称是虚拟路由规元余协议&#xff0c;它是一种容错协议。该协议通过把几台路由设备联合组成一台虚拟的路由设备&#xff0c;该虚拟路由器在本地局域网拥有唯一的一个虚拟 ID 和虚拟 IP 地址。实际上&…

计算机毕业设计python+spark知识图谱音乐推荐系统 音乐数据分析可视化大屏 音乐爬虫 LSTM情感分析 大数据毕设 深度学习 机器学习

流程&#xff1a; 1.Python采集网易云音乐歌手、歌词、音乐、评论等约10-20万海量数据&#xff0c;存入mysql数据库&#xff1b; 2.使用pandasnumpy/MapReduce对mysql中四类数据进行数据清洗&#xff0c;写入.csv文件并上传至hdfs(含评论NLP文本分类/lsm情感分析); 3.使用hive建…

LVGL移植和图片显示

最近闲来无事&#xff0c;偶尔刷到了移植LVGL的教程&#xff0c;今天肝完了机械原理又移植完LVGL库&#xff0c;真是收获满满的一天&#xff0c;先接一杯水去。 回来了&#xff0c;发个朋友圈高级一下&#xff0c;好困。 lvgl v8.3移植及组件使用_lvgl界面编辑器-CSDN博客htt…

nlp学习笔记

目录 很多入门例子 bert chinese 很多入门例子 https://github.com/lansinuote/Huggingface_Toturials bert chinese import torch import torch.nn as nn from transformers import AutoTokenizer, AutoModel, BertModel, TFBertModel, BertTokenizer# youpath = D:/bert-…

任务调度选择之PowerJob 和 Snail Job

背景 最近在选择一款任务调度产品&#xff0c;找了几款产品进行调研&#xff0c;我对产品的要求是可以进行可视化、有角色权限、任务编排、支持http、接入成本低等&#xff0c;发现有有两款挺符合的PowerJob和Snail Job。 同类产品对比 Elastic-Jobxxl-jobPowerJobSnail Job…

c#自定义ORM框架-实体类扩展属性

步骤一、建立扩展属性类 实体类扩展属性要继承Attribute基类完成 步骤二、创建实体类并引用扩展实体类属性 Attributes属性定义&#xff0c;主要标明表名和主键名字 /// <summary> /// 表名 /// </summary> [AttributeUsage(AttributeTargets.Class)] [System.S…

C语言之存储类、作用域、生命周期、链接属性

一 &#xff1a;概念解析 1&#xff1a; 存储类 &#xff08;1&#xff09;存储类就是存储类型&#xff0c;就是描述C语言变量存储在什么地方 &#xff08;2&#xff09;内存有多种管理方法&#xff1a;栈、堆数据段、bss段、.text段......一个变量的存储类属性就是描述…

Objective-C之通过协议提供匿名对象

概述 通过协议提供匿名对象的设计模式&#xff0c;遵循了面向对象设计的多项重要原则&#xff1a; 接口隔离原则&#xff1a;通过定义细粒度的协议来避免实现庞大的接口。依赖倒置原则&#xff1a;高层模块依赖于抽象协议&#xff0c;而不是具体实现。里氏替换原则&#xff1…

计算机毕业设计 | SpringBoot+vue的教务管理系统

1&#xff0c;绪论 1.1 项目背景 在这个资讯高度发展的时代&#xff0c;资讯管理变革已经是一个更为宽泛、更为全面的潮流。为了保证中国的可持续发展&#xff0c;随着信息化技术的不断进步&#xff0c;教务管理体系也在不断完善。与此同时&#xff0c;伴随着信息化的飞速发展…

Golang-分离式加载器(传参)AES加密

目录 enc.go 生成: dec.go --执行dec.go...--上线 cs生成个c语言的shellcode. enc.go go run .\enc.go shellcode 生成: --key为公钥. --code为AES加密后的数据, ----此脚本每次运行key和code都会变化. package mainimport ("bytes""crypto/aes"&…

好书推荐之《生成式 AI 入门与亚马逊云科技AWS实战》

最近小李哥在亚马逊云科技峰会领到了一本关于如何在云计算平台上设计、开发GenAI应用的书&#xff0c;名字叫&#xff1a;《生成式 AI 入门与亚马逊云科技AWS实战》&#xff0c;今天仔细看了下&#xff0c;发现这本书讲的真的很好&#xff01;他涵盖了当下AI领域所有热门的技术…

《精通ChatGPT:从入门到大师的Prompt指南》第11章:Prompt与AI的未来

第11章&#xff1a;Prompt与AI的未来 11.1 技术发展的新方向 在迅速发展的人工智能领域&#xff0c;Prompt工程作为与AI模型交互的核心方式&#xff0c;正处于技术创新的前沿。未来几年&#xff0c;Prompt工程将沿着多个新方向发展&#xff0c;这些方向不仅会改变我们与AI互动…

Android平台RTMP推送|轻量级RTSP服务|GB28181接入之文字、png图片水印的精进之路

技术背景 Android平台推流模块&#xff0c;添加文字或png水印&#xff0c;不是一件稀奇的事儿&#xff0c;常规的做法也非常多&#xff0c;本文&#xff0c;我们主要是以大牛直播SDK水印迭代&#xff0c;谈谈音视频行业的精进和工匠精神。 第一代&#xff1a;不可动态改变的文…

[ROS 系列学习教程] 建模与仿真 - ros_control 介绍

ROS 系列学习教程(总目录) 本文目录 一、ros_control 架构1.1 hardware_interface1.2 combined_robot_hw1.3 controller_interface1.4 controller_manager1.5 controller_manager_msgs1.6 joint_limits_interface1.7 transmission_interface1.8 realtime_tools 二、ros_control…

LLVM Cpu0 新后端9 objdump readelf

想好好熟悉一下llvm开发一个新后端都要干什么&#xff0c;于是参考了老师的系列文章&#xff1a; LLVM 后端实践笔记 代码在这里&#xff08;还没来得及准备&#xff0c;先用网盘暂存一下&#xff09;&#xff1a; 链接: https://pan.baidu.com/s/1yLAtXs9XwtyEzYSlDCSlqw?…

Android——热点开关(优化中)

SoftAP打开与关闭 目录 1.三个名词的解释以及关系 Tethering——网络共享&#xff0c;WiFi热点、蓝牙、USB SoftAp——热点(无线接入点)&#xff0c;临时接入点 Hostapd——Hostapd是用于Linux系统的软件&#xff0c;&#xff0c;支持多种无线认证和加密协议&#xff0c;将任…

AI大模型在健康睡眠监测中的深度融合与实践案例

文章目录 1. 应用方案2. 技术实现2.1 数据采集与预处理2.2 构建与训练模型2.3 个性化建议生成 3. 优化策略4. 应用示例&#xff1a;多模态数据融合与实时监测4.1 数据采集4.2 实时监测与反馈 5. 深入分析模型选择和优化5.1 LSTM模型的优势和优化策略5.2 CNN模型的优势和优化策略…