【Effective Objective - C】—— 系统框架

news2024/12/23 22:26:41

【Effective Objective - C】—— 系统框架

  • 47.熟悉系统框架
    • CoreFoundation框架
    • 其他框架
    • 要点
  • 48. 多用块枚举,少用for循环
    • for循环
    • 使用Objective-C 1.0的NSEnumerator遍历
    • 快速遍历
    • 基于块的遍历方式
    • 要点
  • 49.对自定义其内存管理语义的collection使用无缝桥接
    • 要点
  • 50.构建缓存时选用NSCache而非NSDictionary
    • NSCache
    • NSCache实例
    • 要点
  • 51.精简initialize与load的实现代码
    • load方法:
    • initialize方法:
      • 与load的区别:
      • initalize方法尽量精简
    • 要点
  • 第52条:别忘了NSTimer会保留其目标对象
    • 要点

47.熟悉系统框架

OC的Foundation框架,像NSObject NSArray, NSDictionary等类都在其中。Foundation框架里的类都是用NS前缀,因为OC之前作为NeXTSTEP操作系统确定的。

将一系列代码封装为动态库,并在其中放入描述其接口的头文件,这样做出来的东西就叫框架。

CoreFoundation框架

与Foundation相伴的框架,叫做CoreFoundation框架,虽然从技术上讲它不是OC框架,但是它却是编写OC应用程序时所应熟悉的重要框架。他其中的很多类都和Foundation框架相似,并且我们还可以通过 “无缝桥接”,功能实现CoreFoundation框架中的C语言数据结构平滑转换为Foundation框架中的OC对象,也可以反向转换。无缝桥接技术是用某些相当复杂的代码实现出来的,这些代码可以使运行期系统把CoreFoundation框架中的对象视为普通的OC对象。

NSString所对应的就是CFString对象。

其他框架

系统库介绍
CFNetwork提供C语言级别的网络通信能力,将“BDS套接字”抽象成为易于使用的网络接口。Foundation将该框架中的部分内容封装为Objective-C语言的接口,以便进行网络通信
CoreAudio提供的C语言API可以用来操作设备上的音频硬件。这个框架比较难用。这套API可以抽象出另一套Objective-C式API
AVFoundation提供的Objective-C对象可以用来回放并录制音频及视频
CoreData提供的Objective-C接口可以将对象放入数据库,便于持久保存。Coredata会处理数据的获取及存储等事宜,可以跨Mac OS X及iOS平台
CoreText提供的C语言接口可以高效的执行文字排版及渲染操作
CoreAnimation是用OC语言写成的,它提供了一些工具,而UI框架则用这些工具来渲染图形并播放动画。但是它本身并不是框架,它只是QuartzCore框架的一部分。
CoreGraphics框架以C语言写成,其中提供了2D渲染所必备的数据结构与函数,例如:CGPoint、CGSize、CGRect等等。
MapKit可以为iOS程序提供地图功能。
Social为Mac OS X及iOS程序提供了社交网络功能。

OC编程的重要特点就是:经常需要使用底层的C语言级 API。 用c语言实现 APTI的好处是,可以统过 Objeotive-C 的运行期系统,从而提升执行速度

要点

  • 许多系统框架都可以直接使用。其中最重要的是Foundation与CoreFoundation,这两个框架提供了构建应用程序所需的许多核心功能。
  • 很多常见任务都能用框架来做,例如音频与视频处理、网络通信、数据管理等。
  • 请记住:用纯C写成的框架与用OC写成的一样重要,若想成为优秀的OC开发者,应该掌握C语言的核心概念。

48. 多用块枚举,少用for循环

在OC里,列举collection中的元素可以使用C语言的for循环,还可以使用快速遍历。当学习了block块特性的时候,又提供了多种遍历collection的方式,可以传入块。

for循环

便利数组的第一种方法就是采用老式的for循环。这是一个很基本的方法,功能非常有限。

NSArray* array = [NSArray arrayWithObjects:@"111", @"222", @"333" ,nil];
    for (int i = 0; i < array.count; i++){
        NSLog(@"%@", array[i]);
    }

