iOS开发笔记之九十六——本地Data Persistence总结笔记

news2024/11/16 14:22:28

本质上来说,不管是哪种缓存方式最终都会以文件的形式存储在磁盘上,只不过上层进行了某种“封装”或“抽象”,所以还是做了分类,目前iOS本地持久化缓存(Storage/Persistence)有以下几种形式:

  • UserDefaults

  • 文件缓存

  • Keychain

  • Core Data

  • 数据库(SQLite)

注意,这里讨论的只是持久化缓存,如果单纯地讨论缓存,严格地说,应该涉及类似NSCache、NSURLCache等等一些列的内存缓存也应该考虑在内。下面我们将从原理、示例代码、注意事项等方面来介绍这些缓存机制。

UserDefaults

UserDefaults是iOS中一种常见的轻量级缓存机制,它可以用来存储应用程序的配置信息、用户偏好设置、临时缓存数据等。

原理说明:

UserDefaults使用plist文件来进行存储,它将缓存的数据以key-value的形式保存在文件中。这个文件被存储在应用程序沙盒中的Library/Preferences目录下,并且是由系统自动管理的。

示例代码:

UserDefaults是单例对象,我们可以通过它的shared实例来访问它。下面是一个使用UserDefaults进行存储和读取的示例代码:

// 存储数据
UserDefaults.standard.set("hello", forKey: "greeting")

// 读取数据
let greeting = UserDefaults.standard.string(forKey: "greeting")
print(greeting)

注意事项:

  1. UserDefaults只能存储基本数据类型和部分Foundation框架中的对象类型,如NSString、NSNumber、NSArray、NSDictionary等,不支持存储自定义对象类型。

  1. 由于UserDefaults的存储数据是通过plist文件进行保存的,所以对于需要频繁写入的数据,最好使用更高效的存储方式,比如Core Data、SQLite等。

  1. 在使用UserDefaults存储敏感数据时,需要进行加密处理,以确保数据安全性。

总结:

UserDefaults是iOS中常见的轻量级缓存机制,它使用plist文件来进行存储,支持存储基本数据类型和部分Foundation框架中的对象类型,使用方便简单,但需要注意存储数据类型的限制和数据安全性问题。

文件缓存

文件缓存机制也是一种常见的缓存方式。

原理说明:

它是一种将应用程序的数据永久地保存在本地文件系统中的方法,以便于下次启动应用程序时能够快速地读取数据。这种缓存机制的原理是将数据保存到应用程序的沙盒目录中,并在应用程序下一次启动时读取该数据。

示例代码:

使用文件持久化缓存机制需要使用iOS中的文件系统API,例如NSFileManager和NSFileHandle等类。这些类提供了对文件系统的基本操作,如创建、删除、移动和读写文件等。

以下是一个使用文件持久化缓存机制的示例代码:

// 获取应用程序的沙盒目录
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!

// 设置要保存的数据
let data = "Hello, world!".data(using: .utf8)

// 保存数据到文件中
let fileURL = documentsDirectory.appendingPathComponent("cache.txt")
do {
    try data?.write(to: fileURL)
} catch {
    print("Error writing to file: \(error)")
}

// 从文件中读取数据
do {
    let cachedData = try Data(contentsOf: fileURL)
    let cachedString = String(data: cachedData, encoding: .utf8)
    print("Cached string: \(cachedString)")
} catch {
    print("Error reading from file: \(error)")
}

使用文件持久化缓存机制需要注意以下几点:

  1. 应该尽量避免保存大量的数据到本地文件系统中,因为这会占用设备的存储空间。

  1. 对于敏感数据,应该使用加密算法来保护数据的安全。

  1. 应该定期清理缓存文件,以避免缓存文件过多导致设备存储空间不足。

  1. 应该注意处理文件读写时的错误,以避免程序崩溃或数据丢失的情况。

另外,文件缓存的还有一种特殊的但是也常用到的方式,就是KeyedArchiver。

KeyedArchiver

用于将对象序列化为二进制数据,并将其写入到文件中进行缓存。KeyedArchiver提供了一种便捷的方法,让开发者能够将自定义对象序列化为二进制数据,并将其保存到文件系统中,以便于以后从文件中读取数据。

以下是KeyedArchiver的使用方法:

  1. 实现NSCoding协议

