【iOS】iOS持久化

news2024/12/28 20:27:42

1 持久化目的

  1. 快速展示,提升体验
    • 已经加载过的数据,用户下次查看时,不需要再次从网络(磁盘)加载,直接展示给用户
  2. 节省用户流量(节省服务器资源)
    • 对于较大的资源数据进行缓存,下次展示无需下载消耗流量
    • 同时降低了服务器的访问次数,节约服务器资源。(图片)
  3. 离线使用。
    • 用户浏览过的数据无需联网,可以再次查看。
    • 部分功能使用解除对网络的依赖。(百度离线地图、图书阅读器)
    • 无网络时,允许用户进行操作,等到下次联网时同步到服务端。
  4. 记录用户操作
    • 草稿:对于用户需要花费较大成本进行的操作,对用户的每个步骤进行缓存,用户中断操作后,下次用户操作时直接继续上次的操作。
    • 已读内容标记缓存,帮助用户识别哪些已读。
    • 搜索记录缓存

2 数据持久化方式分类

2.1 内存缓存

  • 定义
    对于使用频率比较高的数据,从网络或者磁盘加载数据到内存以后,使用后并不马上销毁,下次使用时直接从内存加载。
  • 案例
    iOS系统图片加载——[UIImage imageNamed:@"imageName"]
    网络图片加载三方库:SDWebImage
  • 实现
    实现内存缓存的技术手段包括苹果官方提供的NSURLCacheNSCache,还有性能和API上比较有优势的开源缓存库YYCachePINCache等。

2.2 磁盘缓存

  • 定义
    将从网络加载的、用户操作产生的数据写入到磁盘,用户下次查看、继续操作时,直接从磁盘加载使用。
  • 案例
    用户输入内容草稿缓存(如:评论、文本编辑)
    网络图片加载三方库:SDWebImage
    搜索历史缓存
  • 实现
    1. NSUserDefault
      适合小规模数据,弱业务相关数据的缓存。
    2. keychain
      Keychain是苹果提供的带有可逆加密的存储机制,普遍用在各种存用户名、密码的需求上。另外,Keychain是系统级存储,还可以被iCloud同步,即使App被删除,Keychain数据依然保留,用户下次安装App,可以直接读取,通常会用来存储用户唯一标识串。所以需要加密、同步iCloud的敏感小数据,一般使用Keychain存取。
    3. 文件存储
      • Plist:一般结构化的数据可以Plist的方式去持久化
      • archiveArchive方式可以存取遵循协议的数据,比较方便的是存取使用的都是对象,不过中间的序列化和反序列化需要花费一定的性能,可以在想要使用对象直接进行磁盘存取时使用。
      • Stream:指文件存储,一般用来存图片、视频文件等数据
    4. 数据库存储
      数据库适合存取一些关系型的数据;可以在有大量的条件查询排序类需求时使用。
      • Core Data:苹果官方封装的ORM(Object Relational Mapping)
      • FMDBgithub最受欢迎的iOS sqlite 封装开源库之一
      • WCDB:微信团队在自己使用的sqlite封装基础上的开源实现,具有ORM(Object Relational Mapping)的特性,支持iOSAndroid
      • Realm:由Y Combinator孵化的创业团队开源出来的一款跨平台(iOSAndroid)移动数据库。

2.3 应该用哪种缓存方案

根据需求选择:

  • 简单数据存储直接写文件、key-value存取即可。
  • 需要按照一些条件查找、排序等需求的,可以使用sqlite等关系型存储方式。
  • 不希望App删除后清除的小容量数据(用户名、密码、token)存keychain。

3 沙盒机制介绍

