iOS问题记录 - Xcode 15安装低版本iOS模拟器(持续更新)

news2024/12/28 5:16:12

文章目录

  • 前言
  • 开发环境
  • 问题描述
  • 问题分析
    • 1. 定位问题
    • 2. 逆向分析
      • 2.1. IDA Free
      • 2.2. Hopper Disassembler Demo
    • 3. 模拟器日志
    • 4. supportedArchs
  • 解决方案
  • 最后


前言

最近新需求很多,项目改动很大,开发完成后想测一遍在低版本iOS系统上的兼容性,没想到低版本的iOS模拟器设备突然无法创建了。

在去年年底我研究过这个问题,写下了这篇文章iOS问题记录 - Xcode 14安装低版本iOS模拟器(持续更新),虽然当时没有完全解决,但暂时也够用,没想到现在这个问题又出现了。如果还没有阅读过这篇文章,强烈建议先阅读这篇前置文章。

这里先说明一下,虽然标题是Xcode 15安装低版本iOS模拟器,但是在遇到这个问题时Xcode 15还处于Beta版,平时还是以Xcode 14.3.1版本为主,至于标题中为什么用Xcode 15,请继续往下看。

开发环境

  • macOS: 13.4
  • Xcode: 14.3.1 / 15 beta 5

问题描述

在Xcode 14.3.1版本中,低版本iOS模拟器文件已经修改了Info.plist文件中的CFBundleIdentifier属性值,但是创建iOS模拟器的时候却还是无法选择。从官网重新下载Xcode 14.0.1版本创建低版本iOS模拟器,还是无法选择无法创建,最低只能创建iOS 14.0.1模拟器。

问题分析

1. 定位问题

首先怀疑是不是Xcode 14.3.1版本又加了其他限制,导致原先的方法失效。找了一台打包机,将Xcode版本升到14.3.1,尝试创建低版本iOS模拟器,一切正常!这是怎么回事?

这就不得不提CoreSimulator框架,文件位于/Library/Developer/PrivateFrameworks/CoreSimulator.framework,Xcode的模拟器管理靠它来实现。现在Xcode版本一致,却出现一个正常一个不正常,难道是CoreSimulator框架版本不一致?

查看CoreSimulator框架版本的两种方法:

  • 通过命令查看
xcrun simctl --version

执行输出:

@(#)PROGRAM:simctl  PROJECT:CoreSimulator-917

simctl是用于管理和控制模拟器的命令行工具,更多用法可以通过xcrun simctl help命令查看。

  • 通过version.plist文件查看

找到CoreSimulator框架文件(前面有写路径),version.plist文件位于Versions/A/Resources目录路径下。

经过对比发现,我电脑上的版本是917,而打包机上的版本是885.2。咦🤔?这版本什么️时候升级的我怎么不知道。思来想去,很可能是在前几天体验Xcode 15 beta 5版本的时候更新了CoreSimulator框架。打开大版本更新的Xcode时,一般都会弹出一个安装界面,然后请求管理员权限安装其他组件:

screenshot1

这时候就会自动更新CoreSimulator框架,当然也不限于这个框架,还有其他一些组件也会更新。

接下来就是验证是不是因为CoreSimulator框架版本不一致导致的问题,最简单的验证方法是将917版本降回885.2版本,然后再测试能否创建低版本iOS模拟器。我本来打算先将已有的CoreSimulator框架文件删除,然后从打包机复制一份到原路径,结果刚删除立马就弹出这个:

screenshot2

允许操作后自动重新安装了885.2版本的CoreSimulator框架,用Xcode 14.3.1版本实测可以创建iOS 12.0版本的模拟器,同时运行与调试也一切正常。

由此可以确定当前问题是CoreSimulator框架升级版本后导致的,那么该怎么解决呢?如果是Xcode 14遇到这个问题,直接删除新版本的CoreSimulator框架然后自动重装老版本即可(如果没有自动重装,重新打开Xcode 14也可以完成安装)。不过,这治标不治本,后面Xcode 15还是无法创建低版本iOS模拟器。

2. 逆向分析

CoreSimulator框架的核心是Versions/Current/CoreSimulator可执行文件,想知道框架升级改了什么导致了当前问题的话,逆向分析这个可执行文件是最快的方式。

以下所使用的逆向工具虽然是免费版本,但是如果不开代理可能下载很慢,这里提供分享链接,希望能对你有所帮助。

  • 百度网盘

2.1. IDA Free

关于逆向工具,我首选的是IDA Pro的免费版IDA Free,虽然功能受限,但是基本的静态分析是可用的,最重要的是免费。需要特别注意的一点是IDA Free被限制了只能处理x86/x64架构的二进制文件,这对CoreSimulator可执行文件不是问题,通过file命令可以知道这个可执行文件是个Mach-O通用二进制文件,包含了x86_64架构。

file /Library/Developer/PrivateFrameworks/CoreSimulator.framework/Versions/A/CoreSimulator

执行输出:

/Library/Developer/PrivateFrameworks/CoreSimulator.framework/Versions/A/CoreSimulator: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit dynamically linked shared library x86_64] [arm64e]
/Library/Developer/PrivateFrameworks/CoreSimulator.framework/Versions/A/CoreSimulator (for architecture x86_64):	Mach-O 64-bit dynamically linked shared library x86_64
/Library/Developer/PrivateFrameworks/CoreSimulator.framework/Versions/A/CoreSimulator (for architecture arm64e):	Mach-O 64-bit dynamically linked shared library arm64e