首先,需要在自定义对象中实现NSCoding协议,以便KeyedArchiver能够将对象序列化为二进制数据。该协议包括encode和init(coder:)两个方法,分别用于将对象序列化为二进制数据和从二进制数据反序列化为对象。

class Person: NSObject, NSCoding {
    var name: String
    var age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }

    func encode(with coder: NSCoder) {
        coder.encode(name, forKey: "name")
        coder.encode(age, forKey: "age")
    }

    required init?(coder: NSCoder) {
        name = coder.decodeObject(forKey: "name") as? String ?? ""
        age = coder.decodeInteger(forKey: "age")
    }
}
  1. 缓存对象

接下来,使用KeyedArchiver将自定义对象序列化为二进制数据,并将其写入到文件中进行缓存。

let person = Person(name: "Tom", age: 20)

// 获取文件路径
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let filePath = path + "/person.archive"

// 将对象序列化为二进制数据并写入文件
let data = NSKeyedArchiver.archivedData(withRootObject: person)
try? data.write(to: URL(fileURLWithPath: filePath))
  1. 从缓存中读取对象

// 从文件中读取二进制数据并反序列化为对象
let data = try? Data(contentsOf: URL(fileURLWithPath: filePath))
let cachedPerson = NSKeyedUnarchiver.unarchiveObject(with: data!) as? Person

print("Name: \(cachedPerson?.name ?? "")")
print("Age: \(cachedPerson?.age ?? 0)")

使用KeyedArchiver时需要注意以下几点:

  1. 要对自定义对象实现NSCoding协议中的encode和init(coder:)方法,以便KeyedArchiver能够将对象序列化为二进制数据。

  1. KeyedArchiver会将对象序列化为二进制数据,因此需要注意内存消耗问题。

  1. 对于一些敏感数据,需要考虑数据的安全性。可以使用加密算法保护数据的安全。

  1. 应该注意处理文件读写时的错误,以避免程序崩溃或数据丢失的情况。

Keychain

Keychain是一种iOS的持久化缓存机制,也是iOS中安全框架的一部分,提供了用于以安全方式存储和检索数据的API。

原理说明:

Keychain中的数据存储在受保护的系统区域中,它是完全隔离的,不同的应用程序之间无法共享数据。每个应用程序都有自己的Keychain,它只能访问自己的数据,而无法访问其他应用程序的数据。这种隔离性保证了Keychain存储的安全性。

它可以保证在应用程序启动和设备重启之间安全地存储和检索敏感数据。它使用加密的方式存储数据,如密码、加密密钥和其他凭证,以便其他应用程序和系统无法访问这些数据。

对于每一个应用来说,KeyChain都有两个访问区,私有区公共区私有区是一个Sandbox,本程序存储的任何数据都对其他程序不可见,其他应用程序无法访问该区数据。使用Keychain API,可以通过键值对存储数据,并使用服务名称和账户名称对其进行标识,这样可以保证数据是与应用程序相关联的,并且只能由拥有相应服务名称和账户名称的应用程序访问。

如果要想将存储的内容放在公共区,实现多个应用程序间可以共同访问一些数据,则可以先声明公共区的名称,官方文档管这个名称叫“keychain access group”。

使用示例:

以下是Keychain的使用方法和示例代码(Swift):

  1. 导入Security框架

在使用Keychain之前,需要导入Security框架。

import Security
  1. 存储数据

使用SecItemAdd方法将数据存储到Keychain中。

let password = "123456"
let data = password.data(using: .utf8)!
let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
                            kSecAttrAccount as String: "MyPassword",
                            kSecValueData as String: data]

let status = SecItemAdd(query as CFDictionary, nil)

if status == errSecSuccess {
    print("Password saved to Keychain.")
} else {
    print("Failed to save password to Keychain.")
}

在上面的代码中,我们将字符串密码转换为二进制数据,并将其存储到Keychain中。kSecClass表示存储的数据类型,kSecAttrAccount是用来标识存储数据的名称,kSecValueData则是存储的二进制数据。

  1. 读取数据

使用SecItemCopyMatching方法从Keychain中读取数据。

let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
                            kSecAttrAccount as String: "MyPassword",
                            kSecReturnData as String: kCFBooleanTrue!,
                            kSecMatchLimit as String: kSecMatchLimitOne]