iOS中的沙盒机制是一种安全体系。为了保证系统安全,iOS每个应用程序在安装时,会创建属于自己的沙盒文件(存储空间)。应用程序只能访问自身的沙盒文件,不能访问其他应用程序的沙盒文件,当应用程序需要向外部请求或接收数据时,都需要经过权限认证,否则,无法获取到数据。所有的非代码文件都要保存在此,例如属性文件plist、文本文件、图像、图标、媒体资源等,其原理是通过重定向技术,把程序生成和修改的文件定向到自身文件夹中。

3.1 沙盒机制与持久化的关系

iOS 中的持久化是指将数据在应用程序退出后仍然保留在存储设备上的能力。而沙盒机制是 iOS 系统为每个应用程序提供的安全性措施,通过将每个应用程序限制在自己的沙盒中,确保应用程序只能访问自己的数据,并不能访问其他应用程序的数据。

持久化和沙盒机制在 iOS 应用程序中是密切相关的,因为应用程序需要在沙盒中对数据进行持久化。iOS 提供了几种方式来实现数据持久化,而所有这些方式都是在应用程序的沙盒内进行的。以下是 iOS 持久化与沙盒机制的关系:

  • 文件储存持久化: 在 iOS 应用程序中,可以使用文件系统来持久化数据,例如将数据保存到文件中。iOS 应用程序只能在自己的沙盒目录中创建、读取和写入文件,不能访问其他应用程序的文件。常见的文件系统持久化方式包括使用 NSFileManager 类进行文件操作,或者使用 NSDataNSString 类的方法将数据写入文件。
  • UserDefaults 持久化: NSUserDefaults 是一种简单的持久化方式,可以用于保存用户的偏好设置、配置信息等。虽然数据是持久化的,但是它们仍然存储在应用程序的沙盒中,并且只能被当前应用程序访问。
  • 数据库持久化:它将数据保存到 SQLite 数据库中或其他数据存储。这些也是在应用程序的沙盒内进行数据持久化的方式。
  • Keychain 持久化: KeychainiOS 提供的一种安全存储敏感数据的方式,例如密码、密钥等。Keychain 中的数据也是在应用程序的沙盒内进行持久化,并且具有更高的安全性保护,确保只有应用程序本身才能访问这些数据。

总的来说,iOS中的持久化操作都是在应用程序的沙盒内进行的,受到沙盒机制的限制,确保应用程序只能访问自己的数据,保证了应用程序之间的数据隔离和安全性。

3.2 沙盒的目录结构

3.2.1 获取应用程序的沙盒路径:

// 获取沙盒根目录路径
    NSString *path = NSHomeDirectory();

注意: 每次编译代码会生成新的沙盒路径,注意是编译不是启动,所以模拟机或者真机运行,每次运行所得到的沙盒路径都是不一样的,线上版本app真机不会生成新的沙盒路径。

上面的代码得到的就是当前应用程序目录的路径,该目录下就是应用程序的沙盒,在该目录下有4个文件夹:DocumentsLibrarySystemDatatmp,当前应用程序只能访问该目录下的文件。
在这里插入图片描述

3.2.2 访问沙盒目录常用C函数介绍

//文件路径搜索
FOUNDATION_EXPORT NSArray<NSString *> *NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde);

该方法返回值为一个数组,在iphone中由于只有一个唯一路径,所以直接取数组第一个元素即可。

该函数的作用是返回指定搜索目录下的路径数组。它接受三个参数:

  1. directoryNSSearchPathDirectory 类型的枚举值,用于指定搜索的目录。常见的枚举值包括:
//常用的NSSearchPathDirectory枚举值
typedef NS_ENUM(NSUInteger, NSSearchPathDirectory) {
    NSApplicationDirectory = 1,             // supported applications (Applications)
    NSDemoApplicationDirectory,             // unsupported applications, demonstration versions (Demos)
    NSAdminApplicationDirectory,            // system and network administration applications (Administration)
    NSLibraryDirectory,                     // various documentation, support, and configuration files, resources (Library)
    NSUserDirectory,                        // user home directories (Users)
    NSDocumentationDirectory,               //  Library 下的(Documentation)模拟器上没有创建
    NSDocumentDirectory,                    // documents (Documents)
};
  1. domainMaskNSSearchPathDomainMask 类型的位掩码,用于指定搜索路径的范围。常见的枚举值包括:
