【iOS】——持久化

news2024/12/26 22:31:44

在iOS开发中,数据持久化是非常重要的,因为它允许应用程序在不同会话之间保存用户数据、设置、偏好等信息。

为什么数据持久化

  1. 数据保存
    • 目的:将应用程序中的数据保存到非易失性存储中,以便在应用程序关闭或重启后仍能访问这些数据。
    • 示例:保存用户输入的数据、应用设置、游戏进度等。
  2. 状态恢复
    • 目的:在应用程序重新启动时恢复到之前的状态。
    • 示例:保存应用的最后状态,以便用户可以从中断的地方继续。
  3. 数据备份
    • 目的:定期备份数据,以防数据丢失。
    • 示例:定期备份数据库到云端或本地存储。
  4. 数据共享
    • 目的:允许多个应用程序或设备之间共享数据。
    • 示例:使用云服务同步数据,如 iCloud、Dropbox 等。
  5. 离线访问
    • 目的:即使在网络不可用的情况下也能访问数据。
    • 示例:离线模式下的地图应用、阅读应用等。
  6. 历史记录
    • 目的:记录用户的操作历史,以便用户可以回顾之前的活动。
    • 示例:浏览历史、购买记录等。
  7. 数据分析
    • 目的:收集用户行为数据,用于分析和改进产品。
    • 示例:收集用户使用频率、停留时间等数据。
  8. 用户个性化
    • 目的:根据用户的偏好定制内容和服务。
    • 示例:保存用户喜好、推荐设置等。
  9. 安全性与合规性
    • 目的:确保敏感数据的安全存储,并遵守相关法规要求。
    • 示例:加密存储个人身份信息、健康数据等。
  10. 性能优化
    • 目的:通过缓存数据减少网络请求,提高应用程序的响应速度。
    • 示例:缓存图片、API 数据等。

数据持久化方式

  • NSUserDefault:简单数据快速读写。
  • Property list: 属性列表的文件存储
  • Archiver:归档。
  • SQLite:本地数据库。
  • CoreData:CoreData 是基于 sqlite 的封装。

数据存储区域

数据存储的区域在内存和磁盘

内存缓存

对于使用频率比较高的数据,从网络或磁盘加载数据到内存以后,使用后并不马上销毁,下次使用直接从内存加载。

例如iOS中图片的加载

磁盘缓存

将从网络加载的,用户操作产生的数据写入到磁盘,用户下次查看、继续操作时,直接从磁盘加载使用

例如搜索历史的缓存、用户输入内容草稿的缓存

沙盒机制

出于安全的原因,iOS 应用在安装时,为每个 App 分配了独立的目录,App 只能对自己的目录进行操作,这个目录就被称为沙盒。

应用程序只能访问自身的沙盒文件,不能访问其他应用程序的沙盒文件,当应用程序需要向外部请求或接收数据时,都需要经过权限认证,否则,无法获取到数据。所有的非代码文件都要保存在此。

例如属性文件plist、文本文件、图像、图标、媒体资源等,其原理是通过重定向技术,把程序生成和修改的文件定向到自身文件夹中。

沙盒中主要包含4个目录: MyApp.appDocumentsLibraryTmp,目录结构如下:

截屏2022-05-19 16.55.08.png

  • MyApp.app:包含了所有的资源文件和和可执行文件,上架前经过数字签名,上架后不可修改。

  • Documents:文档目录,要保存程序生成的数据,会自动被分到iCloud中。保存应用运行时生成的需要持久化的数据,iTunes同步设备时会备份该目录。例如,游戏应用可将游戏存档保存在该目录。(注意点:不要保存从网络上下载的文件,否则会无法上架!)

  • Library:

    用户偏好,使用 NSUserDefault 直接读写!

    如果要想数据及时写入磁盘,还需要调用一个同步方法

    保存临时文件,“后续需要使用”,例如:缓存图片,离线数据(地图数据

    系统不会清理 cache 目录中的文件,就要求程序开发时,“必须提供 cache 目录的清理解决方案”

    Caches:存放体积大又不需要备份的数据

    Preference:保存应用的所有偏好设置,iCloud会备份设置信息

  • Tmp

    临时文件,系统会自动清理。重新启动就会清理。保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时不会备份该目录。

    存放临时文件,不会被备份,而且这个文件下的数据有可能随时被清除的可能

    保存临时文件,“后续不需要使用”

    tmp 目录中的文件,系统会自动清理

    重新启动手机,tmp 目录会被清空

    系统磁盘空间不足时,系统也会自动清理

应用沙盒目录的常见获取方式

获取沙盒根目录:

NSString *home = NSHomeDirectory();

每次编译代码会生成新的沙盒路径,是在编译的时候,所以模拟机和真机每次的沙盒路径都是不一样的。

在这里插入图片描述

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

利用 NSSearchPathForDirectoriesInDomains 函数获取沙盒目录

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


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

  • 参数一 NSSearchPathDirectory directory:指定搜索的目录名称,比如这里用NSDocumentDirectory表明我们要搜索的是Documents目录。如果我们将其换成NSCachesDirectory就表示我们搜索的是Library/Caches目录。

  • 参数二 NSSearchPathDomainMask domainMask:搜索主目录的位置,NSUserDomainMask表示搜索的范围限制于当前应用的沙盒目录。还可以写成NSLocalDomainMask(表示/Library)、NSNetworkDomainMask(表示/Network)等。

  • 参数三 BOOL expandTilde:是否获取完整的路径,该值为YES即表示写成全写形式,为NO就表示直接写成“~”。

上述两个参数的枚举值:

typedef NS_OPTIONS(NSUInteger, NSSearchPathDomainMask) {
    NSUserDomainMask = 1,       // 用户目录 - 基本上就用这个。 
    NSLocalDomainMask = 2,      // 本地
    NSNetworkDomainMask = 4,    // 网络 
    NSSystemDomainMask = 8,     // 系统
    NSAllDomainsMask = 0x0ffff  // 所有 
};

//常用的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)
};


沙盒目录获取示例:

 // 搜索 Document 目录
    NSArray<NSString *> *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentDirectory = [documentPaths firstObject];
    NSLog(@"Document Directory: %@", documentDirectory);
    // 搜索 Document 目录 NO
    
    NSArray<NSString *> *documentPathsNO = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, NO);
    NSString *documentDirectoryNO = [documentPathsNO firstObject];
    NSLog(@"Document Directory NO: %@", documentDirectoryNO);


NSCache

NSCache是苹果提供的一套缓存机制,用法和NSMutableDictionary类似,在AFNetworking,SDWebImage,Kingfisher中都有用到。

当内存不足时NSCache会自动释放内存。 NSCache设置缓存对象数量和占用的内存大小,当缓存超出了设置会自动释放内存。
NSCache是Key-Value数据结构,其中key是强引用,不实现NSCoping协议,作为key的对象不会被拷贝。

NSCache的属性

countLimit: 能够缓存对象的最大数量,默认值是0,没有限制。
totalCostLimit: 设置缓存占用的内存大小 evictsObjectsWithDiscardedContent: 是否回收废弃内容,默认YES

NSCache的方法

objectForKey: 通过key获得缓存对象。
setObject: forKey: 缓存对象。
setObject: forKey: cost: 缓存对象,并指定key值对应的成本,用于计算缓存中所有对象的总成本。
removeObjectForKey: 删除指定对象。
removeAllObjects: 删除所有缓存对象。

NSCacheDelegate代理

willEvictObject: 缓存对象即将被清理时调用,一般开发者用来调试,不能在此方法中修改缓存

在下列场景中会被调用:

  1. removeObjectForKey
  2. 缓存对象超过NSCache的countLimit和otalCostLimit属性设置的限制
  3. App进入后台
  4. 系统发出内存警告
  5. cache这个实例的生命周期结束前

注意

当收到内存警告,而我们又调用removeAllObjects,则无法再继续往缓存中添加数据。
不提供缓存总的大小,想知道NSCache占用的内存大小,只有通过添加缓存的cost自己计算。
NSCache自动释放内存的算法是不确定的,有时是按照LRU(最近最久未使用)释放,有时随机释放。
NSCache中的数据在APP重启后会消失,因为NSCache只是将数据保存在内存 的。

NSCache和NSMutableDictionary的区别
NSCache是线程安全的,不需要加线程锁,而NSMutableDictionary线程不安全。

示例代码:

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController<NSCacheDelegate>
@property (nonatomic, strong)NSCache* myCache;