var dataTypeRef: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &dataTypeRef)

if status == errSecSuccess {
    if let retrievedData = dataTypeRef as? Data,
        let password = String(data: retrievedData, encoding: .utf8) {
        print("Retrieved password from Keychain: \(password)")
    } else {
        print("Failed to retrieve password from Keychain.")
    }
} else {
    print("Failed to retrieve password from Keychain.")
}

在上面的代码中,我们使用kSecReturnData来表示返回存储的二进制数据,使用kSecMatchLimit来表示返回数据的数量,这里我们只需要返回一个结果,所以指定为kSecMatchLimitOne。

使用Keychain时需要注意以下几点:

  1. 应该限制对Keychain的访问权限,并确保只有授权的用户能够访问Keychain中的数据。

  1. Keychain中存储的数据是加密的,因此无法从外部访问它们。如果数据需要与其他应用程序共享,则可以通过group方式,让程序可以在App间共享,不过得要相同TeamID。

  1. Keychain中数据并不存放在App的Sandbox中,即使删除了App,资料依然保存在keychain中。如果重新安装了app,还可以从keychain获取数据。

  1. Keychain是一种安全的存储机制,但并不是完美的。例如,越狱的设备就可以访问Keychain存储的数据。因此,不应在Keychain中存储高度敏感的数据。因此仍然需要谨慎地使用和存储敏感信息。

  1. 在处理Keychain时,应该注意处理可能出现的错误,以避免程序崩溃或数据丢失的情况。

Apple针对keychain也提供了丰富的开发文档说明,包括有Keychain Services Programming Guide:文章中包含了使用mac和ios的keychain开发。

Core Data

Core Data是苹果提供的一种数据管理框架,它提供了一种方便的方式来管理和操作应用程序中的数据。其中最重要的特性就是持久化存储,也就是将数据存储在本地文件中,以便下一次应用程序启动时可以继续使用。

原理说明:

在Core Data中,持久化存储的实现是通过使用SQLite数据库来完成的。SQLite是一种轻量级的嵌入式数据库,可以轻松地嵌入到应用程序中,提供了一种高效、可靠的数据存储方式。

使用示例:

使用Core Data进行持久化存储需要进行以下步骤:

  1. 定义数据模型:在Xcode中创建一个数据模型文件,用于定义数据的实体、属性和关系等。

  1. 创建Core Data栈:使用NSPersistentContainer类创建Core Data栈,包括托管对象上下文、持久化存储协调器等组件。

  1. 存储和读取数据:使用NSManagedObjectContext类操作托管对象上下文,通过操作实体和属性等元素进行数据存储和读取。

下面是一个简单的Swift代码示例,演示如何使用Core Data进行数据存储:

// 创建Core Data栈
let container = NSPersistentContainer(name: "DataModel")
container.loadPersistentStores { _, error in
    if let error = error {
        print("Failed to load persistent stores: \(error)")
        return
    }
}

// 创建一个托管对象上下文
let context = container.viewContext

// 创建一个Person实体对象
let person = NSEntityDescription.insertNewObject(forEntityName: "Person", into: context) as! Person
person.name = "Tom"
person.age = 30

// 保存数据到持久化存储
do {
    try context.save()
} catch {
    print("Failed to save context: \(error)")
}

// 从持久化存储中读取数据
let fetchRequest: NSFetchRequest<Person> = Person.fetchRequest()
do {
    let persons = try context.fetch(fetchRequest)
    for person in persons {
        print("Name: \(person.name!), Age: \(person.age)")
    }
} catch {
    print("Failed to fetch persons: \(error)")
}

在使用Core Data进行持久化存储时,需要注意以下几点:

  1. 定义数据模型时,应该尽可能地保持简单。复杂的数据模型会导致数据库操作变得缓慢,并且会增加代码的复杂性。

  1. Core Data提供了多种持久化存储方式,如SQLite、二进制文件、XML文件等。开发者需要根据具体需求选择合适的存储方式。

  1. Core Data是一种线程安全的框架,但是多线程编程仍然需要注意线程安全问题。建议在每个线程中创建独立的托管对象上下文。

总之,Core Data是iOS中一种强大的持久化存。

SQLite