typedef NS_OPTIONS(NSUInteger, NSSearchPathDomainMask) {
    NSUserDomainMask = 1,       // 用户目录 - 基本上就用这个。 
    NSLocalDomainMask = 2,      // 本地
    NSNetworkDomainMask = 4,    // 网络 
    NSSystemDomainMask = 8,     // 系统
    NSAllDomainsMask = 0x0ffff  // 所有 
};
  1. expandTildeBOOL 类型的参数,指定是否展开波浪号~。如果设置为 YES,则路径中的波浪号~将被展开为用户的主目录路径。

该值为NO:Caches目录路径为~/Library/Caches
该值为YES:Caches目录路径为/var/mobile/Containers/Data/Application/E7B438D4-0AB3-49D0-9C2C-B84AF67C752B/Library/Caches

3.2.3 沙盒目录的获取示例

//获取沙盒根路径
NSString *path = NSHomeDirectory();
NSLog(@"沙盒根路径:%@", path);
//Document路径
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSLog(@"Document目录路径:%@", docDir);
// 获取Library的目录路径
NSString *libDir = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
NSLog(@"Libarary目录路径:%@", libDir);
// 获取Caches目录路径
NSString *cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
NSLog(@"Cacheas目录路径:%@", cachesDir);
// library Preference
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSLog(@"偏好设置目录路径:%@", defaults);
// 获取tmp目录路径
NSString *tmpDir =  NSTemporaryDirectory();
NSLog(@"tmp目录路径:%@", tmpDir);

输出结果:
在这里插入图片描述

3.2.4 沙盒目录介绍

  • Documents:保存持久化数据,会备份。一般用来存储需要持久化的数据。
    一般我们在项目中,我们会把一些用户的登录信息以及搜索历史记录等一些关键数据存储到这里。
// 获取Documents目录路径
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];

此文件夹是默认备份的,备份到iCloud。
注:iCloud的备份,会通过Wi-Fi每天自动备份用户iOS设备。
我们可以在获取到的路径结尾加一个字符串来创建一个文件名:

NSString *filename = [docDir stringByAppendingPathComponent:@"data.txt"];

这样我们的这个filename就是一个完整的.txt类型文件的目录了。

  • Library:默认存放设置和其他状态信息,除了caches子目录之外其他目录都会被iclude同步。
    • Application Support:此目录包含应用程序用来运行但应对用户隐藏的文件,如游戏的新关卡等文件。
    • Caches:保存应用运行时生成的需要持久化的数据,一般存储体积大、不需要备份的非重要数据,如网络请求的音视频与图片等的缓存。在 iOS 5.0 及以后版本中,Caches 当系统磁盘空间非常低时,系统可能会在极少数情况下该删除目录(APP 正在运行时不会发生),所以尽量保证该路径的文件在 APP 在重新运行时可以得到重新创建。
    • Cooikes:系统会自动将App中网络请求的cookie保存为文件。
    • Preferences:保存应用的所有偏好设置。UserDefaults 生成的 plist 文件就会保存该目录下。
    • SplashBoard:存储启动屏缓存,缓存文件格式为 ktx,本质上就是图片,如果启动屏不生效的问题可以考虑从删除该路径下相关缓存文件这个角度解决。
  • SystemData:存放系统数据,无对外暴露的接口。
  • tmp:临时文件夹(系统会不定期删除里面的文件)。

4 持久化数据存储方式

4.1 plist文件(序列化)

plist文件是通过XML文件的方式保存在目录中 以下类型可以被序列化:

NSString;//字符串
NSMutableString;//可变字符串
NSArray;//数组
NSMutableArray;//可变数组
NSDictionary;//字典
NSMutableDictionary;//可变字典
NSData;//二进制数据
NSMutableData;//可变二进制数据
NSNumber;//基本数据
NSDate;//日期

这里我们就用NSDictionary当例子,其他的类型和这个方法类似:

- (void) writeToPlist {
    // 定义plistName
    NSString *plistName = @"test.plist";
    // 存取路径
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    // 打印路径
    NSLog(@"%@", path);
    // 连接路径
    NSString *filePath = [path stringByAppendingPathComponent:plistName];
    
    // 定义字典文件
    NSDictionary *dict = @{@"SXTTTTT":@"10"};
    
    //序列化
    [dict writeToFile:filePath atomically:YES];
}

atomically是否先写入辅助文件,增加安全性的写入文件方法,一般都是YES。

前往打印出的路径查看,发现确实多了一个test.plist文件。
在这里插入图片描述

打开这个文件看看。
在这里插入图片描述

可以看到值确实储存到了这个文件内部。

使用dictionaryWithContentsOfFile:类方法可以取出这个值:

    NSDictionary *dict1 = [NSDictionary dictionaryWithContentsOfFile:filePath];
    NSLog(@"%@", dict1);

结果:
在这里插入图片描述

4.2 preference:偏好设置

偏好设置(Preferences)是 iOS 开发中一种简单的数据持久化方式,用于保存应用程序的配置信息、用户偏好设置等数据。在 iOS 中,可以使用 NSUserDefaults 类来进行偏好设置的读取和保存。

NSUserDefaults 是一个单例类,用于访问应用程序的偏好设置。它可以存储各种类型的数据,如布尔值、整数、浮点数、字符串、数组、字典等。这些数据将会持久化到应用程序的沙盒中,即使应用程序退出,下次启动时也可以读取这些数据。

NSUserDefaults:简单数据快速读写,不能存储自定义类型。
UserDefaults设置数据时,不是立即写入,而是根据时间戳定时地把缓存中的数据写入本地磁盘。所以调用了set方法之后数据有可能还没有写入磁盘应用程序就终止了。出现以上问题,可以通过调用synchornize方法[defaults synchornize];强制写入。

偏好设置存储的优点:

  • 不需要关心文件名,系统会自动帮你生成一个文件名。
  • 快速做键值对的存储。

我们来尝试使用使用UserDefaults注册一个账号密码

- (void)writeToUserDefaults {
    // 获取偏好设置对象
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    
    // 存储数据
    [defaults setObject:@"ouhaijian" forKey:@"name"];
    [defaults setObject:@"666666" forKey:@"password"];
    
    // 同步调用,立刻写到文件中,不写这个方法会异步,有延迟
    [defaults synchronize];
}
- (void)readFromUserDefaults {
    // 获取偏好设置对象
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    
    // 获取数据
    NSString *name = [defaults objectForKey:@"name"];
    NSString *password = [defaults objectForKey:@"password"];
    
    NSLog(@"name:%@", name);
    NSLog(@"password:%@", password);
}

运行结果:
在这里插入图片描述

注意,对于设置偏好设置值后,需要调用 synchronize 方法来立即将数据保存到磁盘中,以确保数据持久化。不过,iOS 7 及以上版本,synchronize 方法会自动在合适的时机将数据保存,所以不再是必需的操作。

我们到cd到沙盒中的preference文件目录,可以看到里面多了一个新的文件,这个文件里面储存的就是我们储存的账号。
在这里插入图片描述

打开这个文件看看。
在这里插入图片描述

4.3 NSKeyedArchiver归档和解档

NSKeyedArchiver(归档):归档一般都是保存自定义对象的时候,使用归档。因为plist文件不能够保存自定义对象。如果一个字典中保存有自定义对象,如果把这个对象写入到文件当中,它是不会生成 plist文件的。如果对象是NSStringNSDictionaryNSArrayNSDataNSNumber等类型,可以直接用NSKeyedArchiver进行归档和恢复。

