11.Objective-C 編碼規(guī)范指南

@(〓〓 iOS-實(shí)用技術(shù))[Objective-C編碼規(guī)范]


目錄

  • 11.Objective-C 編碼規(guī)范指南
  • 項(xiàng)目工程結(jié)構(gòu)
  • 代碼結(jié)構(gòu)
  • 項(xiàng)目Xode相關(guān)配置
    • 代碼縮進(jìn)配置
    • 代碼行號(hào)顯示配置
    • 項(xiàng)目編碼建議
  • 注釋
    • 方法注釋
    • 屬性注釋
  • 命名與編碼規(guī)范
    • 類名命名規(guī)則
    • 協(xié)議編碼規(guī)則
    • 控件/控制器定義命名規(guī)則
  • 方法
    • 方法名和參數(shù)命名規(guī)則
    • 方法聲明和編碼規(guī)范
    • 方法調(diào)用父類方法編碼規(guī)則
  • 函數(shù)
  • 變量
    • 成員屬性編碼規(guī)則
  • 常量
    • Foundation框架常量賦值規(guī)則
    • 定義普通常量以字母k開頭
  • 枚舉與宏定義
    • 枚舉編碼規(guī)則
    • NS_ENUM定義普通枚舉
    • NS_OPTIONS定義位枚舉
  • 通知和異常
    • 通知NSNotification常量命名規(guī)則
    • 異常命名規(guī)則
  • 布爾值
  • 條件語句
    • if else 條件語句
    • switch case 語句
  • 其他規(guī)則
    • 初始化方法(構(gòu)造方法)規(guī)則
    • 直接放回對(duì)應(yīng)數(shù)據(jù)時(shí),無需添加get, calc單詞
    • 單例的聲明和使用規(guī)則
    • 設(shè)置常用屬性,直接使用點(diǎn)語法
    • 協(xié)議和代理方法命名規(guī)則
    • 可以使用({})語法模塊化設(shè)置控件屬性(可選)

項(xiàng)目工程結(jié)構(gòu)


代碼結(jié)構(gòu)

  • 實(shí)現(xiàn)文件中的代碼結(jié)構(gòu),提倡以下約定:

    • #pragma mark -將函數(shù)或方法按功能進(jìn)行分組;分組之間空2行,方法之間空1行.
    • delgate或協(xié)議相關(guān)方法放到一般內(nèi)容之后。
#pragma mark - Lifecycle (生命周期)
- (void)dealloc {}

- (instancetype)init {}

- (void)viewDidLoad {}

- (void)viewWillAppear:(BOOL)animated {}

- (void)didReceiveMemoryWarning {}


#pragma mark - Private (私有方法,比如初始控件設(shè)置方法/類內(nèi)部業(yè)務(wù)處理方法)
- (CGFloat)setupTableView {}


#pragma mark - Public (對(duì)外公開方法)
- (CGFloat)reloadAllData {}


#pragma mark - Network (加載網(wǎng)絡(luò)數(shù)據(jù))
- (void)loadMoreData {}
- (void)loadNewData {}
- (void)loadOtherData {}


#pragma mark - Property Setter/Getter (成員屬性的setter和getter方法)
- (void)setCustomProperty:(id)value {}

- (id)customProperty {}


#pragma mark - Events (UIControl響應(yīng)函數(shù),如按鈕點(diǎn)擊事件)
- (void)saveButtonClick:(UIButton *)saveButton {}


#pragma mark - KVO/Notification (KVO/通知響應(yīng)函數(shù))
- (void)dataSourceRefreshNotification:(NSNotification *)notification {}

- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString*, id> *)change context:(nullable void *)context {}


#pragma mark - Protocol/Delegate 如UITableViewDataSource/UITableViewDelegate (協(xié)議和代理)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {}


#pragma mark - LazyLoad (懶加載)
- (UILabel *)nameLabel {}


#pragma mark - Other (其他)
- (id)copyWithZone:(NSZone *)zone {}
- (NSString *)description {}


項(xiàng)目Xode相關(guān)配置