建议复制一份CoreSimulator可执行文件到其他目录用于静态分析,用IDA Free打开时选择x86_64架构文件:

screenshot3

当底部的消息输出窗口提示初始化自动分析已完成(“The initial autoanalysis has been finished.”)就可以开始进行静态分析。

screenshot4

万事开头难,现在该怎么找到问题所在呢?之前通过修改Info.plist文件中的CFBundleIdentifier属性值绕过了Xcode的限制,那说明CoreSimulator可执行文件很可能内置了各个模拟器版本的CFBundleIdentifier值用于判断,以此为切入口或许能找到新增加的限制判断。

通过快捷键Shift + Fn + F12或[菜单栏 View] -> [Open subviews] -> [Strings]打开字符串窗口,然后快捷键Command + F搜索关键词com.apple.CoreSimulator.SimRuntime.iOS-

screenshot5

选择任意一个搜索结果双击来到IDA View窗口,通过快捷键X查看引用:

screenshot6

结果没什么用,定位不了在哪里被引用。只好换个思路,从可能相关的函数入手。结合函数列表和模拟器文件的名称(iOS xx.x.simruntime),基本可以确定要找的函数应该和SimRuntime(模拟器运行时)相关。

screenshot7

从这些函数(方法)名可以看出CoreSimulator框架应该是用Objective-C开发的,一般首次加载文件时会弹框提示检测到Objective-C结构,询问是否要解析并重命名方法,以上的方法名经过了解析处理。看方法命名,严重怀疑-[SimRuntime isAvailableWithError:]方法就是我们要找的。在IDA View窗口使用快捷键Fn + F5查看该方法的伪代码:

screenshot8

相对于汇编代码,伪代码可读性确实高了些,方法调用(objc_msgSend)一目了然。不过一些引用数据,特别是字符串没有直接将指针转为实际指向的内容,例如&off_D9D70指针,需要点进去才知道指向的内容是arm64字符串,这导致阅读和搜索(文本搜索快捷键Option + T)伪代码都不方便。

screenshot9

分析一番,收获不大,尝试分析其他相关的方法,也没能找到问题所在。或许可以换个逆向工具试试?

2.2. Hopper Disassembler Demo

Mach-O文件的常用逆向工具还有Hopper Disassembler,它的功能会比IDA Pro弱些,但是更易上手使用。Demo版本虽然功能受限,但是基本够用,唯一需要注意的一点是每次打开只能用30分钟,到时间会弹框强制关闭。

打开Hopper Disassembler,点击Try the Demo开始使用。将需要分析的文件拖进去,会出现弹框:

screenshot10

这里没有被限制只能处理x86/x64架构的二进制文件,可以任选选择。等待自动分析完成就可以开始静态分析,详细使用教程请参考官方教程。

screenshot11

相比IDA Free的伪代码,这个的可读性确实更高些。不过分析一番还是没能找到问题所在,难道只能暂时搁置了?

3. 模拟器日志

如果能向分析源码一样,随时能打印日志和调试断点,逆向分析就轻松了。对于修改和调试二进制文件,前面的逆向工具也不是不能做,只是比较麻烦,而且这些功能在免费版上基本受限用不了。

正当我考虑要不要暂时搁置问题的时候,灵光一闪,日志可能一直都存在!在静态分析中经常能看到日志打印:

screenshot12

而且日志打印好像也没什么限制,猜测应该是一直在输出:

screenshot13

通常日志会被写入文件系统(.log扩展名的文件),那这些日志被输出到哪了呢?尝试搜索.log字符串查找写入文件路径:

screenshot14

%s/Library/Logs/CoreSimulator/CoreSimulator.%s.log应该就是日志文件的路径,不过这路径前面部分的%s还不确定。在汇编显示模式下点击指定行,然后点击右键就可以查看相关引用:

screenshot15

日志文件路径被____SimLogASLInit_block_invoke函数引用了,从伪代码可知路径前面部分的%s是被环境变量HOME的值替换了:

screenshot16

执行env命令打印环境变量可知,HOME变量的值是用户目录路径,例如/Users/xxx,所以模拟器日志文件所在目录的完整路径是/Users/xxx/Library/Logs/CoreSimulator。打开该目录下的CoreSimulator.log文件,发现一直在打印这样的错误日志:

Aug  9 21:36:53 mac com.apple.CoreSimulator.simctl[30026] <Error>: Error Domain=com.apple.CoreSimulator.SimError Code=401 "Unable to determine supported architectures for runtime (/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 12.4.simruntime)" UserInfo={NSLocalizedDescription=Unable to determine supported architectures for runtime (/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 12.4.simruntime)}

难道这个报错日志是问题的关键?将CoreSimulator框架版本降为885.2后,不再打印类似的错误日志。

补充一点:后续通过逆向发现CoreSimulator.log日志文件实际应该是CoreSimulator框架下的Versions/A/Resources/bin/simctl生成的,不过以上报错的关键信息确实来源于CoreSimulator可执行性文件。

4. supportedArchs

逆向CoreSimulator可执行文件,搜索关键词Unable to determine supported architectures for runtime,通过相关引用定位到-[SimRuntime initWithBundle:error:]方法:

screenshot17

相关伪代码(省略部分):

loc_9658b:
    rax = [r15 objectForKeyedSubscript:@"supportedArchs"];
    rax = [rax retain];
    var_268 = rax;
    if (rax != 0x0) {
            ...
    }
    else {
            rax = (r14)(@class(NSBundle), @selector(bundleWithIdentifier:), @"com.apple.CoreSimulator");
            rax = [rax retain];
            rbx = rax;
            r15 = @"Unable to determine supported architectures for runtime (%@)";
            rdx = r15;
            rcx = r15;
            rax = (r14)(rax, @selector(localizedStringForKey:value:table:), rdx, rcx, 0x0);
            rax = [rax retain];
            r12 = rax;
            if (rax != 0x0) {
                    r15 = rax;
            }
            rax = (r14)(var_218, @selector(bundlePath), rdx, rcx, 0x0);
            rax = [rax retain];
            r15 = [(r14)(@class(NSString), @selector(stringWithFormat:), r15, rax, 0x0) retain];
            [rax release];
            [r12 release];
            [rbx release];
            var_208 = r15;
            rax = [NSError errorWithSimErrno:0x191 localizedDescription:r15];
            rax = [rax retain];
            if (rax != 0x0) {
                    __SimLog(0x3, "-[SimRuntime initWithBundle:error:]", 0x1fa, @"%@", rax, r9, var_3C0);
                    rax = rax;
            }
            r14 = var_1E8;
            r15 = var_1F0;
            rbx = var_238;
            if (r14 != 0x0) {
                    rax = objc_retainAutorelease(rax);
                    *r14 = rax;
            }
            r12 = 0x0;
            r14 = var_1C0;
    }
    ...

逆向885.2版本的CoreSimulator可执行文件,对比同个方法的伪代码,这部分判断逻辑确实是新加的。从以上伪代码可知,r15(根据objectForKeyedSubscript可以推测应该是NSDictionary类型)通过supportedArchs键获取对应值时,因为键不存在所以返回NULL(也就是0x0),进而执行else代码块打印错误日志。那么r15的值是从哪来的呢?

通过不断溯源查找应该可以找到,不过这个方法的伪代码很长,需要耗费不少时间精力。换个思路,根据报错信息中出现的模拟器文件路径(/Library/.../Runtimes/iOS 12.4.simruntime)以及发生错误的方法(-[SimRuntime initWithBundle:error:]),可以大胆猜测错误是在加载模拟器文件初始化SimRuntime对象时发生的,所以r15的值很可能源于模拟器文件中的某个配置文件。

搜索关键词plist查找可能的配置文件:

screenshot18