但是对于集合和字典,集合和字典是无序的,要将他们转化为数组才可以进行for循环遍历。

NSDictionary* dictionary = [NSDictionary dictionaryWithObjects:@[@"111", @"222", @"333", ] forKeys:@[@"1", @"2", @"3"]];
    NSArray* keys = [dictionary allKeys];
    for (int i = 0; i < keys.count; i++){
        NSLog(@"%@", dictionary[keys[i]]);
        
    }

NSSet* set = [[NSSet alloc] initWithObjects:@"111", @"222", @"333", nil];
    NSArray* array = [set allObjects];
    for (int i = 0; i  < set.count; i++){
        NSLog(@"%@", array[i]);
    }

使用Objective-C 1.0的NSEnumerator遍历

NSEnumerator是一个抽象基类。方法nextObject返回枚举里的下一个对象。每次调用此方法时, 内部数据都会更新,使得下次调用方法时能返回下一个对象。

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        NSArray* array = [NSArray arrayWithObjects:@"111", @"222", @"333" ,nil];
        NSEnumerator* enumerator = [array objectEnumerator];
        id object;
        while ((object = [enumerator nextObject] )!= nil) {
            NSLog(@"%@", object);
        }
    }
    return 0;
}

遍历字典的方式和数组和set不太一样,先根据给定的键把对应的值提取出来。

NSDictionary* dictionary = [NSDictionary dictionaryWithObjects:@[@"111", @"222", @"333", ] forKeys:@[@"1", @"2", @"3"]];
        NSEnumerator* enumerator = [dictionary keyEnumerator];
        id key;
        while (( key = [enumerator nextObject]) != nil) {
            id value = dictionary[key];
            NSLog(@"%@", value);
        }
NSSet* set = [[NSSet alloc] initWithObjects:@"111", @"222", @"333", nil];
    NSEnumerator* enmuator = [set objectEnumerator];
    id object;
    while ((object = [enmuator nextObject]) != nil) {
        NSLog(@"%@", object);
    }

使用NSEnumerator还有一个好处,就是有多种“枚举器”可供使用。反向遍历数组所用的枚举器,如果用它来遍历,就可以按反方向来迭代collection中的元素了。

NSArray* array = [NSArray arrayWithObjects:@"111", @"222", @"333" ,nil];
    NSEnumerator* enumerator = [array reverseObjectEnumerator];
    id object;
    while ((object = [enumerator nextObject]) != nil) {
        NSLog(@"%@", object);

    }

快速遍历

快速遍历是OC2.0引入的语法功能,引入了in关键字,语法更加简洁了collection的遍历过程。尤其是字典类

NSArray* array = [NSArray arrayWithObjects:@"111", @"222", @"333" ,nil];
    for (id object in array) {
        NSLog(@"%@", object);
    }

如果某个类的对象支持快速遍历,那么就可以说自己遵从名为NSFastEnumerator的协议,令开发者可以采用此语法来迭代该对象。

NSDictionary* dictionary = [NSDictionary dictionaryWithObjects:@[@"111", @"222", @"333", ] forKeys:@[@"1", @"2", @"3"]];
    for (id key in dictionary) {
        id value = dictionary[key];
        NSLog(@"%@", value);
    }

//这里采用的是倒序枚举的快速遍历
NSArray* array = [NSArray arrayWithObjects:@"111", @"222", @"333" ,nil];
    for (id object in [array reverseObjectEnumerator]) {
        NSLog(@"%@", object);
    }

基于块的遍历方式

对于块的引入,数组字典和集合都有自己的块遍历方法。

[array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

参数1是每次枚举的对象, idx是下标, stop则是代表是否停止遍历.
obj = array[idx];

//块枚举
NSArray* array = @[@"111", @"222", @"333", @"444", @"555", @"666"];
 __block NSInteger x = 2;
[array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
     if (x < 4) {
         x++;
         NSLog(@"%@", obj);
         // 等效
         NSLog(@"%@", array[idx]);
         *stop = NO;
     } else {
         *stop = YES;
         NSLog(@"x == 4 STOP");
     }
 }];

