小技巧四:iOS開發(fā)遇到的問題及解決辦法

一.統(tǒng)計(jì)應(yīng)用中代碼的總行數(shù)

每一個(gè)程序員都想在開發(fā)完成之后知道總共寫了多少行的代碼,這里有一個(gè)比較簡(jiǎn)單的方法。

1、打開終端

2、cd 進(jìn)入項(xiàng)目根目錄,這里的根目錄可以是你這個(gè)項(xiàng)目的根目錄,也可以是你想統(tǒng)計(jì)那個(gè)文件夾的根目錄。這里以yykit為例子進(jìn)行測(cè)試。

3、輸入命令 find . "(" -name "*.m" -or -name "*.mm" -or -name "*.cpp" -or -name "*.h" -or -name "*.rss" ")" -print | xargs wc -l ?這是可以統(tǒng)計(jì)每個(gè)文件的行數(shù)和總行數(shù)

find . -name "*.m" -or -name "*.h" -or -name "*.xib" -or -name "*.c" |xargs grep -v "^$"|wc -l ?這是可以直接統(tǒng)計(jì)總共的行數(shù),不顯示每個(gè)文件的行數(shù)

4、回車

圖01


圖02

說明:這里統(tǒng)計(jì)的行數(shù)包括系統(tǒng)頭文件里面的代碼,系統(tǒng)框架里面的代碼,所以比你自己寫的代碼要多一點(diǎn)。如果想統(tǒng)計(jì)自己寫了多少,只需要cd到自己代碼的文件夾下,輸入find . "(" -name "*.m" -or -name "*.mm" -or -name "*.cpp" -or -name "*.h" -or -name "*.rss" ")" -print | xargs wc -l,回車即可。

二、release版本禁止輸出NSLog內(nèi)容

前提:在XCode做開發(fā)調(diào)試時(shí)往往需要打印一些調(diào)試信息做debug用,大家知道當(dāng)打印信息的地方多了之后在模擬器上跑可能不會(huì)有什么問題,因?yàn)槟M器用的是電腦的硬件但是當(dāng)應(yīng)用跑在設(shè)備上時(shí)這些輸出語句會(huì)在很大程度上影響應(yīng)用的性能,針對(duì)這種問題可以寫一些宏來控制這些調(diào)試信息的輸出。

在release版本禁止輸出NSLog內(nèi)容

因?yàn)镹SLog的輸出還是比較消耗系統(tǒng)資源的,而且輸出的數(shù)據(jù)也可能會(huì)暴露出App里的保密數(shù)據(jù),所以發(fā)布正式版時(shí)需要把這些輸出全部屏蔽掉。

我們可以在發(fā)布版本前先把所有NSLog語句注釋掉,等以后要調(diào)試時(shí),再取消這些注釋,這實(shí)在是一件無趣而耗時(shí)的事!還好,還有更優(yōu)雅的解決方法,就是在項(xiàng)目的prefix.pch文件里加入下面一段代碼,加入后,NSLog就只在Debug下有輸出,Release下不輸出了。

如何實(shí)現(xiàn):

在-Prefix.pch(pch全稱是“precompiled header”,也就是預(yù)編譯頭文件,該文件里存放的工程中一些不常被修改的代碼,比如常用的框架頭文件,這樣做的目的提高編譯器編譯速度。我們知道當(dāng)我們修改一個(gè)工程中某個(gè)文件代碼時(shí)候,編譯器并不是重新編譯所有所有文件,而是編譯改動(dòng)過文件的,假如pch中某個(gè)文件修改了,那么pch整個(gè)文件里包含的的其他文件也會(huì)重新編譯一次,這樣就會(huì)消耗大量時(shí)間,所以它里面添加的文件最好是是很少變動(dòng)或不變動(dòng)的頭文件或者是預(yù)編譯的代碼片段;)文件中添加

1#ifdef DEBUG

2#define NSLog(...) NSLog(__VA_ARGS__)

3#define debugMethod() NSLog(@"%s",__func__)

4#else

5#define NSLog(...)

6#define debugMethod()

7#endif

