问题1:[[UIDevice currentDevice] identifierForVendor].UUIDString什么情况下值会变化?

[[UIDevice currentDevice] identifierForVendor].UUIDString 是一个用于标识设备的唯一标识符(UUID),针对同一应用程序供应商(即同一开发者的应用程序集合),在设备上不变。然而,有一些情况会导致这个标识符发生变化:

情况导致 identifierForVendor 变化:

  1. 应用卸载和重装:当设备上来自同一供应商的所有应用程序都被卸载,再重新安装任意一个应用程序时,会生成新的 identifierForVendor。这意味着,如果用户完全清除你的应用并重新安装,它会获得一个新值。

  2. 设备恢复出厂设置:如果设备被恢复出厂设置,也会生成新的 identifierForVendor

除此之外,identifierForVendor 不会因为设备上的通常操作(如重启设备、软件更新等)而改变。

存储到 Keychain 的优势

Keychain 是一个安全存储敏感信息的系统级服务,适用于存储比如密码、证书和加密密钥等重要数据。把 identifierForVendor 存储到 Keychain 有一些优势:

  1. 持久性:即使用户删除了应用,Keychain 中存储的数据不会被删除。当用户重新安装应用时,可以从 Keychain 中恢复数据。
  2. 安全性:Keychain 提供了高安全性的存储方式,对敏感数据的保护比普通的文件存储要好得多。
  3. 跨应用共享:在适当的配置下,同一供应商的应用程序可以共享 Keychain 中的数据。

下面是将 identifierForVendor 存储到 Keychain 的示例代码:

#import <Security/Security.h>