在这里插入图片描述
字典和集合是一样的思路。
遍历时可以直接从块里获取更多信息,并且它能够修改块的方法签名,以免进行类型转换操作。

要点

  • 遍历collection有四种方式。最基本的办法是for循环,其次是NSEnumerator遍历法及快速遍历法,最新、最先进的方式则是“块枚举法”。
  • “块枚举法”本身就能通过GCD来并发执行遍历操作,无须另行编写代码。而采用其他遍历方式则无法轻易实现这一点。
  • 若提前知道待遍历的collection含有何种对象,则应修改块签名,指出对象的具体类型。

49.对自定义其内存管理语义的collection使用无缝桥接

“无缝桥接”技术其实就是不同库之间相同类型的相互转换。
使用“无缝桥接”技术,可以在定义于Foundation框架中的OC类和定义于CoreFoundation框架中的C数据结构之间互相转换。

NSArray* array = @[@"111", @"222", @"333", @"444", @"555", @"666"];
        CFArrayRef aCFArray = (__bridge  CFArrayRef)array;
        NSLog(@"cfArratSize =  %li", CFArrayGetCount(aCFArray));
        NSLog(@"%@", aCFArray);
        CFRelease(aCFArray);

转换操作中的__bridge告诉ARC如何处理转换所涉及的OC对象。__bridge本身的意思是:ARC仍然具备这个OC对象的所有权。而__bridge_retained则与之相反,意味着ARC将交出对象的所有权。与之相似,反向转换可通过__bridge_transfer来实现,也就是将对象的所有权交给ARC。这三种转换方式称为“桥式转换”。

需要加上CFRelease()释放内存。

要点

  • 通过无缝桥接技术,可以在Foundation框架中的OC对象与CoreFoundation框架中的C语言数据结构之间来回转换。
  • 在CoreFoundation层面创建collection时,可以指定许多回调函数,这些函数表示此collection应如何处理其元素。然后,可运用无缝桥接技术,将其转换成具备特殊内存管理语义的OC collection。

50.构建缓存时选用NSCache而非NSDictionary

就目前的知识而言,对于从网上下载的图片如何缓存,我会把图片全部放到字典里,使用的时候就无需再次下载了,OC提供了一个NSCache类更好的方便缓存。

NSCache

NSCache类的优势在于当系统资源即将耗尽的时候自动删减缓存,这是字典类不能做到的。并且遵循先删减最久未使用的对象。

NSCache并非拷贝键而是保留键。NSCache对象不拷贝键的原因在于:很多时候,键都是由不支持拷贝操作的对象来充当的。 这和字典完全不同,并且NSCache是线程安全的,它在开发者不自己编写安全锁的情况下多个线程可以同时访问NSCache,这对于缓存来说是很重要的,多线程完成这个任务更加方便。

NSCache可以令开发者操控缓存删减其内容的时机,可以调整缓存里的对象总数和对象的总开销,就是在讲对象加入缓存的时候开发者可以知道开销值,对象总数或总开销超过上限,缓存就会自动删减不需要的对象,当然这个删减不能确定会不会删减掉某个必要的对象,所以把对象转换成NSData对象之后把数据大小当作缓存值更合适这样避免了复杂的计算开销值,变成了读取数据大小的步骤

NSCache实例

书上提供了实用NSCache的例子,并引入其他的知识。
在这里插入图片描述
在这里插入图片描述
在本例中,下载数据所用的URL,就是缓存的键。若缓存未命中,即缓存中没有访问者所需的数据,则下载数据并将其放入缓存。而数据的“开销值”则设为其长度。

存在一个类叫做NSPurgeableData和NSCache搭配起来用,它是NSMutableData的子类,而且实现了NSDiscardableContent协议。如果某个对象所占的内存能够根据需要随时丢弃,那么就可以实现该协议所定义的接口。这就是说,当系统资源紧张时,可以把保存NSPurgeableData对象的那块内存释放掉。NSDiscardableContent协议里定义了名为isContentDiscarded的方法,用来查询相关内存是否释放。