上段代碼的意思就是用宏指令做一個(gè)判斷,如果DEBUG為真,則編譯#ifdef到#endif宏定義,否則編譯器就不編譯;這個(gè)DEBUG在哪設(shè)置呢,在"Target > Build Settings >

Preprocessor Macros > Debug"里有一個(gè)"DEBUG=1"。設(shè)置為Debug模式下,Product-->Scheme-->SchemeEdit Scheme

設(shè)置Release,發(fā)布app版本的時(shí)候就不會(huì)打印了,提高了性能

三、修改項(xiàng)目APP名字后,在真機(jī)運(yùn)行報(bào)錯(cuò):

錯(cuò)誤提醒:The provisioning profile specified in yourbuild settings (“haotian”) has an AppID of “com.basecom.vipose” which does notmatch your bundle identifier “com.baseus.iTemperature”.? Xcode can resolvethis issue by downloading a new provisioning profile from the Member Center.

原因:是我在xxx-info.plist中Bundle display name的值(用來改變APP在左邊顯示的名字),修改后再在真機(jī)運(yùn)行就報(bào)這個(gè)錯(cuò)誤!,描述文件不對(duì),設(shè)置好相應(yīng)的描述文件就行。

解決辦法:參考地址:http://stackoverflow.com/questions/1760518/codesign-error-provisioning-profile-cannot-be-found-after-deleting-expired-prof

這里所說的就是要通過修改你的項(xiàng)目的.xcodeproj文件來解決上述的錯(cuò)誤。

1.找到項(xiàng)目中的**.xcodeproj文件,點(diǎn)擊右鍵,showpackage contents(打開包內(nèi)容)。

2.打開后找到project.pbxproj文件,用文本編輯器打開。其實(shí)就是右鍵,點(diǎn)擊open就好了。

3.打開這個(gè)文件后,按command+F,在這個(gè)文件中查找“PROVISIONING_PROFILE",找到和這個(gè)“

四、UUID和UDID 區(qū)別

UUID(Universally Unique IDentifier)是基于iOS設(shè)備上面某個(gè)單個(gè)的應(yīng)用程序,只要用戶沒有完全刪除應(yīng)用程序,則這個(gè)UUID在用戶使用該應(yīng)用程序的時(shí)候一直保持不變。如果用戶刪除了這個(gè)應(yīng)用程序,然后再重新安裝,那么這個(gè)UUID已經(jīng)發(fā)生了改變。通過調(diào)用[[UIDevice currentDevice]identifierForVendor];方法可以獲取UUID。UUID不好的地方就是用戶刪除了你開發(fā)的程序以后,基本上你就不可能獲取之前的數(shù)據(jù)了。

UDID(Unique Device Identifier)是一串由40位16進(jìn)制數(shù)組成的字符串,用以標(biāo)識(shí)唯一的設(shè)備,現(xiàn)在想通過代碼獲取是不可能的了,如果你想看看你設(shè)備的UDID,可以通過iTunes來查看。蘋果從iOS5開始就移除了通過代碼訪問UDID的權(quán)限,所以碼農(nóng)啊,想知道用戶設(shè)備的UDID,是不行的嘍。

五、Xcode6+環(huán)境下,對(duì)iPhone5或iPhone5s模擬器,在iOS7或iOS7.1下運(yùn)行,屏幕上下有黑邊

問題描述:

Xcode6環(huán)境下,對(duì)iPhone5或iPhone5s模擬器,在iOS7或iOS7.1下運(yùn)行,屏幕上下有黑邊。在iOS8下沒問題。

問題分析:

其實(shí)可以發(fā)現(xiàn),不只是上下留白的問題,在這種狀態(tài)下LaunchScreen其實(shí)根本沒有加載。

原因可想而知了。沒有相對(duì)應(yīng)的啟動(dòng)圖。