iOS中,SQLite是一种轻量级的数据库引擎,被广泛用于持久化存储。SQLite使用文件作为数据存储介质,通过对数据进行编码和解码实现对数据的存储和读取。在iOS中,SQLite被用于开发本地应用,以存储大量结构化数据。

原理说明

SQLite是一种基于磁盘的关系型数据库,支持SQL语言操作。SQLite通过一个单一的文件存储所有的数据,这个文件可以被轻松地复制、备份和传输。SQLite的特点是占用内存极少、速度快,适合移动设备等资源受限的环境。

使用方法

使用SQLite持久化缓存需要进行以下步骤:

  1. 导入SQLite库:在项目中导入SQLite库,可以使用CocoaPods或手动导入。

  1. 创建数据库:通过SQLite库提供的API创建数据库文件。如果数据库文件已经存在,可以直接打开,否则可以使用SQL语句创建数据库文件。

  1. 创建表格:使用SQL语句创建表格,并为表格定义字段类型和约束。

  1. 执行SQL语句:通过SQLite提供的API执行SQL语句,对表格进行增删改查操作。

  1. 关闭数据库:在应用程序退出或不再使用数据库时,需要关闭数据库,释放资源。

示例代码

以下是一个使用SQLite进行数据存储的示例代码,其中使用了Swift的SQLite.swift库:

// 导入SQLite.swift库
import SQLite

// 打开数据库连接
let db = try! Connection("path/to/database.sqlite3")

// 定义数据表
let users = Table("users")
let id = Expression<Int64>("id")
let name = Expression<String>("name")
let email = Expression<String>("email")

// 创建表格
try! db.run(users.create { t in
    t.column(id, primaryKey: true)
    t.column(name)
    t.column(email, unique: true)
})

// 插入数据
let insert = users.insert(name <- "Alice", email <- "alice@example.com")
try! db.run(insert)

// 查询数据
for user in try! db.prepare(users) {
    print("id: \(user[id]), name: \(user[name]), email: \(user[email])")
}

// 更新数据
let alice = users.filter(name == "Alice")
try! db.run(alice.update(email <- "alice@example.org"))

// 删除数据
try! db.run(alice.delete())

// 关闭数据库连接
db.close()

注意事项:

在使用SQLite持久化缓存时,需要注意以下事项:

  1. 需要手动编写SQL语句进行数据操作,对于不熟悉SQL语言的开发者来说可能会有一定难度。

  1. 在进行数据操作时需要保证线程安全,可以使用SQLite提供的事务机制进行数据操作,避免数据损坏或丢失。

  1. SQLite的数据库文件可以被轻松地复制、备份和传输,需要注意数据安全问题。

总结

经过以上介绍,我们统一总结下,如下:

  1. UserDefaults

UserDefaults是轻量级的持久化存储方式,适用于存储一些简单的配置信息或用户偏好设置。它的优点在于简单易用,无需考虑数据模型和数据迁移等问题。但是它的缺点在于只能存储一些基本数据类型,对于复杂的数据结构无法支持。

最佳应用场景:适合存储少量的简单配置信息或用户偏好设置。

  1. 文件缓存

文件缓存可以将数据以文件形式存储在本地文件系统中,适用于存储较大的数据,如图片、视频等。它的优点在于可以灵活地控制缓存策略和缓存大小,可以有效地减轻服务器负载,提高用户体验。但是它的缺点在于需要手动管理缓存,包括缓存路径、缓存文件名、缓存过期时间等,一旦管理不当,可能会导致缓存文件过多,浪费存储空间。

最佳应用场景:适合存储大量的非敏感数据,如图片、音频、视频(SDWebImage)等。

  1. Keychain

Keychain是一种安全的存储方式,可以将敏感信息(如用户密码、密钥等)加密后存储在系统中,保证数据的安全性。它的优点在于可以保护敏感信息不被恶意获取,同时也提供了方便的API来管理这些敏感信息。但是它的缺点在于只能存储较小的数据,不适合存储大量的数据。

最佳应用场景:适合存储敏感信息,如用户密码、密钥等。

  1. Core Data