- (void)storeIdentifierForVendorInKeychain {
NSString *uuid = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
NSString *key = @"com.yourcompany.yourapp.identifierForVendor"; // 删除之前存储的 UUID
[self deleteUUIDFromKeychain:key]; NSData *uuidData = [uuid dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *query = @{
(id)kSecClass: (id)kSecClassGenericPassword,
(id)kSecAttrAccount: key,
(id)kSecValueData: uuidData,
}; OSStatus status = SecItemAdd((CFDictionaryRef)query, NULL);
if (status == errSecSuccess) {
NSLog(@"UUID stored successfully.");
} else {
NSLog(@"Error storing UUID: %d", (int)status);
}
} - (NSString *)retrieveUUIDFromKeychain {
NSString *key = @"com.yourcompany.yourapp.identifierForVendor"; NSDictionary *query = @{
(id)kSecClass: (id)kSecClassGenericPassword,
(id)kSecAttrAccount: key,
(id)kSecReturnData: (id)kCFBooleanTrue,
}; CFDataRef dataRef = NULL;
OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&dataRef); if (status == errSecSuccess) {
NSData *resultData = (__bridge NSData *)dataRef;
NSString *uuid = [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
CFRelease(dataRef);
return uuid;
} else {
NSLog(@"Error retrieving UUID: %d", (int)status);
return nil;
}
} - (void)deleteUUIDFromKeychain:(NSString *)key {
NSDictionary *query = @{
(id)kSecClass: (id)kSecClassGenericPassword,
(id)kSecAttrAccount: key,
}; OSStatus status = SecItemDelete((CFDictionaryRef)query);
if (status == errSecSuccess) {
NSLog(@"UUID deleted successfully.");
} else {
NSLog(@"Error deleting UUID: %d", (int)status);
}
}

步骤:

  1. 存储 UUID:使用 storeIdentifierForVendorInKeychain 方法将 identifierForVendor 存储到 Keychain 中。
  2. 检索 UUID:使用 retrieveUUIDFromKeychain 方法从 Keychain 中检索存储的 UUID。
  3. 删除 UUID:使用 deleteUUIDFromKeychain 方法删除存储的 UUID。

通过这些步骤和方法,你可以确保即使应用被删除和重新安装,也可以从 Keychain 中恢复先前的 identifierForVendor,保持UUID的一致性。

问题2:存储到 Keychain,什么情况下值会变化 ?

存储在 Keychain 中的数据通常在一些特定情况下会发生变化。以下是其中一些主要情形:

1. 恢复出厂设置

恢复出厂设置会清除设备上的所有数据,包括应用数据、用户文件、系统设置和 Keychain 数据。在这种情况下,Keychain 中存储的任何值(例如标识符、密码等)都会被删除并且无法恢复。

2. 刷机

刷机通常指的是重新安装设备的固件或操作系统。刷机过程也会清除设备上的所有数据,包括 Keychain 中的数据。因此,存储在 Keychain 中的值会被删除。

3. 应用被卸载

不同于普通的文件存储,Keychain 中的数据在应用被卸载时不会被删除。当应用重新安装时,可以继续访问先前存储的 Keychain 数据。然而,如果用户选择了“删除应用的数据”或使用特定第三方工具清理 Keychain 数据,相关的存储值可能会被删除。

4. 设备迁移

在某些情况下,通过 iCloud 备份或设备迁移将 Keychain 数据同步到新设备上。如果用户选择没有迁移 Keychain 数据(例如,设备迁移时选择了不备份 Keychain),那么新设备中的值会发生变化或丢失。

5. 越狱设备

越狱会增加 Keychain 数据被第三方工具访问、修改或删除的风险。尽管越狱本身不会直接改变 Keychain 中的值,但越狱后的应用和操作可能影响其数据完整性,可能导致 Keychain 数据被篡改或清除。

6. 应用自身操作

如果应用在某些条件下(如用户登出、换新账户、重装等)主动删除或更新 Keychain 中的数据,也会导致相关值发生变化。例如:

- (void)deleteIdentifierInKeychain {
NSString *key = @"com.yourcompany.yourapp.identifierForVendor";
NSDictionary *query = @{
(id)kSecClass: (id)kSecClassGenericPassword,
(id)kSecAttrAccount: key,
}; OSStatus status = SecItemDelete((CFDictionaryRef)query);
if (status == errSecSuccess) {
NSLog(@"UUID deleted successfully.");
} else {
NSLog(@"Error deleting UUID: %d", (int)status);
}
}

7. 用户主动清除 Keychain

用户可以通过某些工具或设置,主动选择清除特定的 Keychain 数据,这样会导致存储值的删除或变化。

常见问题:

  • 卸载和重新安装应用

    • 不恢复出厂设置:重装应用通常不会影响 Keychain 数据。
    • 恢复出厂设置或重置所有设置:Keychain 数据会被删除。
  • 设备切换

    • 如果用户在设备切换过程中未备份或恢复 Keychain 数据,新的 Keychain 数据将重新生成。

简而言之,尽管 Keychain 存储提供了一种相对持久的存储机制,在以下情况下存储值可能会发生变化或被清除:

  1. 恢复出厂设置或刷机。
  2. 设备迁移而未同步 Keychain 数据。
  3. 越狱引起的数据篡改或清除。
  4. 应用自身操作或用户主动清除 Keychain 数据。

iOS开发基础149-由UUIDString引发的思考的更多相关文章

  1. IOS开发基础知识碎片-导航

    1:IOS开发基础知识--碎片1 a:NSString与NSInteger的互换 b:Objective-c中集合里面不能存放基础类型,比如int string float等,只能把它们转化成对象才可 ...

  2. iOS开发——总结篇&IOS开发基础知识

    IOS开发基础知识 1:Objective-C语法之动态类型(isKindOfClass, isMemberOfClass,id) 对象在运行时获取其类型的能力称为内省.内省可以有多种方法实现. 判断 ...

  3. IOS开发基础环境搭建

    一.目的 本文的目的是windows下IOS开发基础环境搭建做了对应的介绍,大家可根据文档步骤进行mac环境部署: 二.安装虚拟机 下载虚拟机安装文件绿色版,点击如下文件安装 获取安装包:       ...

  4. iOS开发基础-九宫格坐标(6)

    继续对iOS开发基础-九宫格坐标(5)中的代码进行优化. 优化思路:把字典转模型部分的数据处理操作也拿到模型类中去实现,即将 ViewController 类实现中 apps 方法搬到 WJQAppI ...

  5. iOS开发基础-九宫格坐标(5)

    继续在iOS开发基础-九宫格坐标(4)的基础上进行优化. 一.改进思路 1)iOS开发基础-九宫格坐标(4)中 viewDidLoad 方法中的第21.22行对控件属性的设置能否拿到视图类 WJQAp ...

  6. iOS开发基础-九宫格坐标(4)

    对iOS开发基础-九宫格坐标(3)的代码进行进一步优化. 新建一个 UIView 的子类,并命名为 WJQAppView ,将 appxib.xib 中的 UIView 对象与新建的视图类进行关联. ...

  7. iOS开发基础-九宫格坐标(3)之Xib

    延续iOS开发基础-九宫格坐标(2)的内容,对其进行部分修改. 本部分采用 Xib 文件来创建用于显示图片的 UIView 对象. 一.简单介绍  Xib 和 storyboard 的比较: 1) X ...

  8. iOS开发基础-九宫格坐标(2)之模型

    在iOS开发基础-九宫格(1)中,属性变量 apps 是从plist文件中加载数据的,在 viewDidLoad 方法中的第20行.26行中,直接通过字典的键名来获取相应的信息,使得 ViewCont ...

  9. iOS开发基础-图片切换(4)之懒加载

    延续:iOS开发基础-图片切换(3),对(3)里面的代码用懒加载进行改善. 一.懒加载基本内容 懒加载(延迟加载):即在需要的时候才加载,修改属性的 getter 方法. 注意:懒加载时一定要先判断该 ...

  10. iOS开发基础-图片切换(3)之属性列表

    延续:iOS开发基础-图片切换(2),对(2)里面的代码用属性列表plist进行改善. 新建 Property List 命名为 Data 获得一个后缀为 .plist 的文件. 按如图修改刚创建的文 ...