Xcode6在Xcode5的基礎(chǔ)上,做出的一些調(diào)整,其實(shí)并不是向下兼容的。Xcode5在啟動(dòng)頁通過images asset進(jìn)行管理,而到了Xcode6,蘋果引入了一種新的啟動(dòng)頁機(jī)制:LaunchScreen.xib,而這種機(jī)制恰恰是不向下兼容的。Xcode6已經(jīng)自動(dòng)為iPhone6以上的模擬器強(qiáng)制使用iOS8+系統(tǒng),iPhone 6 (7.1)這種模擬器是不存在的(至少我沒有找到),因此對(duì)于iPhone 6以上的模擬器,不存在這個(gè)問題,對(duì)于iPhone 4s模擬器,在iOS7.1下也僅僅是沒有加載LaunchScreen.xib,這種蘋果最為古老的屏幕尺寸當(dāng)然不存在留白的狀況。但對(duì)于iPhone5/5s +

iOS7/7.1,由于iOS7無法兼容LaunchScreen.xib這種機(jī)制,而又找不到對(duì)應(yīng)的default-568h.png文件,問題自然就出現(xiàn)了。

問題解決:

在項(xiàng)目配置頁,General下面有一欄App Icons and Launch Images,其中有一項(xiàng)Launch Images Source,如果你遇到了問題,那么旁邊顯示的可能是一個(gè)按鈕,Use Asset

Catalog,點(diǎn)一下然后確定就可以了,會(huì)在項(xiàng)目中的Images.xcassets中生成LaunchImage,就像Xcode5中那樣。此時(shí)再運(yùn)行程序,已經(jīng)不會(huì)再有上下的黑邊問題了。但為了更好的用戶體驗(yàn),做張圖片放進(jìn)去吧。當(dāng)然,在iOS8中依然會(huì)加載LaunchScreen.xib,看來至少二者是可以共存的。

六、iOS開發(fā)6-Xcode使用第三方字體

Xcode自帶中文字體:PingFang

HK(香港)PingFang TC(繁體)PingFang SC(簡(jiǎn)體)。但是我們有時(shí)候還是需要其他的中文字體,這時(shí)候就要將字體庫加入到工程中。

目前網(wǎng)上有很多字體資源,這里推薦一個(gè):http://font.knowsky.com/

1、將字體加入到工程中

檢查一下字體是否被加入到了project中,可去Build?Phases下的Copy?Bundle?Resources中找一下。如果沒有,點(diǎn)擊+來添加。


01

2、設(shè)置info.plist文件

在info.plist文件中添加"Fonts provided by application"選項(xiàng).選擇+號(hào),將字體文件名添加上。


02


03

3、使用字體


1.NSMutableArray*familyNames?=?[UIFontfamilyNames].mutableCopy;

2.[familyNamessortUsingSelector:@selector(compare:)];

3.for(NSString*familyName?in?familyNames?){

4.printf("Family:?%s?\n",?[familyNameUTF8String]?);

5.NSArray*fontNames?=?[UIFontfontNamesForFamilyName:familyName];

6.for(NSString*fontName?in?fontNames?){

7.printf("\tFont:?%s?\n",?[fontNameUTF8String]?);

8.}

9.}//打印出所有的字體

10./*

11.

12.Family:?FZCaiYun-M09//方正彩云

13.Font:?FZCYK--GBK1-0

14.Family:?FZKai-Z03//方正楷體

15.Font:?FZKTK--GBK1-0

16.Family:?Bradley?Gratis

17.Font:?BradleyGratis

18.

19.*/

20.

21.self.label1.text=@"hello";

22.self.label2.text=@"你好";

23.self.label3.text=@"你好";

24.//使用字體

25.self.label1.font=[UIFontfontWithName:@"BradleyGratis"size:20];

26.self.label2.font=[UIFontfontWithName:@"FZCaiYun-M09"size:20];

27.self.label3.font=[UIFontfontWithName:@"FZKTK--GBK1-0"size:20];

4、效果

04

七、用instancetype代替id作返回類型有什么好處?


蘋果在iOS 8中全面使用instancetype代替id


對(duì)于簡(jiǎn)易構(gòu)造函數(shù)(convenience constructor),應(yīng)該總是用instancetype。編譯器不會(huì)自動(dòng)將id轉(zhuǎn)化為instancetype。id是通用對(duì)象,但如果你用instancetype,編譯器就知道方法返回什么類型的對(duì)象。initializer的情況更復(fù)雜,當(dāng)你輸入