但是在我们使用归档之前,我们必须得遵守NSSecureCoding协议才行,老版本只需要遵循NSCoding实现其归档和解档的方法就行,但是iOS13更新之后就不行了,我们就必须的遵守NSSecureCoding协议,NSSecureCoding协议也遵循了原来NSCoding这个协议,不过我们还需要遵循它的一个supportsSecureCoding方法,这样我们才能归档成功。

因为NSSecureCoding协议也遵循了原来NSCoding这个协议,所以他也就有了- (void)encodeWithCoder:(NSCoder *)coder方法和- (id)initWithCoder:(NSCoder *)coder方法:

-(void)encodeWithCoder:(NSCoder *)coder,每次归档对象时,都会调用这个方法。一般在这个方法里面指定如何归档对象中的每个实例变量。可以使用encodeObject:forKey:方法归档实例变量。

-(id)initWithCoder:(NSCoder *)coder,每次从文件中会恢复(解码)对象时,都会调用这个方法。一般在这个方法里面指定如何解码文件中的数据为对象的实例变量,可以使用decodeObject:forKey方法解码实例变量。

例,新建一个SXPerson类:

#import <Foundation/Foundation.h>

@interface SXPerson : NSObject <NSSecureCoding>
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) int age;
@end

@implementation SXPerson
- (void)encodeWithCoder:(NSCoder *)coder {
    [coder encodeObject:self.name forKey:@"name"];
    [coder encodeInt:self.age forKey:@"age"];
}

- (id)initWithCoder:(NSCoder *)coder {
    if (self = [super init]) {
        self.name = [coder decodeObjectForKey:@"name"];
        self.age = [coder decodeIntForKey:@"age"];
    }
    return self;
}

+ (BOOL)supportsSecureCoding {
    return YES;
}
@end

进行归档和解档:

// 归档
- (void)writeUseNSKeyedArchiver {
    SXPerson *person = [[SXPerson alloc] init];
    person.age = 10;
    person.name = @"蔡徐坤";
    NSError * __autoreleasing *error = NULL;
    
    // 获得Document的全路径
    NSString *docu = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    // 获得新文件的全路径
    NSString *path = [docu stringByAppendingPathComponent:@"SXPerson.data"];
    // 将对象封装为Data并归档
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:person requiringSecureCoding:YES error:error];
    if (error) {
        NSLog(@"writeUseNSKeyedArchiver:%@", *error);
    } else {
        [data writeToFile:path atomically:YES];
    }
}

// 解档
- (void)readUseNSKeyedArchiver {
    NSError * __autoreleasing *error = NULL;
    // 获得Document的全路径
    NSString *docu = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    // 获得新文件的全路径
    NSString *path = [docu stringByAppendingPathComponent:@"SXPerson.data"];
    // 从path路径中获取data数据
    NSData *unData = [NSData dataWithContentsOfFile:path];
    // 创建解档操作的客户端允许的类集合
        // 这个集合应包括自定义对象的属性的类
    NSSet *allowedClassesSet = [NSSet setWithObjects:[NSString class], [SXPerson class], nil];
    SXPerson *person = (SXPerson *)[NSKeyedUnarchiver unarchivedObjectOfClasses:allowedClassesSet fromData:unData error:error];
    // 打印结果
    if (error) {
        NSLog(@"readUseNSKeyedArchiver:%@", *error);
    } else {
        NSLog(@"%@-%d", person.name, person.age);
    }
}

创建解档操作的客户端允许的类集合,这个集合应包括自定义对象的属性的类,否则会给出警告。这个警告并不会导致解档操作出错,但是在将来的版本中可能会被禁止。为了避免将来的兼容性问题,建议您在解档时将需要解档的所有类都添加到客户端允许的类集合中。

结果:
在这里插入图片描述

我们还可以看到Document目录下多了一个SXStudent.data文件:
在这里插入图片描述