随机推荐

  1. Kotlin 编程语言详解:特点、应用领域及语法教程

    什么是 Kotlin? Kotlin 是一种现代.流行的编程语言,由 JetBrains 在 2016 年发布. 自发布以来,它已经变得非常流行,因为它与 Java 兼容(Java 是目前最流行的编程 ...

  2. 同时开启firewall和iptables

    使用向导 With the iptables service, every single change means flushing all the old rules and reading all ...

  3. 算法金 | 没有思考过 Embedding,不足以谈 AI

    大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」 抱个拳,送个礼 在当今的人工智能(AI)领域,Embedding 是一个不可或缺的概念 ...

  4. mysql查看用户的过期时间

    1. mysql查看用户的过期时间的方法 在MySQL中,用户的过期时间(也称为账户过期日期)是一个可选项,用于确定某个MySQL用户账户何时到期.但是,值得注意的是,并非所有的MySQL安装或版本都 ...

  5. docker配置域名

    先运行docker镜像 # 进入 docker 容器 mynginx 是容器名 docker exec -i -t mynginx /bin/bash #安装vim apt-get install v ...

  6. 嵌入式进阶之关于SPI通信的案例分享——基于全志科技T3与Xilinx Spartan-6处理器

    本文主要介绍基于全志科技T3与Xilinx Spartan-6的通信案例. 适用开发环境: Windows开发环境:Windows 7 64bit.Windows 10 64bit Linux开发环境 ...

  7. 算法金 | 致敬深度学习三巨头:不愧是腾讯,LeNet问的巨细。。。

    ​ 大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」 抱个拳,送个礼 读者参加面试,竟然在 LeNet 这个基础算法上被吊打~ LeNe ...

  8. CF1864C 题解

    \(x = 2^k\) 是好做的,每次以 \(2^{k-1}\) 为因数即可. 对于其他情况,考虑每次让 \(x\) 减去其二进制下最低位的 \(1\) 直至变成 \(2^k\). 这种策略下显然每个 ...

  9. python执行shell并获取结果

    在Python中执行Shell命令并获取其结果,通常可以使用subprocess模块.这个模块允许我们启动新的进程,连接到它们的输入/输出/错误管道,并获取它们的返回码.下面是一个详细的示例,展示了如 ...

  10. cgroup限制进程cpu

    编写一个死循环脚本 [root@workstation ~]# cat circle.sh #!/bin/bash a=1 while true do let a++ done 查看top 使用cgr ...