- (id)initWithBar:(NSInteger)bar

編譯器會(huì)假設(shè)你輸入了

- (instancetype)initWithBar:(NSInteger)bar

對(duì)于ARC而言,這是必須的。Clang Language Extensions的相關(guān)結(jié)果類型(Related result types)也講到了這一點(diǎn)。也許別人會(huì)據(jù)此告訴你不必使用instancetype,但我建議你用它。下面解釋我為什么如此建議。

使用instancetype有三點(diǎn)好處:

1、明確性。代碼只做你讓它做的事,而不是其他。

2、程式化。你會(huì)養(yǎng)成好習(xí)慣,這些習(xí)慣在某些時(shí)候會(huì)很有用,而且肯定有用武之地。

3、一致性。讓代碼可讀性更好。

明確性

用instancetype代替id作為返回值的確沒有技術(shù)上的好處。但這是因?yàn)榫幾g器自動(dòng)將id轉(zhuǎn)化成了instancetype。你以為init返回的值類型是id,其實(shí)編譯器返回了instancetype。

這兩行代碼對(duì)于編譯器來說是一樣的:

- (id)initWithBar:(NSInteger)bar; - (instancetype)initWithBar:(NSInteger)bar;

但在你眼里,這兩行代碼卻不同。你不該學(xué)著忽視它。

模式化

在使用init等方法時(shí)的確沒有區(qū)別,但在定義簡(jiǎn)易構(gòu)造函數(shù)時(shí)就區(qū)別了。

這兩行代碼并不等價(jià):

+ (id)fooWithBar:(NSInteger)bar; + (instancetype)fooWithBar:(NSInteger)bar;

如果用instancetype作為函數(shù)的返回類型,就不會(huì)出錯(cuò)。

一致性:

最后,想象把所有東西放到一起時(shí)的情景:你想要一個(gè)init方法和一個(gè)簡(jiǎn)易構(gòu)造函數(shù)。

如果你用id來作為init函數(shù)的返回類型,最終代碼如下:

- (id)initWithBar:(NSInteger)bar; + (instancetype)fooWithBar:(NSInteger)bar;

但如果你用instancetype,代碼如下:

- (instancetype)initWithBar:(NSInteger)bar; + (instancetype)fooWithBar:(NSInteger)bar;

代碼更加一致,可讀性更強(qiáng)。它們返回相同的東西,這一點(diǎn)一目了然。

結(jié)論

除非你有意為舊編譯器寫代碼,不然你在合適的時(shí)候都應(yīng)該用instancetype。

在寫一條返回id的消息前,問自己:這個(gè)類返回實(shí)例嗎?如果返回,用instancetype。

肯定有需要返回id的時(shí)候,但你用instancetype的頻率應(yīng)該會(huì)更高。



八 NSbundle

bundle是一個(gè)目錄,其中包含了程序會(huì)使用到的資源.這些資源包含了如圖像,聲音,編譯好的代碼,nib文件(用戶也會(huì)把bundle稱為plug-in).對(duì)應(yīng)bundle,cocoa提供了類NSBundle.

我們的程序是一個(gè)bundle.在Finder中,一個(gè)應(yīng)用程序看上去和其他文件沒有什么區(qū)別.但是實(shí)際上它是一個(gè)包含了nib文件,編譯代碼,以及其他資源的目錄.我們把這個(gè)目錄叫做程序的main bundle

bundle中的有些資源可以本地化.例如,對(duì)于foo.nib,我們可以有兩個(gè)版本:一個(gè)針對(duì)英語用戶,一個(gè)針對(duì)法語用戶.在bundle中就會(huì)有兩個(gè)子目錄:English.lproj和French.lproj,我們把各自版本的foo.nib文件放到其中.當(dāng)程序需要加載foo.nib文件時(shí),bundle會(huì)自動(dòng)根據(jù)所設(shè)置的語言來加載.我們會(huì)在16章再詳細(xì)討論本地化

通過使用下面的方法得到程序的main bundle

NSBundle *myBundle= [NSBundle mainBundle];