咦🤔️?这行rax = [r12 pathForResource:@"profile" ofType:@"plist"];代码获取了profile.plist文件的完整路径,感觉很有可能就是它。找到iOS 12.4.simruntime文件,右键显示包内容,然后搜索profile.plist,搜索结果如下:

screenshot19

打开后确实没找到supportedArchs属性。另找一个没报错的模拟器文件,打开其中的profile.plist文件,确实有该属性:

screenshot20

iOS 12.4.simruntime文件中的profile.plist复制一份到其他地方,然后打开添加supportedArchs属性并保存,最后将修改后的文件替换原来的文件。

重新打开Xcode创建低版本iOS模拟器,还是不行。难道这么做无效?再次检查一下模拟器日志还有没有报错,好吧,原先的错误没了,来了新的错误:

Aug  9 23:28:01 mac com.apple.CoreSimulator.simctl[30026] <Error>: Failed to setup launchHostClient for runtime com.apple.CoreSimulator.SimRuntime.iOS-12-4-1: Error Domain=NSPOSIXErrorDomain Code=88 "Malformed Mach-o file" UserInfo={NSLocalizedDescription=Failed to open liblaunch_sim: dlopen(/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 12.4.simruntime/Contents/Resources/RuntimeRoot/usr/lib/system/host/liblaunch_sim.dylib, 0x0101): tried: '/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 12.4.simruntime/Contents/Resources/RuntimeRoot/usr/lib/system/host/liblaunch_sim.dylib' (fat file, but missing compatible architecture (have 'x86_64,i386', need 'arm64')), '/System/Volumes/Preboot/Cryptexes/OS/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 12.4.simruntime/Contents/Resources/RuntimeRoot/usr/lib/system/host/liblaunch_sim.dylib' (no such file), '/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 12.4.simruntime/Contents/Resources/RuntimeRoot/usr/lib/system/host/liblaunch_sim.dylib' (fat file, but missing compatible architecture (have 'x86_64,i386', need 'arm64')), NSLocalizedFailureReason=Malformed Mach-o file}

关键报错信息:

but missing compatible architecture (have 'x86_64,i386', need 'arm64')

报错信息说的很明白,缺少arm64架构。这些低版本的模拟器文件肯定是没有arm64架构的,毕竟发布的时候arm架构的M系列芯片还没出来。逐一查看电脑上已有的iOS模拟器文件,发现supportedArchs属性是从iOS 14.0.simruntime开始出现的,这就对了,iOS 14/Xcode 12/M1芯片都是2020年发布的,也就是说,当前问题只会出现在iOS 14以下。

看来不能完全照搬照抄,将supportedArchs属性中的arm64删除,重新打开Xcode创建低版本iOS模拟器,创建成功!不过尝试启动,却出现了弹框报错:

screenshot21

经过实测发现是模拟器相关的服务没有重启。模拟器服务CoreSimulatorServiceCoreSimulator框架的一部分,用于管理模拟器的创建、启动、停止和删除等功能。打开活动监视器,找到com.apple.CoreSimulator.CoreSimulatorService进程,然后结束进程。

screenshot22

重新运行iOS 12.4版本的模拟器,能启动但是黑屏。好吧,可用的低版本iOS模拟器又少了。实测iOS 13.7以下版本不是黑屏就是无法运行和调试应用,真是忙了个寂寞!明明Xcode 15的部署目标最低还是iOS 12,却不支持iOS 13.7以下的模拟器。以下来自官方支持文档:

screenshot23

文档中Xcode 14.3.1版本的iOS模拟器显示最低支持iOS 13.7,但实际可下载列表中最低版本已经是iOS 14.0.1。

解决方案

强烈建议先阅读前置文章iOS问题记录 - Xcode 14安装低版本iOS模拟器(持续更新),然后在修改Info.plist文件的基础上,再额外修改模拟器文件中的profile.plist(位于Contents/Resources目录)文件,增加supportedArchs属性,具体增加的内容如下:

screenshot24

注意事项:

  • 建议先复制一份profile.plist文件到其他地方,修改完成后再替换原文件
  • 如果遇到问题的iOS模拟器版本大等于iOS 14.0,那么应该不是同一个问题
  • 实测Xcode 15 beta 5版本最低只支持iOS 13.7版本,而且可能因为配套使用的Simulator.app(Xcode内置)也还处于Beta版,运行调试会有点问题。
  • 如果你还在用Xcode 14却遇到当前问题,建议按问题分析中的操作重装老版本的CoreSimulator框架