@end

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor whiteColor];
        
        self.myCache = [[NSCache alloc]init];
        self.myCache.delegate = self;
        
        for (int i = 0; i<10; i++) {
            [self.myCache setObject:[NSString stringWithFormat:@"%d", i] forKey:@(i) cost: 1];
        }
        
        for (int i = 0; i<10; i++) {
            NSLog(@"NSCache取出---%@", [self.myCache objectForKey:@(i)]);
        }
        
        /// 清除缓存
        [self.myCache removeAllObjects];
        /// 设置缓存限制
        self.myCache.totalCostLimit = 5;
        
        NSLog(@"设置缓存限制后=================");
        
        for (int i = 0; i<10; i++) {
            // 设置成本数为1
            [self.myCache setObject:[NSString stringWithFormat:@"%d", i] forKey:@(i) cost: 1];
        }
        
        for (int i = 0; i<10; i++) {
            NSLog(@"NSCache取出---%@", [self.myCache objectForKey:@(i)]);
        }
        
        /// 清除缓存
        [self.myCache removeAllObjects];
        NSLog(@"设置缓存限制后但未设置成本数cost=================");
        
        for (int i = 0; i<10; i++) {
            [self.myCache setObject:[NSString stringWithFormat:@"%d", i] forKey:@(i)];
        }
        
        for (int i = 0; i<10; i++) {
            NSLog(@"NSCache取出---%@", [self.myCache objectForKey:@(i)]);
        }
        
        /// 清除缓存
        [self.myCache removeAllObjects];

}
// 即将回收对象的时候进行调用,实现代理方法之前要遵守NSCacheDelegate协议。
- (void)cache:(NSCache *)cache willEvictObject:(id)obj{
    NSLog(@"NSCache回收---%@", obj);
}

@end

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

从打印结果可以看看出:

  1. 设置缓存限制且知道缓存成本数时,超出是会自动回收。但是设置缓存限制但不知道缓存成本数时不会自动回收。
  2. 回收时会调用 willEvictObject 的代理方法。

持久化数据存储方式

Plist(属性列表)

属性列表是一种XML格式的文件,拓展名为plist如果对是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,就可以使用writeToFile:atomically:方法直接将对象写到属性列表文件中。

属性列表-NSDictionary的存储和读取过程:

img

- (void)directorfile {
    // 获取 Document 目录
    NSArray<NSString *> *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentDirectory = [documentPaths firstObject];
    // 在 Document 目录下新建一个 test.plist 文件
    NSString *documentfileName = [documentDirectory stringByAppendingPathComponent:@"data.plist"];
    NSLog(@"%@", documentfileName);
    
    // // 存字典,将字典数据存到刚才的 test.plist 文件
    NSDictionary *dict = @{@"name": @"clearlove", @"boom": @"4396"};
    [dict writeToFile:documentfileName atomically:YES];
    
    // 取字典
    NSDictionary* msgDict = [NSDictionary dictionaryWithContentsOfFile:documentfileName];
    NSLog(@"%@", msgDict);
}

Preference 偏好设置(UserDefaults)

很多iOS应用都支持偏好设置,比如保存用户名、密码、字体大小等设置,iOS提供了一套标准的解决方案来为应用加入偏好设置功能。
每个应用都有个NSUserDefaults实例,通过它来存取偏好设置。

比如,保存用户名、字体大小、是否自动登录:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:@"张三" forKey:@"username"];
[defaults setFloat:18.0f forKey:@"text_size"];
[defaults setBool:YES forKey:@"auto_login"];

读取上次保存的设置

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *username = [defaults stringForKey:@"username"];
float textSize = [defaults floatForKey:@"text_size"];
BOOL autoLogin = [defaults boolForKey:@"auto_login"];

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

偏好设置存储的优点:

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

NSKeyedArchiver 归档解档

NSKeyedArchiver(归档)归档一般都是保存自定义对象的时候,使用归档。因为plist文件不能够保存自定义对象。如果一个字典中保存有自定义对象,如果把这个对象写入到文件当中,它是不会生成 plist文件的。如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,可以直接用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方法解码实例变量。

NSSecureCoding协议还有+ (BOOL)supportsSecureCoding方法,只有当这个方法为YES的时候,才可以归档成功。

下面给出示例代码:

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Person : NSObject<NSSecureCoding>
@property (nonatomic, strong) NSString *name;
@property (assign) int age;
- (void)saveData;
- (void)readData;

@end
  
  #import "Person.h"

@implementation Person
- (void)encodeWithCoder:(NSCoder *)coder {
    [coder encodeObject:_name forKey:@"name"];
    [coder encodeInt:_age forKey:@"age"];
}
- (id)initWithCoder:(NSCoder *)coder {
    if (self = [super init]) {
        _name = [coder decodeObjectForKey:@"name"];
        _age = [coder decodeIntForKey:@"age"];
    }
    return self;
}
// 返回YES才能成功归档
+ (BOOL)supportsSecureCoding {
    return YES;
}