代碼縮進(jìn)配置

  • 只用空格縮進(jìn),1個(gè)TAB = 4個(gè)空格字符

XCode->Preferences->Text Editing->Indentation中進(jìn)行如下設(shè)置:
ps. 設(shè)置成4個(gè),是因?yàn)閄code的默認(rèn)縮進(jìn)是4個(gè)空格。

01.代碼格式化配置.png

代碼行號(hào)顯示配置

  • Xcode行號(hào)顯示配置

勾選上XCode->Preferences->Text Editing->Editing中的Line numbers,開啟行號(hào)提示。

02.代碼行號(hào)顯示配置.png

項(xiàng)目編碼建議

  • 建議:每行代碼的長(zhǎng)度最多不超過120個(gè)字符;

勾選XCode->Preferences->Text Editing->Editing,并將長(zhǎng)度設(shè)置成120個(gè)字符來打開行寬指示。設(shè)置成功時(shí)Xcode會(huì)出現(xiàn)一條豎線! (可選配置)

  • 建議:為了簡(jiǎn)潔和便于閱讀,請(qǐng)嘗試將單個(gè)函數(shù)或方法的實(shí)現(xiàn)代碼控制在50行內(nèi);單個(gè)實(shí)現(xiàn)文件里的代碼行數(shù)控制在500~600行內(nèi);

  • 建議:為了簡(jiǎn)潔和便于閱讀,請(qǐng)嘗試將單個(gè)函數(shù)或方法的實(shí)現(xiàn)代碼控制在50行內(nèi);當(dāng)接近或超過800行時(shí),就應(yīng)當(dāng)開始考慮分割實(shí)現(xiàn)文件了。


注釋


方法注釋

  • 方法注釋規(guī)則
    • 注釋應(yīng)該盡量保持簡(jiǎn)潔,代碼應(yīng)該盡量達(dá)到能自我解釋的程度;
    • 注釋必須和代碼保持同步。不要出現(xiàn)代碼修改了,注釋不更新的情況;
    • 對(duì)外公開方法 使用 /** 方法描述 */VVDocumenter-Xcode注釋,公開方法需盡量注釋清楚;如果公開方法有帶參數(shù),可按需對(duì)參數(shù)進(jìn)行說明;
    • 其他方法可使用 // 方法描述VVDocumenter-Xcode 注釋;
    • 方法內(nèi)部行注釋需對(duì)齊;
// .m文件
// 按鈕點(diǎn)擊事件處理 (非對(duì)外公開的方法)
- (void)saveButtonClick:(UIButton *)saveButton {
    NSLog(@"Hello Liwx");               // 打印日志
    NSLog(@"Hello Liwx");               // 打印日志
}

/** 刷新全部數(shù)據(jù) (對(duì)外公開的方法)*/
- (void)reloadAllData {
    //Do Something
}

// .h文件
/** 刷新全部數(shù)據(jù) (對(duì)外公開的方法)*/
- (void)reloadAllData;

屬性注釋

  • 建議外部屬性注釋建議使用/** 屬性描述 */注釋, 因?yàn)閄code對(duì)此類注釋有提示功能,便于開發(fā)人員在編碼時(shí)能更快的了解該屬性的作用;

  • 建議屬性與@interface ... @end之間各空1行;

@interface ViewController () 

/** 時(shí)間 */
@property (nonatomic, copy) NSString *time;

@end
03.外部屬性注釋提示.png
  • 私有屬性注釋可使用// 屬性描述/** 屬性描述 */注釋;

命名與編碼規(guī)范