总的来说,如果Xcode 15正式版最低也只支持到iOS 13.7版本,那么后续想使用更低版本的iOS模拟器就只能通过Xcode 14。等正式版发布后,会重新测试并更新本篇文章。

以下是一些Xcode版本所支持的最低iOS模拟器版本:

最后更新日期:2023/08/10

Xcode versionCoreSimulator framework versionMinimum supported simulator version
14.0.1857.712.0
14.2857.1412.0
14.3.1885.212.0
15 beta 591713.7

以上数据实测于M芯片的电脑,如果不是M芯片的电脑,可能会因为架构不一致有所差别。不过,更有可能是因为电脑上的Xcode版本和CoreSimulator框架版本不一致导致的,当这两个版本不一致时以CoreSimulator框架版本为主。

最后

如果这篇文章对你有所帮助,点赞👍加星🌟支持一下吧,谢谢~


本篇文章由@crasowas发布于CSDN。

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

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

相关文章

windows使用/服务(13)戴尔电脑怎么设置通电自动开机

戴尔pc机器通电自启动 1、将主机显示器键盘鼠标连接好后&#xff0c;按主机电源键开机 2、在开机过程中按键盘"F12",进入如下界面&#xff0c;选择“BIOS SETUP” 3、选择“Power Management” 4、选择“AC Recovery”&#xff0c;点选“Power On”&#xff0c;点击“…

Codeforces Round 828 (Div. 3)E题题解