如果需要访问某个NSPurgeableData对象,可以调用其beginContentAccess方法,告诉它现在还不应丢弃自己所占据的内存。用完之后,调用endContentAccess方法,告诉它在必要时可以丢弃自己所占据的内存了。这些调用可以嵌套,类似于对象的引用计数机制,为0就告诉系统可以销毁对象了

将NSPurgeableData对象加入NSCache,那么当该对象为系统所丢弃时,也会自动从缓存中清除。通过NSCache的evictsObjectsWithDiscardedContent属性,选择开启或者关闭此功能。

要点

  • 实现缓存时应选用NSCache而非NSDictionary对象。因为NSCache可以提供优雅的自动删减功能,而且是“线程安全的”,此外,它与字典不同,并不会拷贝键。
  • 可以给NSCache对象设置上限,用以限制缓存中的对象总个数及“总成本”,而这些尺度则定义了缓存删减其中对象的时机。但是绝对不要把这些尺度当成可靠的“硬限制”,它们仅对NSCache起指导作用。
  • 将NSPurgeableData与NSCache搭配使用,可实现自动清除数据的功能,也就是说,当NSPurgeableData对象所内存为系统所丢弃时,该对象自身也会从缓存中移除。
  • 如果缓存使用得当,那么应用程序的响应速度就能提高。只有那种“重新计算起来很费事的”数据,才值得放入缓存,比如那些需要从网络获取或从磁盘读取的数据。

51.精简initialize与load的实现代码

有时候,类必须先执行某些初始化操作,然后才能正常使用。在OC中,绝大多数的类都继承自NSObject这个根类,而该类有两个办法,可用来实现这种初始化操作。

load方法:

首先是load方法,其原型如下:

+ (void)load;

加入运行期系统中的每个类和分类来说,会调用此方且仅调用一次,当类和分类的程序载入系统的时候就会执行这个方法,调用顺序是类大于分类。
load方法执行的时候运行期系统处于脆弱状态,在执行子类的load方法之前必须执行所有超类的load方法,其中还会执行代码涉及到的库的load,导致在load方法里面使用其他类不安全。
在这里插入图片描述
在B类里调用A类,无法保证A类已经加载完成,也就是只有A的load方法执行完成才能完整的使用A类。

并且在load方法里调用的类若之前没有加载好,那么再调用程序就会崩溃了,注意:程序在执行load方法时会阻塞系统,并且每个类都只能执行自己的load,不会执行超类的load的。

总的来说,load方法里代码要写的精简,能少写就少写,能不用就不用。

initialize方法:

想执行与类相关的初始化操作,还有个办法,就是覆写下列方法:

+ (void)initialize;

对于每个类来说,该方法会在程序首次用该类之前调用,且只调用一次。它是由运行期系统来调用的,绝不应该通过代码直接调用。

与load的区别:

  • 它是“惰性调用的”,也就是说,只有当程序用到了相关的类时,才会调用。
  • 其次运行期在执行该方法的时候是系统正常状态,也就是安全状态,不影响调用类的其他方法,此为线程安全。
  • 当某个类没实现initialize方法,超类实现后会调用超类的方法,和大多数消息是一样的。

initalize方法尽量精简

  • 大家都不想看到自己的应用程序“挂起”,若写的太过繁琐,导致其运行很慢那就适得其反了。
  • 开发者无法控制类的初始化时机。
  • 如果某个类的实现代码很复杂,那么其中可能会直接或间接用到其他类。若那些类尚未初始化,则系统会迫使其初始化。然而,本类的初始化方法此时尚未运行完毕。其他类在运行其initialize方法时,有可能会依赖本类中的某些数据,而这些数据此时也许还未初始化好,就会造成依赖环

所以说,initialize方法只应该用来设置内部数据。不应该在其中调用其他方法,即便是本类自己的方法,也最好别调用。若某个全局状态无法在编译期初始化,则可以放在initialize里来做。
在这里插入图片描述
注意,某些OC对象也可以在编译期创建,例如NSString实例。

编写load或initialize方法时,一定要留心这些注意事项。把代码实现的简单一些,能节省很多调试时间。除了初始化全局状态之外,如果还有其他事情要做,那么可以专门创建一个方法来执行这些操作,并要求该类的使用者必须在使用本类之前调用此方法。