類名命名規(guī)則

  • 類名命名規(guī)則
    • 類名、類別名字及協(xié)議名字,都采用大駝峰式命名規(guī)則

    • 文件名要能反映出它所包含的類的名稱

      如:NSString.h 和 NSString.m 包含了NSString類的定義和實(shí)現(xiàn)

    • Category的文件名要包含它所擴(kuò)展的那個(gè)類的名稱,并且類別名稱要盡量能夠描述它的功能

      UIImage+Resize.h 或 UIImage+TintColor.h

    • 在面向特定應(yīng)用的代碼中,類名盡量避免使用前綴,每個(gè)類都使用相同的前綴會(huì)影響可讀性

      面向特定應(yīng)用的代碼,指那些只會(huì)在一個(gè)項(xiàng)目中使用的代碼,不會(huì)被用于其他項(xiàng)目中的代碼。

    • 在面向多應(yīng)用的代碼中,類名要使用前綴,防止命名沖突

      面向多應(yīng)用的代碼,指那些會(huì)被多個(gè)項(xiàng)目共同使用的代碼。

      比如CRKit這個(gè)類庫(kù)中,使用了CR前綴。

    • 建議:前綴至少使用三個(gè)字母

      此條是為了減少命名沖突。但鑒于目前流行前綴大多都是兩個(gè)字母,所以此條不做強(qiáng)制要求


協(xié)議編碼規(guī)則

  • 協(xié)議編碼規(guī)則
    • 協(xié)議聲明或定義中,類型標(biāo)識(shí)符、協(xié)議名稱、尖括號(hào)之間不留空格;
// 協(xié)議聲明協(xié)議名稱、尖括號(hào)之間不留空格
@protocol UITableViewDelegate<NSObject, UIScrollViewDelegate>

@end
// 定義屬性遵守協(xié)議,不留空格
@property (nonatomic, weak, nullable) id <UITableViewDelegate> delegate;


控件/控制器定義命名規(guī)則

  • 控件命名盡量使用控件全稱命名,不建議使用縮寫;命名規(guī)則: [功能(name)]+[控件名(Label)]
// 建議使用控件全稱命名
/** 名稱Label */
@property (nonatomic, weak) UILabel *nameLabel;
/** 保存Button */
@property (nonatomic, weak) UIButton *saveButton;

// 不建議控件名使用縮寫
/** 名稱Label */
@property (nonatomic, weak) UILabel *nameLbl;
/** 保存Button */
@property (nonatomic, weak) UIButton *saveBtn;

  • 定義或聲明類時(shí)如果名稱過長(zhǎng)采用后綴縮寫;注意大小寫;
    • 如控制器ViewController可縮寫為Vc;
    • TableViewCell可縮寫為TvCell;
    • CollectionViewCell可縮寫為CvCell;
// TableViewCell后綴縮寫為TvCell
TopicTableViewCell *topicTvCell = nil;
// CollectionViewCell后綴縮寫為CvCell
ItemCollectionViewCell *itemCvCell = nil;
// ViewController可縮寫為Vc
HomeViewController *homeVc = nil;

方法


方法名和參數(shù)命名規(guī)則

  • 方法名和參數(shù)名都采用小駝峰式命名規(guī)則;

如:- (BOOL)isFileExistedAtPath:(NSString *)filePath;

  • 方法名可以使?用情態(tài)動(dòng)詞( can , should , will 等)來提?高清晰性,但不要使?用 do 或 does;
// 正確
- (BOOL)canHide;
- (BOOL)shouldRefreshData;
- (void)willChangeData

方法聲明和編碼規(guī)范

  • 方法聲明中,-/+返回值類型之間要空1個(gè)空格,方法名參數(shù)類型之間以及參數(shù)類型和參數(shù)名之間不留空格;
- (instancetype)initwithTitle:(NSString *)title;    // 正確
-(instancetype)initwithTitle:(NSString *)title;     // 錯(cuò)誤
- (instancetype) initwithTitle:(NSString *)title;   // 錯(cuò)誤
- (instancetype)initwithTitle: (NSString *)title;   // 錯(cuò)誤
- (instancetype)initwithTitle:(NSString *) title;   // 錯(cuò)誤
  • 方法名和參數(shù)名應(yīng)該盡量讀起來像一句話。

如:convertPoint:fromRect: 或者 replaceCharactersInRange:withString:

  • 當(dāng)各個(gè)參數(shù)是接收者的某個(gè)屬性時(shí),方法名中不要用"and"來連接;