可以使用vim打开这个文件看一下,大概能看懂是储存了NSKeyedArchiver归档的一个对象:
在这里插入图片描述

最后另外说一点,归档操作有时会被用于实现对象(尤其是自定义对象)的深拷贝操作。通过归档,我们可以将原对象序列化为二进制数据,并在反归档时重新创建出一个全新的对象,包括其内部引用对象。这样,新对象与原对象之间是完全独立的,修改其中一个对象不会影响到另一个对象。

4.4 数据库存储(这部分太多了,以后有机会另学)

  • SQLite
    是目前主流的嵌入式关系型数据库,其最主要的特点就是轻量级、跨平台,当前很多嵌入式操作系统都将其作为数据库首选。
  • CoreData
    CoreData是iOS5之后才出现的一个框架,本质上是对SQLite的一个封装,它提供了对象-关系映射(ORM)的功能,即能够将OC对象转化成数据,保存在SQLite数据库文件中,也能够将保存在数据库中的数据还原成OC对象,在这个过程中不需要手动编写任何SQL语句,CoreData封装了数据库的操作过程,以及数据库中数据和OC对象的转换过程。通过CoreData管理应用程序的数据模型,可以极大程度减少需要编写的代码数量。
  • FMDB
    是一个处理数据存储的第三方框架,框架是对sqlite的封装,整个框架非常轻量级但又不失灵活性,而且更加面向对象。
  • SQLiteCoreData的区别:
    CoreData可以在一个对象更新时,其关联的对象也会随着更新,相当于你更新一张表时,其关联的其他表的也会随着更新。
    CoreData供更简单的性能管理机制,可以限制查询记录的总数,这个类会自动更新其缓存。
    多表查询方面,CoreData没有SQL直观,没有类似外连接,左连接等操作。

5 补充

5.1 什么是序列化和反序列化,用来做什么?

  • 序列化:把对象转化为字节序列的过程
  • 反序列化:把字节序列恢复成对象
  • 作用:把对象写到文件或者数据库中,并且读取出来

5.2 程序中的plist文件

plist全名Property List,属性列表文件,它是一种用来存储串行化后的对象的文件,属性列表文件的扩展名为plist ,因此通常被称为plist文件。文件是xml格式的。

这里补充一下程序中的plist文件,及其对应的写入,读取操作。

程序中的plist文件必须先创建,后使用:
在这里插入图片描述

源代码:

// 写入程序plist
- (void)setDataToPlist {
    // 第一参数:文件名
    // 第二参数:文件后缀
    NSString *plist = [[NSBundle mainBundle] pathForResource:@"show" ofType:@"plist"];
    NSDictionary *dict = @{@"蔡徐坤":@"name", @10:@"age"};
    [dict writeToFile:plist atomically:YES];
}

// 读取程序plist
- (void)getDataFromPlist {
    NSString *plist = [[NSBundle mainBundle] pathForResource:@"show" ofType:@"plist"];
    NSLog(@"%@", plist);
    NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:plist];
    NSLog(@"%@", dict);
}

运行结果:
在这里插入图片描述

虽然我们在项目工程里创建了这个文件,但是数据似乎并不会保存在这个文件里,至少不是这个工程包里的文件。

我们cd到打印出来的目录中:
在这里插入图片描述

使用vim看看这个同名文件:
在这里插入图片描述

可以看到数据被保存到应用程序的资源束(Resource Bundle)中。

当我们编译项目时,Xcode似乎会将资源文件(包括 .plist 文件)全复制到应用程序的资源束(Resource Bundle)中。这样可以确保在运行时能够找到并正确读取资源文件中的内容。

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

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

相关文章

容器管理工具 portainer可视化面板 的安装及使用