一般我們通過這種方法來得到bundle.如果你需要其他目錄的資源,可以指定路徑來取得bundle

NSBundle*goodBundle;

goodBundle =[NSBundle bundleWithPath:@"~/.myApp/Good.bundle"];

一旦我們有了NSBundle對(duì)象,那么就可以訪問其中的資源了

// Extension is optional

NSString *path =[goodBundle pathForImageResource:@"Mom"];

NSImage *momPhoto= [[NSImage alloc] initWithContentsOfFile:path];

bundle中可以包含一個(gè)庫.如果我們從庫得到一個(gè)class, bundle會(huì)連接庫,并查找該類:

Class newClass =[goodBundle classNamed:@"Rover"];

id newInstance =[[newClass alloc] init];

如果不知到class名,也可以通過查找主要類來取得

Class aClass =[goodBundle principalClass];

id anInstance =[[aClass alloc] init];

可以看到, NSBundle有很多的用途.在這當(dāng)中, NSBundle負(fù)責(zé)(在后臺(tái))加載nib文件.我們也可以不通過NSWindowController來加載nib文件,直接使用NSBundle:

BOOL successful =[NSBundle loadNibNamed:@"About" owner:someObject];

注意噢,我們指定了一個(gè)對(duì)象someObject作為nib的File's Owner

使用initWithContentsOfFile時(shí),文件路徑的寫法使用initWithContentsOfFile方法可以通過讀取一個(gè)文件的內(nèi)容來初始化對(duì)象。但文件的路徑應(yīng)該怎么確定呢?可以使用NSBundle的對(duì)象來獲取。例如當(dāng)前程序所在目錄下有個(gè)文件re.xml,我們要將該文件的內(nèi)容做為NSData的數(shù)據(jù)源來初始化一個(gè)NSData對(duì)象,可以用下面的方法來實(shí)現(xiàn):?

NSString *filePath= [[NSBundle mainBundle] pathForResouse:@"re" ofType:@"xml"];NSData *data = [[NSData alloc] initWithContentsOfFile:filePath];

讀取plist中的內(nèi)容:

NSString *dataPath= [[NSBundle mainBundle] pathForResource:@"Data"ofType:@"plist"]; self.data = [NSArrayarrayWithContentsOfFile:dataPath];

刪除本地文件

NSString * thePath=[selfgetUserDocumentDirectoryPath];

NSMutableString *fullPath=[[[NSMutableString alloc]init]autorelease];

[fullPathappendString:thePath];

NSString *idString=[idArray objectAtIndex:indexPath.row];

NSString *coverName=[NSString stringWithFormat:@"/%@.jpg",idString];

[fullPathappendString:coverName];

NSFileManager*defaultManager;

defaultManager =[NSFileManager defaultManager];

-(BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error BOOLboolValue=[defaultManager removeItemAtPath: fullPath error: nil];

if (boolValue) {

NSLog(@"removecover image ok");

}

-(NSString*)getUserDocumentDirectoryPath {

NSArray* array =NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask,YES);

if([array count])

return [arrayobjectAtIndex: 0];

else return@"";

} ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

九、數(shù)組和鏈表的區(qū)別

二者都屬于一種數(shù)據(jù)結(jié)構(gòu)

從邏輯結(jié)構(gòu)來看

1.數(shù)組必須事先定義固定的長(zhǎng)度(元素個(gè)數(shù)),不能適應(yīng)數(shù)據(jù)動(dòng)態(tài)地增減的情況。當(dāng)數(shù)據(jù)增加時(shí),可能超出原先定義的元素個(gè)數(shù);當(dāng)數(shù)據(jù)減少時(shí),造成內(nèi)存浪費(fèi);數(shù)組可以根據(jù)下標(biāo)直接存取。

2.鏈表動(dòng)態(tài)地進(jìn)行存儲(chǔ)分配,可以適應(yīng)數(shù)據(jù)動(dòng)態(tài)地增減的情況,且可以方便地插入、刪除數(shù)據(jù)項(xiàng)。(數(shù)組中插入、刪除數(shù)據(jù)項(xiàng)時(shí),需要移動(dòng)其它數(shù)據(jù)項(xiàng),非常繁瑣)鏈表必須根據(jù)next指針找到下一個(gè)元素