// 正確
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil;
// 錯(cuò)誤
- (instancetype)initWithNibName:(NSString *)nibNameOrNil andBundle:(NSBundle *)nibBundleOrNil;
  • 方法名之后空1格,緊隨左大括號(hào){,無需換號(hào);但是右大括號(hào)}必須另取一行
- (CGFloat)setupTableView {
    // Do Something
}

方法調(diào)用父類方法編碼規(guī)則

  • 重載父類方法時(shí),遇到必須調(diào)用父類方法時(shí)。調(diào)用super的代碼和重載的代碼之間留一行空行。將super方法的調(diào)用和重載代碼區(qū)隔開來.
- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];

    // Do Something
}

函數(shù)

  • 函數(shù)指純C函數(shù),這里提倡與蘋果風(fēng)格類似的約定。

    • 函數(shù)名采用大駝峰式命名方式,``參數(shù)名采用小駝峰式`命名方式

    • 如果函數(shù)和某個(gè)特定類型相關(guān),那么函數(shù)名前綴要和類型前綴一樣

CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)


變量

成員屬性編碼規(guī)則

  • 屬性名變量名都采用小駝峰式命名規(guī)則;
  • 禁止使用匈牙利標(biāo)記法或含糊不清的縮寫單詞來命名變量;
  • 指針符號(hào) "*" 靠近變量名字。(常量定義除外)
  • property屬性括號(hào)兩邊各空1格, 屬性關(guān)鍵字以逗號(hào)加空格隔開
  • 除了xib拖控件的方式除外,nonatomic需放在最前面, strong,weak,assign,copy應(yīng)放在nonatomic后面;
  • 成員變量和局部變量聲明Demo
// 成員變量聲明
/** 標(biāo)題Label (正確) */
@property (nonatomic, copy) NSString *titleLabel;
/** 標(biāo)題Label (錯(cuò)誤) */
@property (nonatomic, copy) NSString *titleLbl;
/** 標(biāo)題Label (錯(cuò)誤) */
@property(nonatomic, copy) NSString *titleLabel;
/** 標(biāo)題Label (錯(cuò)誤) */
@property (nonatomic,copy) NSString *titleLabel;
/** 標(biāo)題Label (錯(cuò)誤) */
@property (copy, nonatomic) NSString *titleLabel;

// 局部變量聲明
NSString *titleLabel = nil;     //  正確
NSString* titleLabel = nil;     //  錯(cuò)誤
NSString * titleLabel = nil;    //  錯(cuò)誤
NSString*titleLabel = nil;      //  錯(cuò)誤
  • 使用property時(shí),優(yōu)先使用點(diǎn)語法;
/** 名稱 */
@property (nonatomic, copy) NSString *name;

// 訪問成員屬性時(shí),優(yōu)先使用點(diǎn)語法
self.name = @"Liwx";
  • 賦值操作符 "="兩邊各空1格;
self.name = @"Liwx";    // 正確
self.name= @"Liwx";     // 錯(cuò)誤
self.name=@"Liwx";      // 錯(cuò)誤
  • 如果使用property修飾的是屬性BOOL值,建議為getter方法加上一個(gè)"is"開頭的別名。

@property (assign, getter = isSelected) BOOL selected;

  • 如果網(wǎng)絡(luò)獲取的屬性數(shù)據(jù)為數(shù)值型的,則定義屬性也應(yīng)該為數(shù)值型;如果是枚舉類型,則應(yīng)定義對(duì)應(yīng)枚舉類型;不應(yīng)將數(shù)值型定義為NSString字符串類型;
// 正確
@property (copy,nonatomic) UserStatus *userStatus;
// 錯(cuò)誤
@property (copy,nonatomic) NSString *userStatus;

常量


Foundation框架常量賦值規(guī)則

  • 為了提高代碼簡(jiǎn)潔度,創(chuàng)建NSString, NSDictionary, NSArray, 以及NSNumber等常量時(shí),使用Literals語法;
// 正確
NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul"];
NSDictionary *productManagers = @{@"iPhone" : @"Kate", @"iPad" : @"Kamal", @"Mobile Web" : @"Bill"}; 
NSNumber *shouldUseLiterals = @YES; 
NSNumber *buildingZIPCode = @10018; 

// 錯(cuò)誤
NSArray *names = [NSArray arrayWithObjects:@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul", nil]; 
NSDictionary *productManagers = [NSDictionary dictionaryWithObjectsAndKeys: @"Kate", @"iPhone", @"Kamal", @"iPad", @"Bill", @"Mobile Web", nil]; 
NSNumber *shouldUseLiterals = [NSNumber numberWithBool:YES]; 
NSNumber *zipCode = [NSNumber numberWithInteger:10018];

定義普通常量以字母k開頭

  • 如果定義的常量是類,則格式為: [類名] + [*] + [const] + [k+常量描述];
  • 如果定義的常量屬于基本數(shù)據(jù)類型, 則格式為: [基本數(shù)據(jù)類型] + [const] + [k+常量描述];
// 普通常量定義
NSString * const kUserKey = @"kUserKey";
CGFloat const kTopViewHeight = 50;
  • 只在某一個(gè)特定文件里面使用的常量,用static

static關(guān)鍵字保證變量只有文件作用域,可以避免變量名重名造成的鏈接錯(cuò)誤問題。

如: static CGFloat const RWImageThumbnailHeight = 50.0;


枚舉與宏定義


枚舉編碼規(guī)則

  • 定義枚舉常量時(shí),使用NS_ENUMNS_OPTIONS;

因?yàn)?strong>NS_ENUM和NS_OPTIONS都提供了類型檢查;

  • 定義枚舉時(shí),一定要注釋,并且格式為: [枚舉類型名(UITableViewStyle)] + [類型(Plain)];

NS_ENUM定義普通枚舉

  • 使用NS_ENUM定義普通枚舉Demo,建議枚舉值 = 對(duì)應(yīng)數(shù)值
// 應(yīng)用皮膚樣式
typedef NS_ENUM(NSInteger, AppStyle) {
    AppStyleLight = 0,              // 白天模式
    AppStyleDark = 1                // 夜間模式
};

NS_OPTIONS定義位枚舉

  • 使用NS_OPTIONS定義位枚舉
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
    UIViewAutoresizingNone                 = 0,         // 注釋
    UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,    // 注釋
    UIViewAutoresizingFlexibleWidth        = 1 << 1,    // 注釋
    ...
};

通知和異常


通知NSNotification常量命名規(guī)則

  • 通知常量命名格式: [相關(guān)聯(lián)的類名字] + [Did | Will] + [獨(dú)一無二的一段名稱] + Notification
    • 建議:定義通知常量不采用宏定義的方法;
    • .h文件, 全局通知聲明時(shí)需加上UIKIT_EXTERN關(guān)鍵字
    • .m文件, 通知常量名和值必須保持一致
  • 通知命名Demo
// .h文件
// 全局通知聲明時(shí)需加上UIKIT_EXTERN關(guān)鍵字
UIKIT_EXTERN NSString *const UIKeyboardDidChangeFrameNotification ;

// .m文件, 通知常量名和值必須保持一致
NSString *const UIKeyboardDidChangeFrameNotification = @"UIKeyboardDidChangeFrameNotification";

異常命名規(guī)則

  • 異常名字的命名規(guī)則:[前綴] + [獨(dú)一無二的一段名稱] + Exception

如:NSColorListIOException


布爾值

  • Objective-C的布爾值只使用YESNO;
  • 注意: truefalse只能用于CoreFoundation,C或C++的代碼中;
  • 禁止將某個(gè)值或表達(dá)式的結(jié)果與YES進(jìn)行比較
// 正確
if (self.isLogin) {}
// 錯(cuò)誤
if (self.isLogin == YES) {}
  • 如果返回值為BOOL值,必須確保返回值為YES或NO,最好不要存在多值的情況
// 正確
- (BOOL)isLogin {
    return self.userToken.length != 0 ? YES : NO;
}
// 錯(cuò)誤
- (BOOL)isLogin {
    return self.userToken.length;
}

條件語句


if else 條件語句

  • 條件語句的語句體,即便只有一行,也不能省略花括弧;
  • 判斷條件之后空1格,緊隨左大括號(hào){,無需換號(hào);但是右大括號(hào)}必須另取一行;
  • else或 elseif應(yīng)緊隨在右大括號(hào)}之后,并且中間空1格;
// 正確
if (isLogin) {
    // Do Something
} else {
    // DO Something
}

// 錯(cuò)誤
if (isLogin) 
{
    // Do Something
} 
else {
    // DO Something
}
// 正確
if (error == nil) {
    return success;
}
// 錯(cuò)誤
if (error == nil)
    return success;
  • 多層嵌套的條件語句,優(yōu)先考慮條件不成立可以立即跳出的情況
// 優(yōu)先考慮可以跳出的流程
if (!a) {
    return;
}

if (!b) {
    return;
}

if (!c) {
    return;
}

// 不建議使用嵌套的方式
if (a) {
    if (b) {
        if (c) {
        } 
    } 
} 
  • 三目運(yùn)算只有在能增加代碼清晰度和整潔度的時(shí)候才推薦使用
// 正確
NSInteger value = 5;
result = (value != 0) ? x : y;
// 錯(cuò)誤
result = a > b ? x = c > d ? c : d : y;

switch case 語句

  • switch case如果判斷條件是枚舉類型的值,則case也應(yīng)該為枚舉值,而不是 case 1;并且可以省略default處理
RWTLeftMenuTopItemType menuType = RWTLeftMenuTopItemMain;

switch (menuType) {
  case RWTLeftMenuTopItemMain:
    // ...
    break;
  case RWTLeftMenuTopItemShows:
    // ...
    break;
  case RWTLeftMenuTopItemSchedule:
    // ...
    break;
}

其他規(guī)則


初始化方法(構(gòu)造方法)規(guī)則

  • 初始化方法的返回類型用instancetype,而不是用id;
  • 如果重寫init方法,必須調(diào)用[super init]方法;

直接放回對(duì)應(yīng)數(shù)據(jù)時(shí),無需添加get, calc單詞

- (CGFloat)cellHeight;      // 正確
- (CGFloat)getCellHeight;   // 錯(cuò)誤
- (CGFloat)calcCellHeight;  // 錯(cuò)誤

單例的聲明和使用規(guī)則

  • 獲取單例的類方法
+ (instancetype)sharedInstance {
    static id sharedInstance = nil;
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    
    return sharedInstance;
}
  • UIApplication的使用規(guī)則
    • 獲取單例的方法不使用點(diǎn)語法;
// 正確
[UIApplication sharedApplication].delegate;
// 錯(cuò)誤
UIApplication.sharedApplication.delegate;

設(shè)置常用屬性,直接使用點(diǎn)語法

// 正確
self.view.backgroundColor = [UIColor redColor];
// 錯(cuò)誤
[self.view setBackgroundColor:[UIColor redColor]];

協(xié)議和代理方法命名規(guī)則

  • 協(xié)議方法名開頭應(yīng)與類名一樣(不包含前綴)
  • 必須將本身作為參數(shù)傳遞給外部,如(UITableView *)tableView
  • 傳遞所需參數(shù)給外部,如(NSIndexPath *)indexPath;

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath;


可以使用({})語法模塊化設(shè)置控件屬性(可選)

  • 要使用({})語法,前提: 該屬性需由strong修飾;
// 前提: 該屬性需由strong修飾
/** 名稱Label */
@property (nonatomic, strong) UILabel *nameLabel;

self.nameLabel = ({
        UILabel *label = [[UILabel alloc] init];
        label.textAlignment = NSTextAlignmentCenter;
        label.font = [UIFont systemFontOfSize:12];
        label.textColor = [UIColor orangeColor];
        label;
    });

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容