大家好&#xff0c;我是早九晚十二&#xff0c;目前是做运维相关的工作。写博客是为了积累&#xff0c;希望大家一起进步&#xff01; 我的主页&#xff1a;早九晚十二 什么是portainer Portainer是一款轻量级的Docker图形化管理的方案&#xff0c;相比k8s和k3s&#xff0c;只需…

Dev C++下载安装

1、下载 下载地址&#xff1a;Dev-C download | SourceForge.nethttps://sourceforge.net/projects/orwelldevcpp/ 点击“Download”下载 新建文件夹用于安装 2、安装 双击exe文件执行安装程序&#xff0c;选择“English”&#xff08;我没看到普通话&#xff09; 选择“I …

简单的语音广播功能方案

方案介绍&#xff1a; 1&#xff09;前端可以复用如下播放器的方案 &#xff08;或自行实现&#xff09; 其中&#xff0c;rtp封装过程中&#xff0c;额外增加了2字节的长度信息&#xff0c;后端服务接收之后&#xff0c;做好校验之后&#xff0c;需要剔除2个字节的数据头 2&a…

.Net Core依赖注入

.Net Core依赖注入 往期文章&#xff1a; .ner Core实现接口限流.net Core程序发布到IIS(Window Server 2019) 文章目录 .Net Core依赖注入前言一、ICO 和DI和DLICO [控制反转]DI [依赖注入]DL [依赖查找] 二、.net Core 中的依赖注入【Autofac】瞬时模式作用域模式单例模式尝…

Android Dalvik 虚拟机(详细版)

经典好文推荐,通过阅读本文,您将收获以下知识点: 1.Java 语言在Android 上运行流程 2.虚拟机发展过程 3.Android Dalvik 模式 4.Android N 中dex2oat 原理以及模式 5.如何判断dex2oat 采用的相关参数 6.如何查看dex2oat 的log 7.什么时候进行dex2oat 8.手机反应慢的原因 9.解…

再获权威认可!MIAOYUN荣获中国信通院一云多芯优秀案例,荣登《云管理产品与服务图谱》

2023年7月25日&#xff0c;以“云领创新&#xff0c;算启新篇”为主题的2023可信云大会在北京国际会议中心顺利召开。会上中国信息通信研究院发布了一云多芯稳定安全运行优秀案例和业界首个《云管理产品与服务图谱&#xff08;2023&#xff09;》。成都元来云志科技有限公司&am…

QEMU源码全解析12 —— QOM介绍(1)

接前一篇文章&#xff1a;QEMU源码全解析11 —— 定义一个QEMU模块&#xff08;3&#xff09; 本文内容参考&#xff1a; 《趣谈Linux操作系统》 —— 刘超&#xff0c;极客时间 《QEMU/KVM》源码解析与应用 —— 李强&#xff0c;机械工业出版社 特此致谢&#xff01; 前几…

springboot创建并配置环境(一) - 创建环境

文章目录 一、介绍二、启动环境Environment的分析三、进入源码四、创建环境1. 如何确定应用类型2. 测试 一、介绍 在springboot的启动流程中&#xff0c;启动环境Environment是可以说是除了应用上下文ApplicationContext之外最重要的一个组件了&#xff0c;而且启动环境为应用…

5点搞透电阻选型

一提到电阻&#xff0c;大家肯定会想到一个人&#xff1a;欧姆。 欧姆(Georg Simon 0hm&#xff0c;1787~1854年)是德国物理学家。生于巴伐利亚埃尔兰根城。欧姆定律及其公式的发现&#xff0c;给电学的计算&#xff0c;带来了很大的方便。 人们为了纪念他&#xff0c;将电阻的…

前端css--导航栏效果

效果如下&#xff1a; <!DOCTYPE html> <html lang"en" > <head><meta charset"UTF-8"><title>导航栏动态效果</title><link rel"stylesheet" href"./style/style.css"> </head> &…

51单片机:数码管和矩阵按键