要点

  • 在加载阶段,如果类实现了load方法,那么系统就会调用它。分类里也可以定义此方法,类的load方法要比分类中的先调用。与其他方法不同,load方法不参与覆写机制。
  • 首次使用某个类之前,系统会向其发送initialize消息。由于此方法遵从普通的覆写规则,所以通常应该在里面判断当前要初始化的是那个类。
  • load与initialize方法都应该实现的精简一些,这有助于保持应用程序的响应能力,也能减少引入“依赖环”的几率。
  • 无法在编译期设定的全局常量,可以放在initialize方法里初始化。

第52条:别忘了NSTimer会保留其目标对象

Foundation框架中有个类叫NSTimer,开发者可以指定绝对的日期与时间,以便到时执行任务,**计时器要和“运行循环(run loop)”相关联,**运行循环到时候会触发任务。创建NSTimer时,可以将其“预先安排”在当前的运行循环中,也可以先创建好,然后由开发者自己来调度。无论采用哪种方式,只有把计时器放在运行环里,它才能正常触发任务。

创建定时器

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimerInterval)seconds target:(id)target selector:(SEL)selector userInfo:(id)userInfo repeats:(BOOL)repeats;

用此方法创建出来的计时器,会在指定的间隔时间之后执行任务。也可以令其反复执行任务,知道开发者稍后将其手动关闭为止。
target与selector参数表示计时器将在哪个对象上调用哪个方法。计时器会保留其目标对象,等到自身“失效”时再释放此对象。 调用invalidate方法可令计时器失效;执行完相关任务之后,一次性的计时器也会失效。开发者若将计时器设置成重复执行模式,那么必须自己调用invalidate方法,才能令其停止。

由于计时器会保留其目标对象,所以反复执行任务通常会导致应用程序出现保留环。
就像下面这样:
在这里插入图片描述
创建计时器的时候,由于目标对象是self,所以要保留此实例。然而,因为计时器是用实例变量存放的,所以实例也保留了计时器,于是,就产生了保留环。所以说,那么调用stopPolling,要么令系统将此实例回收,只有这样才能打破保留环。

因为是类和这个类中的实例出现了保留环,不管你外界怎么对这个类释放,这个计时器始终都会保留这个类,而这个类也会保留这个计时器,他们的保留计数永远都不会降为0。
在这里插入图片描述
如果从外界直接先调用stop方法,代码没办法自己检测。

使用块的特点打破保留环
使用块和weak关键字合理的打破保留环,块可以传递代码,这一功能可以利用
在这里插入图片描述
在这里插入图片描述
这段代码将计时器所应执行的任务封装成“块”,在调用计时器函数上,把它作为userInfo参数传进去。该参数可用来存放“不透明值”(即万能值),只要计时器还有效,就会一直保留着它。传入参数时要通过copy方法将block拷贝到“堆”上,否则等到稍后要执行它的时候,该块可能已经无效了。计时器现在的target是NSTimer类对象,这是个单例,因此计时器是否会保留它,其实都无所谓。此处依然有保留环,然而因为类对象无须回收,所以不用担心。

新改写的代码这样调用:
在这里插入图片描述
但是其实它还是有保留环的,因为块捕获了self变量,所以块要保留实例。而计时器又通过userInfo参数保留了块。 最后,实例本身还是要保留计时器。不过,只要改用weak引用,即可打破保留环。
在这里插入图片描述
这段代码采用了一种很有效的写法,他先定义了一个弱引用,令其指向self,然后使块捕获这个引用,而不直接去捕获普通的self变量。也就是说,self不会为计时器所保留。当块开始执行时,立刻生成strong引用,以保证实例在执行期间持续存活。