- (void)saveData {
    Person *p = [[Person alloc] init];
    p.name = @"clearlove";
    p.age = 24;
    NSError *error;
    // 2.归档模型对象
    // 3.获得 Documents 的全路径
    NSString *docu = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    // 4.获得新文件的全路径,即新建一个 person.data 文件来存储我们要归档的数据
    NSString *path = [docu stringByAppendingString:@"/person.plist"];
    NSLog(@"%@", path);
    // 5.将对象封装为 Data 数据并归档
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:p requiringSecureCoding:YES error:&error];
    if (error) {
        NSLog(@"sodufosuf%@", error);
    }
    [data writeToFile:path atomically:YES];
}
// 读档,将数据从文件中读出
- (void)readData {
   NSError *error;
   // 1.获得 Documents 的全路径
   NSString *docu = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
   // 2.获得文件的全路径,即获取我们要解档文件的路径
   NSString *path = [docu stringByAppendingString:@"/person.plist"];
   // 3.从 path 路径中获取 Data 数据
   NSData *unData = [NSData dataWithContentsOfFile:path];
   // 4.从文件中读取Person对象
   Person *person = (Person *)[NSKeyedUnarchiver unarchivedObjectOfClass:[Person class] fromData:unData error:&error];
   // 打印结果
   NSLog(@"name: %@ age: %d",person.name, person.age);
}
@end


如果父类也遵守了NSCoding协议,请注意: 应该在encodeWithCoder:方法中加上一句[super encodeWithCode:encode];确保继承的实例变量也能被编码,即也能被归档。 应该在initWithCoder:方法中加上一句self = [super initWithCoder:decoder];确保继承的实例变量也能被解码,即也能被恢复。

有时候可能想将多个对象写入到同一个文件中,那么就要使用NSData来进行归档对象。 NSData可以为一些数据提供临时存储空间,以便随后写入文件,或者存放从磁盘读取的文件内容。可以使用[NSMutableData data]创建可变数据空间。

// 新建一块可变数据区
NSMutableData *data = [NSMutableData data];
// 将数据区连接到一个NSKeyedArchiver对象
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
// 开始存档对象,存档的数据都会存储到NSMutableData中
[archiver encodeObject:person1 forKey:@"person1"];
[archiver encodeObject:person2 forKey:@"person2"];
// 存档完毕(一定要调用这个方法)
[archiver finishEncoding];
// 将存档的数据写入文件
[data writeToFile:path atomically:YES];

img

数据库存储

  • SQLite

是目前主流的嵌入式关系型数据库,其最主要的特点就是轻量级、跨平台,当前很多嵌入式操作系统都将其作为数据库首选。

  • CoreData

CoreData是iOS5之后才出现的一个框架,本质上是对SQLite的一个封装,它提供了对象-关系映射(ORM)的功能,即能够将OC对象转化成数据,保存在SQLite数据库文件中,也能够将保存在数据库中的数据还原成OC对象,在这个过程中不需要手动编写任何SQL语句,CoreData封装了数据库的操作过程,以及数据库中数据和OC对象的转换过程。通过CoreData管理应用程序的数据模型,可以极大程度减少需要编写的代码数量。

Core Data 中的三个对象
  • NSManagedObject
    只要定义一个类继承该类就会创建一张与之对应的表,也就是一个继承与该类的类就对应一张表,每一个通过继承该类创建出来的对象,都是该类对应的表中的一条数据。

  • NSManagedObjectContext
    用于操作数据库,只要有类它就能对数据库的表进行增删改查

  • NSPersistentStoreCoordinator
    决定存储的位置

  • FMDB

是一个处理数据存储的第三方框架,框架是对sqlite的封装,整个框架非常轻量级但又不失灵活性,而且更加面向对象。

Core data 多线程不安全

Core data 本身并不是一个并发安全的架构,所以在多线程中实现 Core data 会有问题。

  • 原因: CoreData 中的 NSManagedObjectContext 在多线程中不安全。
  • 如果想要多线程访问 CoreData,最好的方法是一个线程一个 NSManagedObjectContext。
  • 每个 NSManagedObjectContext 都可以使用同一个 NSPersistentStoreCoordinator 实例,因为 NSManagedObjectContext 会在使用 NSPersistentStoreCoordinator 前上锁。