文章目录 [Divisible Numbers (easy version)](https://codeforces.com/contest/1744/problem/E1)问题建模问题分析代码 [ Divisible Numbers (hard version)](https://codeforces.com/contest/1744/problem/E2)问题建模问题分析1.根据简单版本分析所求2.方法1通过因数分解得到…

竞赛项目 深度学习图像风格迁移 - opencv python

文章目录 0 前言1 VGG网络2 风格迁移3 内容损失4 风格损失5 主代码实现6 迁移模型实现7 效果展示8 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习图像风格迁移 - opencv python 该项目较为新颖&#xff0c;适合作为竞赛课题…

MongoDB安装和配置

一、MongoDB安装和配置 1、进入官网下载你所需要的安装版本&#xff0c;点击直通官网 Step1&#xff1a;进入官网后&#xff0c;将看到如下界面&#xff0c;点击上方导航栏Products&#xff0c;找到Community Server Step2&#xff1a;选择自己需要的版本、系统和压缩方式 2、下…

Java算法_ 岛屿数量(LeetCode_Hot100)

题目描述&#xff1a;给你一个由 &#xff08;陆地&#xff09;和 &#xff08;水&#xff09;组成的的二维网格&#xff0c;请你计算网格中岛屿的数量。‘1’ , ‘0’ 岛屿总是被水包围&#xff0c;并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。 此外&#…

Java:Stream API

文章目录 1 说明2 为什么要使用Stream API3 什么是StreamStream的操作三个步骤创建Stream实例一系列中间操作终止操作 1 说明 Java8中有两大最为重要的改变。第一个是 Lambda 表达式&#xff1b;另外一个则是 Stream API。Stream API ( java.util.stream) 把真正的函数式编程风…

Linux6.37 Kubernetes 集群调度

文章目录 计算机系统5G云计算第三章 LINUX Kubernetes 集群调度一、调度约束1.调度过程2.指定调度节点3.亲和性1&#xff09;节点亲和性2&#xff09;Pod 亲和性3&#xff09;键值运算关系 4.污点(Taint) 和 容忍(Tolerations)1&#xff09;污点(Taint)2&#xff09;容忍(Toler…

聊聊行锁、间隙锁、临键锁的区别

一、准备 创建 student 表 CREATE TABLE student ( id bigint NOT NULL, age int DEFAULT NULL, b int DEFAULT NULL, a int DEFAULT NULL, c int DEFAULT NULL, PRIMARY KEY ( id ), ) ENGINEInnoDB DEFAULT CHARSETutf8mb3 插⼊数据 insert into student (id,age,a,b,c) val…

Java【Spring】使用注解, 更简单的存储和获取 Bean

文章目录 前言一、存储 Bean1, 配置文件2, 五大类注解Bean 的命名规则 3, 方法注解Bean 的命名规则 二、获取 Bean1, 属性注入2, Setter 注入3, 构造方法注入4, Autowired 和 Resource 的区别5, 同一个类型的多个 Bean 注入问题 总结 前言 各位读者好, 我是小陈, 这是我的个人主…

机器学习、深度学习项目开发业务数据场景梳理汇总记录三

本文的主要作用是对历史项目开发过程中接触到的业务数据进行整体的汇总梳理&#xff0c;文章会随着项目的开发推进不断更新。 这里是续文&#xff0c;因为CSDN单篇文章内容太大的话就会崩溃的&#xff0c;别问我怎么知道的&#xff0c;问就是血泪教训&#xff0c;辛辛苦苦写了一…

C语言 指针与const

const 修饰变量&#xff0c;使得这个变量不能被修改。 const 对指针具有两种修饰的方式&#xff0c;且两种方式所限制的情况不同。 当const在 * 的左边 const int * p &n; 或者 int const * p &n; 当const在*的左边时&#xff0c;指针变量p所指向的空间内容无法被修…

C语言 指针与assert

assert 又称断言&#xff0c;需要包含头文件 assert.h 用于在运行时确保程序符合指定条件&#xff0c;如果不符合&#xff0c;就报错终止运行。 assert(p ! NULL); 上面代码在程序运行到这一行语句时&#xff0c;验证变量 p 是否等于 NULL。如果确实不等于 NULL &#xff0c;…

慎写指针类型的全局变量

简述: 在 关于range二三事[1] 第二个case中,介绍了对于指针类型的 切片/map变量A 的循环,要格外注意, 迭代出的value作用域是整个方法而非循环体内. 改进办法:在循环体中引入中间变量,"暂存"下每次迭代的value的值 但对于这个A,如果是全局变量,则又极有可能出现问题:…

Apache Maven简介安装及系统坏境配置eclipse配置Apache Maven---详细介绍

一&#xff0c;简介 Maven可以简化项目的构建和依赖管理&#xff0c;并提供了一种规范化和可复用的方式来管理Java项目。它广泛应用于Java开发领域&#xff0c;简单来说&#xff1a;它提供了一个简单而强大的方式来管理项目的构建、依赖关系和文档在企业级项目中被广泛采用。 1…

京东秋招攻略,备考在线测评和网申笔试

京东秋招简介 伴随着社会竞争越来越激烈&#xff0c;人们投递简历的岗位也变得越来越多元&#xff0c;而无论人们的选择面变成何样&#xff0c;那些知名度较高的企业&#xff0c;永远都备受关注&#xff0c;只要其一发布招聘公告&#xff0c;总有人第一时间踊跃报名。而作为这…

Java算法_ LRU 缓存(LeetCode_Hot100)

题目描述&#xff1a;请你设计并实现一个满足 LRU &#xff08;最近最少使用&#xff09; 缓存 约束的数据结构。 获得更多&#xff1f;算法思路:代码文档&#xff0c;算法解析的私得。 运行效果 完整代码 import java.util.HashMap; import java.util.Map;/*** 2 * Author: L…

winform中嵌入cefsharp, 并使用selenium控制

正常说&#xff0c; 需要安装的包 下面是所有的包 全部代码 using OpenQA.Selenium.Chrome; using OpenQA.Selenium; using System; using System.Windows.Forms; using CefSharp.WinForms; using CefSharp;namespace WindowsFormsApp2 {public partial class Form1 : Form{//…

(kubernetes)k8s常用资源管理

目录 k8s常用资源管理 1、创建一个pod 1&#xff09;创建yuml文件 2&#xff09;创建容器 3&#xff09;查看所有pod创建运行状态 4&#xff09;查看指定pod资源 5&#xff09;查看pod运行的详细信息 6&#xff09;验证运行的pod 2、pod管理 1&#xff09;删除pod 2…

搜索二叉树(二叉树进阶)

目录 1.二叉搜索树 1.1二叉搜索树概念 1.2二叉搜索树操作 2.3二叉搜索树的实现 2.4二叉搜索树的应用 2.5二叉搜索树的性能分析 1.二叉搜索树 1.1二叉搜索树概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一颗空树&#xff0c;或者是具有以下性质的二叉树&#xff…

mac安装nvm管理工具遇到的问题和解决方法

nvm 是一款可以管理多版本node的工具&#xff0c;因为是刚买没多久的电脑之前用的都是windows&#xff0c;昨天折腾了一下午终于倒腾好了 第一步&#xff1a; 卸载电脑已有的node&#xff1b;访问nvm脚本网址&#xff0c;另存为到电脑上任何目录&#xff0c;我是放在桌面上的…