從內(nèi)存存儲(chǔ)來看

1. (靜態(tài))數(shù)組從棧中分配空間,對(duì)于程序員方便快速,但是自由度小

2.鏈表從堆中分配空間,自由度大但是申請(qǐng)管理比較麻煩

從上面的比較可以看出,如果需要快速訪問數(shù)據(jù),很少或不插入和刪除元素,就應(yīng)該用數(shù)組;相反,如果需要經(jīng)常插入和刪除元素就需要用鏈表數(shù)據(jù)結(jié)構(gòu)了。

十、objectForKey:和valueForKey區(qū)別

從NSDictionary取值的時(shí)候有兩個(gè)方法,objectForKey:和valueForKey:,這兩個(gè)方法具體有什么不同呢?

先從NSDictionary文檔中來看這兩個(gè)方法的定義:

objectForKey: returns the value associated

with aKey, or nil if no value is associated with aKey.返回指定key的value,若沒有這個(gè)key返回nil.

valueForKey: returns the value associated

with a given key.同樣是返回指定key的value。

直觀上看這兩個(gè)方法好像沒有什么區(qū)別,但文檔里valueForKey:有額外一點(diǎn):

If key does not start with “@”, invokesobjectForKey:. If key does start with “@”, strips the “@” and invokes [supervalueForKey:] with the rest of the key. via Discussion

一般來說key可以是任意字符串組合,如果key不是以@符號(hào)開頭,這時(shí)候valueForKey:等同于objectForKey:,如果是以@開頭,去掉key里的@然后用剩下部分作為key執(zhí)行[super valueForKey:]。

比如:

NSDictionary*dict = [NSDictionary dictionaryWithObject:@"theValue"

forKey:@"theKey"];

NSString*value1 = [dict objectForKey:@"theKey"];

NSString*value2 = [dict valueForKey:@"theKey"];

這時(shí)候value1和value2是一樣的結(jié)果。如果是這樣一個(gè)dict:

NSDictionary*dict = [NSDictionary dictionaryWithObject:@"theValue"

forKey:@"@theKey"];//注意這個(gè)key是以@開頭

NSString*value1 = [dict objectForKey:@"@theKey"];

NSString*value2 = [dict valueForKey:@"@theKey"];

value1可以正確取值,但是value2取值會(huì)直接crash掉,報(bào)錯(cuò)信息:

Terminating app due to uncaught exception‘NSUnknownKeyException’, reason: ‘[<__NSCFDictionary 0x892fd80>valueForUndefinedKey:]: this class is not key value coding-compliant for thekey theKey.’

這是因?yàn)関alueForKey:是KVC(NSKeyValueCoding)的方法,在KVC里可以通過property同名字符串來獲取對(duì)應(yīng)的值。比如:

@interface Person : NSObject

@property (nonatomic, retain) NSString*name;

@end

Person *person= [[Person alloc] init];

person.name = @"fannheyward";

NSLog(@"name:%@",[person name]);

NSLog(@"name:%@",[person valueForKey:@"name"]);

valueForKey:取值是找和指定key同名的property

accessor,沒有的時(shí)候執(zhí)行valueForUndefinedKey:,而valueForUndefinedKey:的默認(rèn)實(shí)現(xiàn)是拋出NSUndefinedKeyException異常。

回過頭來看剛才crash的例子,[dict valueForKey:@"@theKey"];會(huì)把key里的@去掉,也就變成了[dict valueForKey:@"theKey"];,而dict不存在theKey這樣的property,轉(zhuǎn)而執(zhí)行[dict

valueForUndefinedKey:@"theKey"];,拋出NSUndefinedKeyException異常后crash掉。

objectForKey:和valueForKey:在多數(shù)情況下都是一樣的結(jié)果返回,但是如果key是以@開頭,valueForKey:就成了一個(gè)大坑,建議在NSDictionary下只用objectForKey:來取值。

最后編輯于
?著作權(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)容