要点

  • NSTimer对象会保留其目标,直到计时器本身失效为止,调用invalidate方法可令计时器失效,另外,一次性的计时器在触发完成任务之后也会失效。
  • 反复执行任务的计时器,很容易引人保留环,如果这种计时器的目标对象又保留了计时器本身,那肯定会导致保留环。这种环状保留关系,可能是直接发生的,也可能是通过对象图里的其他对象间接发生的。
  • 可以扩充NSTimer的功能,用“块” 来打破保留环。 不过,除非NSTimer将来在公共接口里提供此功能,否则必须创建分类,将相关实现代码加入其中。

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

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

相关文章

利用MATLAB/Simulink仿真模型加速嵌入式控制系统的开发——以多学科融合的电机控制为例

电机控制涵盖了广泛的应用领域&#xff0c;从家用电器到工业设备&#xff0c;从电动汽车到航空航天&#xff0c;其重要性不言而喻。从过去到现在&#xff0c;再到未来&#xff0c;电机控制技术的发展经历了显著的变革&#xff0c;并持续推动着相关行业的进步。 一、电机控制的…

pip镜像源:清华镜像、阿里云镜像、豆瓣镜像与如何修改默认镜像源

pip镜像源&#xff1a;清华镜像、阿里云镜像、豆瓣镜像与如何修改默认镜像源 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;【Matplotlib之旅&#xff1a;零基础精通数据可视化】 &#x1f3c6;&#x1f3c6;关注博主&#xff0c;随时获取…

git clone 克隆代码报错

在拉取代码的时候报这个错误&#xff0c;也看了一下地址是正确的的&#xff0c;网络也正常。然后ping gitlab.com执行也没问题&#xff0c;如果有问题就是是环境问题。我以为是git名字和邮箱没有绑定的原因&#xff0c;结果绑定了还是这个问题&#xff0c;这个时候就只好百度啦…

OpenAI划时代大模型——文本生成视频模型Sora作品欣赏(六)

Sora介绍 Sora是一个能以文本描述生成视频的人工智能模型&#xff0c;由美国人工智能研究机构OpenAI开发。 Sora这一名称源于日文“空”&#xff08;そら sora&#xff09;&#xff0c;即天空之意&#xff0c;以示其无限的创造潜力。其背后的技术是在OpenAI的文本到图像生成模…

数据结构---字典树(Tire)

字典树是一种能够快速插入和查询字符串的多叉树结构&#xff0c;节点的编号各不相同&#xff0c;根节点编号为0 Trie树&#xff0c;即字典树&#xff0c;又称单词查找树或键树&#xff0c;是一种树形结构&#xff0c;是一种哈希树的变种。 核心思想也是通过空间来换取时间上的…