序列化与反序列化

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

在iOS实际开发中,我们也会使用到序列化,归档就是我们在iOS开发中使用序列化的场景

在iOS中一个自定义对象是无法直接存入到文件中的,必须先转化成二进制流才行。从对象到二进制数据的过程我们一般称为对象的序列化(Serialization),也称为归档(Archive)。同理,从二进制数据到对象的过程一般称为反序列化或者反归档(解档)。

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

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

相关文章

眼镜清洗机哪个品牌好?性价比高的超声波眼镜清洗机

清洁眼镜、化妆刷、项链等物品其实是挺麻烦的&#xff0c;尤其是化妆刷这种经常使用的物品&#xff0c;需要用专门的清洁剂并保持一定的清洗频率。眼镜的日常清洁主要是用眼镜布擦拭镜片上的灰尘和指纹&#xff0c;但对于顽固的污渍或油脂&#xff0c;只有超声波清洗机能提供快…

六西格玛管理法

六西格玛管理法是一种旨在提高业务流程效率和减少缺陷的管理策略。它最初由摩托罗拉公司在1980年代末期提出&#xff0c;并随后被通用电气等公司广泛应用和发展。六西格玛的核心理念是通过减少过程变异性来提高产品质量和服务水平。 六西格玛的含义&#xff1a; 统计学概念&am…

一款功能全面的卸载工具,强大,免费,小巧

HiBit Uninstaller是一款功能全面的卸载工具&#xff0c;它不仅可以卸载Windows程序&#xff0c;还提供了诸如注册表清理、垃圾文件清理等多种系统优化功能。该软件以其小巧、强大、免费的特点受到用户的欢迎&#xff0c;尤其适合处理顽固软件和流氓程序的卸载问题。 主要功能…

WPF的MVVM架构:如何通过数据绑定简化UI逻辑

WPF的MVVM架构&#xff1a;如何通过数据绑定简化UI逻辑 目录 MVVM模式概述数据绑定在MVVM中的作用实现MVVM模式的步骤MVVM模式中的常见问题与解决方案实践示例总结 MVVM模式概述 MVVM&#xff08;Model-View-ViewModel&#xff09;是一种设计模式&#xff0c;用于WPF应用程序…

机器学习(五) -- 无监督学习(2) --降维1

系列文章目录及链接 上篇&#xff1a;机器学习&#xff08;五&#xff09; -- 无监督学习&#xff08;1&#xff09; --聚类2 下篇&#xff1a;机器学习&#xff08;五&#xff09; -- 无监督学习&#xff08;2&#xff09; --降维2 前言 tips&#xff1a;标题前有“***”的内…

热门超声波清洗机有哪些?小型超声波清洗机推荐

在繁忙的工作和生活中&#xff0c;许多人常常会因为种种原因忽略日常的小事&#xff0c;比如忘记清洁手表、眼镜、首饰等常用物品。实际上&#xff0c;这些物品表面不仅积累了灰尘和污垢&#xff0c;特别是跟眼部朝夕相处的眼镜&#xff0c;还可能滋生各种致病细菌&#xff0c;…

Vue3-如何自己写一个“返回顶部”功能

功能描述&#xff1a; 在屏幕的右下角固定一个“返回顶部”按钮&#xff0c;只有当用户滚动屏幕一定程度后出现&#xff0c;否则隐藏。 点击按钮&#xff0c;网页平滑的滚动到页面顶部。 环境&#xff1a;Vue3,js&#xff0c;antd 具体思路&#xff1a; 1、给窗口挂载滚动事…

Python 学习中的 API,如何调用API ?

1.1 API的定义 API&#xff0c;全称是Application Programming Interface&#xff08;应用程序编程接口&#xff09;。它是一组定义好的协议和工具&#xff0c;用于在软件应用程序之间进行通信。API可以简化软件开发&#xff0c;使不同的应用程序能够相互协作。它是软件开发中…

阿里云服务器 Ubuntu18.04 安装 mysql8.0并允许外部连接

参考教程&#xff1a; 官网教程 参考教程一 首先彻底删除mysql5.7 dpkg --list|grep mysql #查看 sudo apt-get remove mysql-common #卸载 sudo apt-get autoremove --purge mysql-server-5.7 #版本自己修改 dpkg -l|grep ^rc|awk {print$2}|sudo xargs dpkg -P #清除残留数…

LeetCode Hot100 将有序数组转换为二叉搜索树

