首页 文章 精选 留言 我的

精选列表

搜索[ios],共10000篇文章
优秀的个人博客,低调大师

iOS SAX解析XML

先从网络获取XML文件 NSURL *url = [NSURL URLWithString:@"https://127.0.0.1/videos.xml"]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler: ^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { if (connectionError) { NSLog(@"连接错误 %@", connectionError); return; } NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; if (httpResponse.statusCode == 200 || httpResponse.statusCode == 304) { // 解析数据 } else { NSLog(@"服务器内部错误"); } }]; 在注释为解析数据处开始解析网络获取的数据 // 给ViewController添加代理 @interface ViewController () <NSXMLParserDelegate> @end // 解析数据 NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data]; // 设置代理 parser.delegate = self; // 开始执行代理方法 [parser parse]; 实现代理方法 // 1. 开始解析文档 - (void)parserDidStartDocument:(NSXMLParser *)parser { NSLog(@"1开始解析"); } // 2. 找开始节点 - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict { NSLog(@"2找开始节点 %@--%@", elementName, attributeDict); } // 3. 找节点之间的内容 - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { NSLog(@"3找节点之间的内容 %@", string); } // 4. 找结束节点 - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { NSLog(@"4找结束节点 %@", elementName); } // 5. 结束解析文档 - (void)parserDidEndDocument:(NSXMLParser *)parser { NSLog(@"5结束解析"); } // 6. 解析出错 - (void) parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError { NSLog(@"解析出错"); } 构建实体类 Video.h #import <Foundation/Foundation.h> @interface Video : NSObject @property (nonatomic, strong) NSNumber *videoId; @property (nonatomic, copy) NSString *name; @property (nonatomic, copy) NSNumber *length; @property (nonatomic, copy) NSString *videoURL; @property (nonatomic, copy) NSString *imageURL; @property (nonatomic, copy) NSString *desc; @property (nonatomic, copy) NSString *teacher; @property (nonatomic, readonly) NSString *time; - (instancetype)initWithDict:(NSDictionary *)dict; + (instancetype)videoWithDict:(NSDictionary *)dict; @end video.m #import "Video.h" @implementation Video - (instancetype)initWithDict:(NSDictionary *)dict { if (self = [super init]) { [self setValuesForKeysWithDictionary:dict]; } return self; } + (instancetype)videoWithDict:(NSDictionary *)dict { return [[self alloc] initWithDict:dict]; } - (NSString *)time { int len = self.length.intValue; return [NSString stringWithFormat:@"%02d:%02d:%02d:", len / 3600, (len %3600) / 60, (len % 60) ]; } - (NSString *)description { return [NSString stringWithFormat:@"<%@ : %p> { videoId : %@, name : %@, length : %@, videoURL : %@, imageURL : %@, desc : %@, teacher : %@}", [self class], self, self.videoId, self.name, self.length, self.videoURL, self.imageURL, self.desc, self.teacher]; } @end XML解析成对象 @interface ViewController () <NSXMLParserDelegate> // 保存XML数据 @property (nonatomic, strong) NSMutableArray *videos; // 当前创建的video对象 @property (nonatomic, strong) Video *video; // 保存当前节点内容 @property (nonatomic, copy) NSMutableString *string; @end @implementation ViewController // 懒加载 - (NSMutableArray *)videos { if (_videos == nil) { _videos = [NSMutableArray arrayWithCapacity:10]; } return _videos; } - (NSMutableString *)string { if (_string == nil) { _string = [NSMutableString string]; } return _string; } @end 在video节点时创建Video对象 // 2. 找开始节点 - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict { NSLog(@"2找开始节点 %@--%@", elementName, attributeDict); // 如果是video标签,创建video对象 if ([elementName isEqualToString:@"video"]) { self.video = [[Video alloc] init]; self.video.videoId = @([attributeDict[@"videoId"] intValue]); // 添加到数组中 [self.videos addObject:self.video]; } } 拼接保存每个节点中的内容 // 3. 找节点之间的内容 - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { NSLog(@"3找节点之间的内容 %@", string); [self.string appendString:string]; } 将内容与对应的节点赋值,并将string对象置空 // 4. 找结束节点 - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { NSLog(@"4找结束节点 %@", elementName); // 判断标签是否有对应的属性 if (![elementName isEqualToString:@"video"] && ![elementName isEqualToString:@"videos"]) { // 为节点赋值 [self.video setValue:self.string forKey:elementName]; } // 清空字符串 [self.string setString:@""]; } 打印查看结果 结果.png videos.xml内容 <videos> <video videoId="1"> <name>01.C语言-语法预览</name> <length>320</length> <videoURL>/itcast/videos/01.C语言-语法预览.mp4</videoURL> <imageURL>/itcast/images/head1.png</imageURL> <desc>C语言-语法预览</desc> <teacher>李雷</teacher> </video> <video videoId="2"> <name>02.C语言-第一个C程序</name> <length>2708</length> <videoURL>/itcast/videos/02.C语言-第一个C程序.mp4</videoURL> <imageURL>/itcast/images/head2.png</imageURL> <desc>C语言-第一个C程序</desc> <teacher>李雷</teacher> </video> <video videoId="3"> <name>03.C语言-函数</name> <length>822</length> <videoURL>/itcast/videos/03.C语言-函数.mp4</videoURL> <imageURL>/itcast/images/head3.png</imageURL> <desc>C语言-函数</desc> <teacher>韩梅梅</teacher> </video> <video videoId="4"> <name>04.C语言-基本数据类型</name> <length>1113</length> <videoURL>/itcast/videos/04.C语言-基本数据类型.mp4</videoURL> <imageURL>/itcast/images/head4.png</imageURL> <desc>C语言-基本数据类型</desc> <teacher>韩梅梅</teacher> </video> <video videoId="5"> <name>05.C语言-基本运算</name> <length>594</length> <videoURL>/itcast/videos/05.C语言-基本运算.mp4</videoURL> <imageURL>/itcast/images/head5.png</imageURL> <desc>C语言-基本运算</desc> <teacher>韩梅梅</teacher> </video> <video videoId="6"> <name>06.C语言-数组</name> <length>923</length> <videoURL>/itcast/videos/06.C语言-数组.mp4</videoURL> <imageURL>/itcast/images/head6.png</imageURL> <desc>C语言-数组</desc> <teacher>韩梅梅</teacher> </video> <video videoId="7"> <name>07.C语言-字符串</name> <length>848</length> <videoURL>/itcast/videos/07.C语言-字符串.mp4</videoURL> <imageURL>/itcast/images/head7.png</imageURL> <desc>C语言-字符串</desc> <teacher>韩梅梅</teacher> </video> <video videoId="8"> <name>08.C语言-指针</name> <length>502</length> <videoURL>/itcast/videos/08.C语言-指针.mp4</videoURL> <imageURL>/itcast/images/head8.png</imageURL> <desc>C语言-指针</desc> <teacher>韩梅梅</teacher> </video> <video videoId="9"> <name>09.C语言-指针用例</name> <length>558</length> <videoURL>/itcast/videos/09.C语言-指针用例.mp4</videoURL> <imageURL>/itcast/images/head1.png</imageURL> <desc>C语言-指针用例</desc> <teacher>韩梅梅</teacher> </video> <video videoId="10"> <name>10.C语言-指针与数组</name> <length>1682</length> <videoURL>/itcast/videos/10.C语言-指针与数组.mp4</videoURL> <imageURL>/itcast/images/head2.png</imageURL> <desc>C语言-指针与数组</desc> <teacher>韩梅梅</teacher> </video> <video videoId="11"> <name>11.C语言-指针与字符串</name> <length>1092</length> <videoURL>/itcast/videos/11.C语言-指针与字符串.mp4</videoURL> <imageURL>/itcast/images/head3.png</imageURL> <desc>C语言-指针与字符串</desc> <teacher>韩梅梅</teacher> </video> </videos>

优秀的个人博客,低调大师

iOS GET/POST请求

GET请求 // GET请求 - (void)get { NSString *name = @"张三"; NSString *pwd = @"zhang"; NSString *strUrl = [NSString stringWithFormat:@"http://127.0.0.1/php/login.php?username=%@&password=%@", name, pwd]; // 对汉字进行转义 strUrl = [strUrl stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; NSLog(@"%@", strUrl); NSURL *url = [NSURL URLWithString:strUrl]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler: ^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { if (connectionError) { NSLog(@"连接错误 %@", connectionError); return; } NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; if (httpResponse.statusCode == 200 || httpResponse.statusCode == 304) { // 解析数据 NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL]; NSLog(@"%@", dict); } else { NSLog(@"服务器内部错误"); } }]; } 打印结果: GET.png POST请求 // POST请求 - (void)post { NSString *name = @"zhangsan"; NSString *pwd = @"zhang"; NSString *str = [NSString stringWithFormat:@"username=%@&password=%@", name, pwd]; NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/php/login.php"]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; // 设置请你去方法 request.HTTPMethod = @"post"; // 设置请求体 request.HTTPBody = [str dataUsingEncoding:NSUTF8StringEncoding]; [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler: ^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { if (connectionError) { NSLog(@"连接错误 %@", connectionError); return; } NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; if (httpResponse.statusCode == 200 || httpResponse.statusCode == 304) { // 解析数据 NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL]; NSLog(@"%@", dict); } else { NSLog(@"服务器内部错误"); } }]; } 打印结果: POST.png

优秀的个人博客,低调大师

iOS 代码块使用

我们可以将经常使用的代码防止在代码块内,使用快捷命令输入 例如如下代码 NSURL *url = [NSURL URLWithString:<# str #>]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler: ^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { if (connectionError) { NSLog(@"连接错误 %@", connectionError); return; } NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; if (httpResponse.statusCode == 200 || httpResponse.statusCode == 304) { // 解析数据 } else { NSLog(@"服务器内部错误"); } }]; 其中<# str #>代表每次输入的内容都是动态变化的。 将整个代码选中,直接右下角的此处 图1.png 拖入后会出现如下对话框, 其中Title为标题,Summary是摘要,即简单介绍代码块的作用,Platform是平台,Language是语言,Completion ShortCut是快捷命令, Completion Scopes是作用域。建议必填项是Completion ShortCut。填写好之后点击Done。 图2.png 使用 1). 在.m文件中输入conn,即可出现如下提示 图3.png 2). 点击回车后,即可出现刚刚的那段代码,将其中的str字符串动态替换就可以正常使用。 图4.png

优秀的个人博客,低调大师

IOS内存警告处理

IPhone下每个app可用的内存是被限制的,如果一个app使用的内存超过20M,则系统会向该app发送Memory Warning消息。收到此消息后,app必须正确处理,否则可能出错或者出现内存泄露。 app收到Memory Warning后会调用: UIApplication::didReceiveMemoryWarning -> UIApplicationDelegate::applicationDidReceiveMemoryWarning,然后调用当前所有的viewController进行处理。因此处理的主要工作是在viewController。 我们知道,创建viewcontroller时,执行顺序是loadview ->viewDidLoad。 当收到内存警告时,如果viewcontroller未显示(在后台),会执行didReceiveMemoryWarning -> viewDidUnLoad;如果viewcontroller当前正在显示(在前台),则只执行didReceiveMemoryWarning。 当重新显示该viewController时,执行过viewDidUnLoad的viewcontroller(即原来在后台)会重新调用loadview -> viewDidLoad。 因此主要注意下面几个函数: loadView 创建view,构建界面; viewDidLoad 做些初始化工作。由于在初次创建viewcontroller和重新恢复时都会调用,因此这个函数需要注意区分不同的情况,设置正确的状态。 didReceiveMemoryWarning 释放不必须的内存,比如缓存,未显示的view等。 viewDidUnLoad 最大程度的释放可以释放的内存。比如应该释放view,这些view在调用loadview后可以重新生成。(其中成员变量释放后应设置为nil)。对于非界面的数据是否释放,需要具体分析,可以恢复的数据可以释放,不能恢复的数据就不要释放。 实际中如果viewcontroller是用xib生成的界面,则需要我们做的就比较少,主要是在viewDidLoad中恢复原来的界面状态。 如果是通过编程创建的界面,则需要做的工作就要更多些,上面4个函数中都需要进行正确处理。 本文转自编程小翁博客园博客,原文链接:http://www.cnblogs.com/wengzilin/p/3383805.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

IOS中SQL语句

以下我们就建立数据库、建立资料表及索引、新增资料、查询资料、更改资料、移除资料、 sqlite3 命令列选项等几个项目做简单的介绍。 目录 1 建立数据库档案 2 在 sqlite3 提示列下操作 3 SQL的指令格式 4 建立资料表 5 建立索引 6 加入一笔资料 7 查询资料 8 如何更改或删除资料 9 其他sqlite的特别用法 10 小结 建立数据库档案 用 sqlite3 建立数据库的方法很简单,只要在shell下键入(以下$符号为shell提示号,请勿键入): $ sqlite3 foo.db 如果目录下没有foo.db, sqlite3 就会建立这个数据库。 sqlite3 并没有强制数据库档名要怎么取,因此如果你喜欢,也可以取个例如foo.icannameitwhateverilike的档名。 在 sqlite3 提示列下操作 进入了 sqlite3 之后,会看到以下文字: SQLite version 3.1.3 Enter ".help" for instructions sqlite> 这时如果使用.help可以取得求助,.quit则是离开(请注意:不是quit) SQL的指令格式 所以的SQL指令都是以分号(;)结尾的。如果遇到两个减号(--)则代表注解, sqlite3 会略过去。 建立资料表 假设我们要建一个名叫film的资料表,只要键入以下指令就可以了: create table film(title, length, year, starring); 这样我们就建立了一个名叫film的资料表,里面有name、length、year、starring四个字段。 这个create table指令的语法为: create table table_name(field1, field2, field3, ...); table_name是资料表的名称,fieldx则是字段的名字。 sqlite3 与许多SQL数据库软件不同的是,它不在乎字段属于哪一种资料型态: sqlite3 的字段可以储存任何东西:文字、数字、大量文字(blub),它会在适时自动转换。 建立索引 如果资料表有相当多的资料,我们便会建立索引来加快速度。好比说: create index film_title_index on film(title); 意思是针对film资料表的name字段,建立一个名叫film_name_index的索引。这个指令的语法为 create index index_name on table_name(field_to_be_indexed); 一旦建立了索引, sqlite3 会在针对该字段作查询时,自动使用该索引。这一切的操作都是在幕后自动发生的,无须使用者特别指令。 加入一笔资料 接下来我们要加入资料了,加入的方法为使用insert into指令,语法为: insert into table_name values(data1, data2, data3, ...); 例如我们可以加入 insert into film values ('Silence of the Lambs, The', 118, 1991, 'Jodie Foster'); insert into film values ('Contact', 153, 1997, 'Jodie Foster'); insert into film values ('Crouching Tiger, Hidden Dragon', 120, 2000, 'Yun-Fat Chow'); insert into film values ('Hours, The', 114, 2002, 'Nicole Kidman'); 如果该字段没有资料,我们可以填NULL。 查询资料 讲到这里,我们终于要开始介绍SQL最强大的select指令了。我们首先简单介绍select的基本句型: select columns from table_name where expression; 最常见的用法,当然是倒出所有数据库的内容: select * from film; 如果资料太多了,我们或许会想限制笔数: select * from film limit 10; 或是照着电影年份来排列: select * from film order by year limit 10; 或是年份比较近的电影先列出来: select * from film order by year desc limit 10; 或是我们只想看电影名称跟年份: select title, year from film order by year desc limit 10; 查所有茱蒂佛斯特演过的电影: select * from film where starring='Jodie Foster'; 查所有演员名字开头叫茱蒂的电影('%' 符号便是 SQL 的万用字符): select * from film where starring like 'Jodie%'; 查所有演员名字以茱蒂开头、年份晚于1985年、年份晚的优先列出、最多十笔,只列出电影名称和年份: select title, year from film where starring like 'Jodie%' and year >= 1985 order by year desc limit 10; 有时候我们只想知道数据库一共有多少笔资料: select count(*) from film; 有时候我们只想知道1985年以后的电影有几部: select count(*) from film where year >= 1985; (进一步的各种组合,要去看SQL专书,不过你大概已经知道SQL为什么这么流行了:这种语言允许你将各种查询条件组合在一起──而我们还没提到「跨数据库的联合查询」呢!) 如何更改或删除资料 了解select的用法非常重要,因为要在sqlite更改或删除一笔资料,也是靠同样的语法。 例如有一笔资料的名字打错了: update film set starring='Jodie Foster' where starring='Jodee Foster'; 就会把主角字段里,被打成'Jodee Foster'的那笔(或多笔)资料,改回成Jodie Foster。 delete from film where year < 1970; 就会删除所有年代早于1970年(不含)的电影了。 其他sqlite的特别用法 sqlite可以在shell底下直接执行命令: sqlite3 film.db "select * from film;" 输出 HTML 表格: sqlite3 -html film.db "select * from film;" 将数据库「倒出来」: sqlite3 film.db ".dump" > output.sql 利用输出的资料,建立一个一模一样的数据库(加上以上指令,就是标准的SQL数据库备份了): sqlite3 film.db < output.sql 在大量插入资料时,你可能会需要先打这个指令: begin; 插入完资料后要记得打这个指令,资料才会写进数据库中: commit; 本文转自编程小翁博客园博客,原文链接:http://www.cnblogs.com/wengzilin/archive/2012/03/27/2419851.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

iOS图片的压缩

1. 压缩质量 UIImageJPEGRepresent 2.压缩分辨率 - (UIImage *)scaleToSize:(UIImage *)img size:(CGSize)size{ // 创建一个bitmap的context // 并把它设置成为当前正在使用的context UIGraphicsBeginImageContext(size); // 绘制改变大小的图片 [img drawInRect:CGRectMake(0, 0, size.width, size.height)]; // 从当前context中创建一个改变大小后的图片 UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext(); // 使当前的context出堆栈 UIGraphicsEndImageContext(); // 返回新的改变大小后的图片 return scaledImage; } 本文转自 卓行天下 51CTO博客,原文链接:http://blog.51cto.com/9951038/1772573,如需转载请自行联系原作者

优秀的个人博客,低调大师

ios19---xib

// // ViewController.m #import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; /* 拷贝一份代码先清理clean一下。 Xib是简单版的故事板,new File————User Interface————(Storyboard和Launch Screen是属于故事板,View和Empty是属于xib). Xib和故事板区别: 1.都是用来描述软件界面的。 2.都是用Interface Buider工具来编译的。 3.xib是轻量级的,用来画局部页面,类似于自定义控件(用xib自定义控件要简单)。 故事板是重量级的,可以相互跳转。 最后xib还是要加载到故事板上面。 */ /* xib放在Supporting Files里面。也是通过拖控件房子布局。 控制台输入: po NSHomeDirectory(): /Users/mctc/Library/Developer/CoreSimulator/Devices/4E7E6AB7-BB75-4C2C-9D87-21A0369A3DD6/data/Containers/Data/Application/75F9E7B6-9F45-448C-9219-2EAFF94B65B8 然后通过终端: open /Users/mctc/Library/Developer/CoreSimulator/Devices/4E7E6AB7-BB75-4C2C-9D87-21A0369A3DD6/data/Containers/Data/Application/75F9E7B6-9F45-448C-9219-2EAFF94B65B8 打开后回退到bundle,—->application—>通过创建日期查看刚才的xib2.app—->xib2.app显示包内容—->可以看见CarView.xib变成了CarView.nib, */ UIView *carView = [[[NSBundle mainBundle] loadNibNamed:@"CarView" owner:nil options:nil] firstObject];//[[NSBundle mainBundle] loadNibNamed:@"CarView" owner:nil options:nil] 返回的是数组,这里的xib的图片和文字是写死的。 carView.frame = CGRectMake(0, 100, 200, 50);//改变不了fram, // carView.clipsToBounds = YES; [self.view addSubview:carView]; // 方式二 // UINib *nib = [UINib nibWithNibName:@"CarView" bundle:nil]; // UIView *carView = [[nib instantiateWithOwner:nil options:nil] firstObject]; // // [self.view addSubview:carView]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end 本文转自农夫山泉别墅博客园博客,原文链接:http://www.cnblogs.com/yaowen/p/7468779.html,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册