Elastic Stack--01--简介

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 Elastic Stack 简介为什么要学习ESDB-Engines搜索引擎类数据库排名常年霸榜![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/051342a83f574c8c910cda522…

YOLOv8改进 | 进阶实战篇 | 利用辅助超推理算法SAHI推理让小目标无所谓遁形(支持视频和图片)

欢迎大家订阅我的专栏一起学习YOLO! 一、本文介绍 本文给大家带来的是进阶实战篇,利用辅助超推理算法SAHI进行推理,同时官方提供的版本中支持视频,我将其进行改造后不仅支持视频同时支持图片的推理方式,SAHI主要的推理场景是针对于小目标检测(检测物体较大的不适用,…

WMS仓储管理系统解决方案如何释放智能仓库的潜力

随着科技的不断进步与创新&#xff0c;智能化仓储设备正逐渐成为企业转型升级的必备利器。越来越多的企业纷纷投入巨资&#xff0c;打造智能仓库&#xff0c;以应对激烈的市场竞争。与传统仓库相比&#xff0c;智能仓库凭借其高效、准确、自动化的特点&#xff0c;成为了企业提…

在springboot项目中调用openai API及我遇到的问题

这两天我在自己的网站中集成了openai API&#xff0c;引入chatgpt对话机器人&#xff0c;中途遇到了很多坑&#xff0c;记录一下。文章中会涉及一些付费工具&#xff0c;如果你有类似功能的工具&#xff0c;完全可以使用自己的。&#xff08;主要是我想澄清一下&#xff0c;我不…

LPDDR6与LPDDR5 ZQ Calibration技术探讨

LPDDR6相比LPDDR5在ZQ校准这一块删除了command-based相关的描述&#xff0c;删除了ZQ校准模式切换的描述&#xff0c;仅支持background-based的校准。 回顾一下LPDDR5 基于background-based的校准&#xff1a; background ZQC是通过MR28 OP[5]来选择的&#xff0c;当选择为0&a…

一个基于C#开发的、开源的特殊字符输入法

emoji表情在社交网络非常流行&#xff0c;我们在手机也非常方便输入&#xff0c;但是在PC电脑我们一般需要到归集好的网页拷贝&#xff0c;所以今天推荐一个Windows小工具&#xff0c;让你方便输入特殊字符和emoji表情。 01 项目简介 这是一个基于C#开发的开源项目&#xff0…

解锁动态体验:探秘文件二维码生成的多重魅力

文件生成二维码&#xff0c;作为一种动态二维码&#xff0c;不仅能够存储丰富的信息&#xff0c;更通过其独特的特点为用户带来了全新的使用体验。让我们一起深入探讨这一引人注目的技术。 1. 数据追踪&#xff1a;揭示用户互动的面纱 在二维彩虹的文件二维码中&#xff0c;数…

使用 Next.js 连接 mysql 数据库

前言 本文主要为大家介绍&#xff0c;如何使用 Next 框架实现一个简单的后端接口&#xff0c;并且从数据库中请求数据返回给前端。 实现 创建api/getData文件夹 项目创建完成后在 app 文件下新建api文件夹&#xff0c;在 api 文件夹下新建 getData 文件夹&#xff0c;在 ge…

聊一聊bpmn-js中的Viewer和Modeler

通过之前对于bpmn-js的学习,可以完成一个基础的Bpmn编辑器(或者叫建模器)的显示和简单绘制,若需要做更多工作还需加强对其的内部实现的了解。通过使用我们可以知道bpmn-js中有两个比较重要的操作对象:bpmnViewer和bpmnModeler。 Viewer:一般习惯性对齐命名对象称之为bpmnVi…

golang入门介绍-1

今天开始发布关于go语言入门到实战内容&#xff0c;各位小伙伴准备好。 go介绍 Go语言&#xff08;或 Golang&#xff09;起源于 2007 年&#xff0c;并在 2009 年正式对外发布。是由 Google 公司开发的一种静态强类型、编译型、并发型、并具有垃圾回收功能的编程语言。 Go 是…

在哪些领域中最需要使用 OCR 识别技术?真实场景介绍

根据我们的项目经验总结来说&#xff0c;OCR&#xff08;光学字符识别&#xff09;技术在多个领域中扮演着至关重要的角色&#xff0c;它能够将图像中的文本内容转换为机器可读的格式&#xff0c;极大地提高了数据处理的效率和准确性。以下是一些主要领域及其对应的应用场景和用…

phar反序列化原理及利用

phar是什么&#xff1f; phar 是 PHP 的一种归档文件格式&#xff0c;类似于 ZIP 或 TAR 文件&#xff0c;它可以包含多个文件和目录&#xff0c;并且可以像访问普通文件系统一样在 PHP 中进行访问。在php 5.3 或更高版本中默认开启 在php.ini中配置如下时&#xff0c;才能生成…

LabVIEW压电驱动迟滞补偿控制

LabVIEW压电驱动迟滞补偿控制 随着精密控制技术的迅速发展&#xff0c;压电陶瓷驱动器因其高精度和快速响应特性&#xff0c;在微纳精密定位系统中得到了广泛应用。然而&#xff0c;压电材料固有的迟滞非线性特性严重影响了其定位精度和重复性。开发了一种基于LabVIEWFPGA的压…

【初始RabbitMQ】死信队列的实现

死信的概念 死信&#xff0c;顾名思义就是无法被消费的消息&#xff0c;字面意思可以这样理解&#xff0c;一般来说&#xff0c;producer 将消息投递到 broker 或者直接到 queue 里了&#xff0c;consumer 从 queue 取出消息 进行消费&#xff0c;但某些时候由于特定的原因导致…

Java 那些诗一般的 数据类型 (1)

本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人…