Core Data是一种ORM(对象关系映射)框架,可以将数据存储在SQLite数据库中。它的优点在于可以很方便地管理数据模型,同时提供了强大的查询、排序、过滤等功能,非常适合存储复杂的数据结构。但是它的缺点在于学习曲线较陡峭,需要理解Core Data的一些概念和API,同时也需要考虑数据模型的迁移等问题。

最佳应用场景:适合存储复杂的数据结构,如联系人、音乐播放列表、日历事件等。

  1. 数据库(SQLite)

数据库是一种通用的存储方式,可以存储任意类型的数据,同时也提供了丰富的查询、排序、过滤等功能。但是一般情况下,我们更倾向于在一些需要复杂存储与查询的场景中使用它。例如联系人、音乐播放列表等。

关注以下公众号,可与作者直接沟通,后续也会有更多文章更新:

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

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

相关文章

vTESTstudio - VT System CAPL Functions - VT2004(续1)

成熟,就是某一个突如其来的时刻,把你的骄傲狠狠的踩到地上,任其开成花或者烂成泥。vtsStartStimulation - 启动激励输出功能&#xff1a;自动激励输出注意&#xff1a;在启动激励输出之前&#xff0c;一定要设置好输出模式Target&#xff1a;目标通道变量空间名称&#xff0c;例…

TLB内存页表 - LoongArch

TLB内存页表 - LoongArch 文章目录TLB内存页表 - LoongArch页表操作指令TLB相关寄存器页表格式CpuSetAttributesUEFI Memory attribute页表操作指令 LDDIR: 用于软件页表遍历过程中目录项的访问. LDPTE: 用于在软件页表遍历过程中页表项的访问. INVTLB: 用于无效TLB中的内容. …

Mybatis源码分析:Mybatis的数据存储对象

前言&#xff1a;SQLSession是对JDBC的封装 一&#xff1a;SQLSession和JDBC的对照说明 左边是我们的客户端程序&#xff0c;右边是我们的MySQL数据仓&#xff0c;或者叫MySQL实例 Mybatis是对JDBC的封装&#xff0c;将JDBC封装成了一个核心的SQLSession对象 JDBC当中的核心对…

2023年浙江理工大学MBA招生考试初试成绩查询及复查的通知

根据往年的情况&#xff0c;2023浙江理工大学MBA考试初试成绩可能将于2月21日下午两点公布&#xff0c;为了广大考生可以及时查询到自己的分数&#xff0c;杭州达立易考教育为大家汇总了信息。 一、成绩查询考生可登录中国研究生招生信息网“全国硕士研究生招生考试初试成绩查询…

二十四节气—雨水,好雨知时节,当春乃发生。

雨水&#xff0c;是二十四节气之第2个节气。 雨水节气不仅表明降雨的开始及雨量增多&#xff0c;而且表示气温的升高&#xff0c;意味着进入气象意义的春天。 雨水节是一个非常富有想象力和人情味的节气&#xff0c;在这一天&#xff0c;不管下不下雨都充满着一种雨意蒙蒙的诗…

nps内网穿透工具

一、准备一台有公网ip的服务器 https://github.com/ehang-io/nps/releases 在这个地址下载服务端的安装包&#xff0c;centos的下载这个 上传到服务器上。 二、然后解压&#xff0c;安装&#xff0c;启动 [rootadministrator ~]# tar xzvf linux_amd64_server.tar.gz [roo…

【C语言】预编译

&#x1f6a9;write in front&#x1f6a9; &#x1f50e;大家好&#xff0c;我是謓泽&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f3c5;2021年度博客之星物联网与嵌入式开发TOP5&#xff5…

[架构之路-110]-《软考-系统架构设计师》-软件架构设计-3-架构描述语言ADL与UML

前言&#xff1a;第3节 架构描述语言ADL3.1 ADL概述3.1.1 什么是ADLADL&#xff0c;即架构描述语言(Architecture Description Language)。两个重要的团体在使用架构描述语言术语。它们是&#xff1a;软件工程团体企业建模和工程团体。在软件工程团体&#xff0c;架构描述语言&…

Jvm -堆对象的划分

堆对于一个jvm进程来说是唯一的&#xff0c;一个进程只有一个jvm&#xff0c;但是进程半酣多个线程&#xff0c;多个线程共享一个堆。 也就是说&#xff0c;一个jvm实例只存在一个堆&#xff0c;同时对也是Java内存管理的核心区域。 Java堆区域的大小在jvm启动时就已经被确定…