目录 一:动态数码管模块 1:介绍 2:共阴极和共阳极 A:共阴极 B:共阳极 C:转化表 3:74HC138译码器 4:74HC138译码器控制动态数码管 5:数码管显示完整代码 二:矩阵按键模块 1:介绍 2:原理图 3:矩阵按键代码 一:动态数码管模块 1:介绍 LED数码管&#xff1a;数码管是一种…

【数字IC】芯片产业链

芯片产业链 FoundaryFablessEDADesign ServiceIP供应商IDM就业岗位 Foundary Fabless 无晶圆厂 IC design house EDA Design Service Veri Silicon &#xff1a; 芯原微 Alchip&#xff1a;世芯&#xff08;上海&#xff09; Brite&#xff1a;灿芯&#xff08;上海&…

Vue+ElementUI操作确认框及提示框的使用

在进行数据增删改查操作中为保证用户的使用体验&#xff0c;通常需要显示相关操作的确认信息以及操作结果的通知信息。文章以数据的下载和删除提示为例进行了简要实现&#xff0c;点击下载以及删除按钮&#xff0c;会出现对相关信息的提示&#xff0c;操作结果如下所示。 点击…

“数字化员工”,正在占领厂区

劳动力规模逐年降低、劳动生产率增速被平均工资增速超越——中国企业正在面临用工难题。为了应对这一困境&#xff0c;唯一的解决方案就是全面转向“第四种用工模式”——“数字化劳动力”&#xff0c;它可以全力激活人效潜能&#xff0c;并助力企业行稳致远。 智能中央立库中的…

放射组学增强的深度多任务学习用于头颈癌预后预测

文章目录 Radiomics-enhanced Deep Multi-task Learning for Outcome Prediction in Head and Neck Cancer摘要本文方法实验结果 Predicting Regions of Local Recurrence in Glioblastomas Using Voxel-Based Radiomic Features of Multiparametric Postoperative MRI摘要方法…

猿人学第二题—混淆 动态cookie检测

猿人学第二题—混淆 动态cookie检测 1、代码格式化检测2、检测global和navigator.vendorSub3、检测setInterval思考 4、console.log输出检测补环境 简单的document.cookie&#xff0c;location.reload等就不写了 1、代码格式化检测 这里应该是利用了字符串正则匹配性能低的特点…

管理类联考——写作——素材篇——论说文——可持续发展——食蚁兽

巴西热带雨林中的食蚁兽在捕食时&#xff0c;使用带粘液的长舌伸进蚁穴捕获白蚁&#xff0c;但不管捕获多少&#xff0c;每次捕食都不超过3分钟&#xff0c;然后去寻找下一个目标&#xff0c;从来不摧毁整个蚁穴。而那些没有被食蚁兽捕获的工蚁就会修复蚁穴&#xff0c;蚁后也会…

【C++进阶之路】继承篇

文章目录 前言一、概念二、性质1.赋值转换2.作用域——隐藏/重定义3.默认成员函数①构造函数②拷贝构造③析构函数④赋值重载 4.友元函数5.多继承①单继承—— "一脉单传"②多继承——"一父多子"③菱形继承—— "一子多父"④菱形虚拟继承 三、总…

【数据分享】1999—2021年地级市固定资产投资和对外经济贸易数据(Shp/Excel格式)

在之前的文章中&#xff0c;我们分享过基于2000-2022年《中国城市统计年鉴》整理的1999-2021年地级市的人口相关数据、各类用地面积数据、污染物排放和环境治理相关数据、房地产投资情况和商品房销售面积、社会消费品零售总额和年末金融机构存贷款余额、地方一般公共预算收支状…

第二十章 原理篇:CLIP

参考教程&#xff1a; 【PDF】Learning Transferable Visual Models From Natural Language Supervision https://github.com/openai/CLIP 文章目录 概述方法自然语言监督创建一个足够大的数据集选择高效的预训练方法代码解读 选择和缩放模型训练使用 代码解读model load rel…