给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 平衡 二叉搜索树。 示例 1&#xff1a; 输入&#xff1a;nums [-10,-3,0,5,9] 输出&#xff1a;[0,-3,9,-10,null,5] 解释&#xff1a;[0,-10,5,null,-3,null,9] 也将被视为正确…

电商老司机教您批量下载1688高清主图、详情图、sku及视频信息

图片在电商中至关重要&#xff0c;高质量的商品图片能吸引顾客注意&#xff0c;提升购买欲望。它们是展示商品特性和细节的主要方式&#xff0c;有助于增强消费者信任&#xff0c;减少退换货率。好的图片还能优化搜索排名&#xff0c;提高转化率。简而言之&#xff0c;图片是电…

Luma AI的战略转向:从Nerf到视频生成领域的背后故事

引言 今天我们将深入探讨Luma AI近期引发关注的视频生成模型——Dream Machine。Luma AI从最初的3D重建和生成业务逐步转向视频生成领域的背后&#xff0c;隐藏着什么样的战略考量和技术演进&#xff1f;让我们通过Luma AI首席科学家宋佳铭的最新访谈&#xff0c;揭开这场技术…

【每日一题 | 数据结构】时间复杂度计算

题目 解题方法 对于二重循环求时间复杂度&#xff1a; 写出外层i的变化值写出内层循环语句执行次数&#xff08;看j&#xff09;对次数求和找到频度和n的关系 笔记 视频跳转&#xff1a; 【每日一题 | 数据结构】时间复杂度计算

手写操作系统:二级引导程序

项目简介 在上篇博客&#xff0c;我们完成了主引导扇区的编写&#xff0c;在主引导扇区我们初始化了寄存器&#xff0c;加载了二级引导程序到内存地址 0x8000处&#xff0c;并跳转至0x8000处执行&#xff0c;在本文我们将继续编写二级引导程序。 在二级引导程序将完成以下任务…

Unity UGUI 实战学习笔记(6)

仅作学习&#xff0c;不做任何商业用途 不是源码&#xff0c;不是源码! 是我通过"照虎画猫"写的&#xff0c;可能有些小修改 不提供素材&#xff0c;所以应该不算是盗版资源&#xff0c;侵权删 因为注册和登录面板的逻辑与数据存储方面已经相对完善 服务器面板逻辑…

为什么现在的家具很多带缓冲器?

在当今的家具市场中&#xff0c;我们不难发现&#xff0c;很多的家具配备了缓冲器。这一现象的背后&#xff0c;有着多方面的原因。首先&#xff0c;随着人们生活水平的提高&#xff0c;对于生活品质的追求也日益增强。缓冲器能够有效地减少家具关闭时产生的噪音&#xff0c;为…

如何通过✅ IPIDEA代理IP,轻松实现数据采集和市场拓展工作(下)

如何通过✅ IPIDEA代理IP&#xff0c;轻松实现数据采集和市场拓展工作 如何通过✅ IPIDEA代理IP&#xff0c;轻松实现数据采集和市场拓展工作前言IPIDEA爬虫实战实战Demo演示总结 如何通过✅ IPIDEA代理IP&#xff0c;轻松实现数据采集和市场拓展工作 前言 在当今全球化市场的…

【Qt】QTextEdit

QTextEdit是Qt中用于编辑和显示文本内容的类。其提供了丰富的用户界面控件&#xff0c;可以用于创建和包含格式化文本、图片和链接的文本编辑器 常用属性 属性说明markdown输入框内持有的内容。支持markdown格式&#xff0c;能自动的对markdown文本进行渲染成htmlhtml输入框持…

性能提升20%,字节跳动HTTPDNS从中心下沉到边缘

摘要&#xff1a;本文介绍了HTTPDNS服务从中心迁移至边缘详细的落地过程。主要内容为&#xff1a; HTTPDNS下沉边缘实践遇到的挑战&#xff0c;包括服务放置、流量调度 HTTPDNS下沉边缘解决方案 从性能、成本出发&#xff0c;谈谈HTTPDNS下沉边缘后的收益 传统的DNS流程中…

Python的语法糖及其进化,带范例

话说python也算是多年媳妇熬成婆的典范了。 1&#xff09;3.6以后引入的f-格式化字符串&#xff0c;现在写代码更像写小作文了&#xff0c;而且折行顺眼多了。 print(f"""Hello, {"World".upper()}""") 2&#xff09;3.5以后引入的:…