基于springboot+vue的儿科保健计划免疫系统

基于springbootvue的儿科保健计划免疫系统 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背…

HDMI协议介绍

HDMI全称&#xff08;High Definition Multimedia Interface&#xff09;高清多媒体接口&#xff0c;支持在单线缆上传输全数字高清视频和多声道音频。 HDMI基于TMDS协议传输&#xff0c;主要用于DVD, 机顶盒等音视频source到TV&#xff0c;显示器等sink设备的传输。HDMI向下兼…

SpringBoot学习笔记:SpringBoot集成JPA-01

文章目录概述JPA的优点在Springboot中集成步骤1.新建springboot项目步骤2.引入相关jar包&#xff0c;pom.xml文件如下:步骤3. 配置文件application.properties设置步骤4. 定义表的ORM对象类步骤5. 实现数据库操作接口(Dao)步骤6. 实现Controller测试概述 JPA是一种规范&#x…

PHP学习笔记(一谦四益)

前言 上一篇文章 PHP学习笔记&#xff08;观隅反三&#xff09;分享了数组的知识&#xff0c;这篇文章接着分享和数组相关的算法。 算法效率 算法效率分为两种&#xff1a;第一种是时间效率&#xff0c;第二种是空间效率。时间效率被称为时间复杂度&#xff0c;而空间效率被称…

SpringSecurity认证

文章目录登陆校验流程依赖yaml实现建表、工具类、实体类加密器、AuthenticationManager登录逻辑登录过滤器、配置过滤器登出登陆校验流程 认证 登录&#xff1a; ​ ①自定义登录接口 ​ 调用ProviderManager的方法进行认证 如果认证通过生成token&#xff0c;根据userId把用…

国密SM2算法(JS加密,C#、Java解密)

常见的渗透测试会将网站登录时密码使用明文传输视为风险。推荐使用国密算法或者RSA算法对密码进行加密传输。 RSA加密&#xff08;JS加密&#xff0c;C#、Java解密&#xff09;请参考《RSA对称加密&#xff08;JS加密&#xff0c;C#、Java解密&#xff09;》​​​​​​ 本文…

数据的进制转换以及算术逻辑运算

1.数据的进制转化 进制的表示&#xff1a;二进制、十六进制&#xff0c;二进制符号位0b&#xff0c;一般表示为0b0011&#xff0c;十六进制符号位0x或H&#xff0c;可以表示为0x18F或18FR进制整数转十进制&#xff1a;位权展开法&#xff0c;用R进制数的每一位乘以R的n次方&am…

C++——二叉树排序树

文章目录1 二叉搜索树概念2 二叉搜索树操作与模拟实现2.1 二叉搜索树的查找非递归版本递归版本2.2 二叉搜索树的插入非递归版本递归版本2.3 二叉搜索树的删除非递归版本递归版本3 二叉搜索树的应用&#xff08;K模型、KV模型&#xff09;4 二叉搜索树的性能分析1 二叉搜索树概念…

Go语言设计与实现 -- 反射

Go的反射有哪些应用&#xff1f; IDE中代码的自动补全对象序列化fmt函数的相关实现ORM框架 什么情况下需要使用反射&#xff1f; 不能明确函数调用哪个接口&#xff0c;需要根据传入的参数在运行时决定。不能明确传入函数的参数类型&#xff0c;需要在运行时处理任意对象。 …

1.TCP、UDP区别、TCP/IP七层、四层模型、应用层协议(计网)

文章目录1.OSI 七层模型是什么&#xff1f;每一层的作用是什么&#xff1f;2.TCP/IP 四层模型是什么&#xff1f;每一层的作用是什么&#xff1f;应用层&#xff08;Application layer&#xff09;传输层&#xff08;Transport layer&#xff09;网络层&#xff08;Network lay…

百度工程师带你探秘C++内存管理

一、概述 ptmalloc是开源GNU C Library(glibc)默认的内存管理器&#xff0c;当前大部分Linux服务端程序使用的是ptmalloc提供的malloc/free系列函数&#xff0c;而它在性能上远差于Meta的jemalloc和Google的tcmalloc。服务端程序调用ptmalloc提供的malloc/free函数申请和释放内…