1. 背景
因為種種原因,當了回接盤俠.
拿到一個運動類APP, 一打開,我去,編譯了好半天,文件大的不得了. 然后就看見那個warning蹭蹭蹭的往上漲.
等編譯完定睛一看,我擦371個warning.
雖然這只是warning,不影響APP的正常運行.
但是:
且不說,影響編譯效率,耗費時間,而且有潛在bug風險,光本著強迫癥習慣這一個理由,就足以決定先停下其他事情,把warning清一清.
否則,根本無心工作啊...
2. 開始清
剛好是端午節, 除了第一天陪妹子去無錫玩了一天,剩下兩天就耗在這個上面了.
不過意外在徐匯發現一個不錯的圖書館:Instituto Cervantes(塞萬提斯圖書館)(就是寫堂吉訶德的那個作者),整個清理過程大部分就是在這里完成的:
清理完,長呼一口氣...
okey,下面是清理完的截圖:
polen: 最后一個warning是CocoaLumberjack的自定義一個紅開關warning,嚴格說就不算warning了,暫且忽略之...
<br >
3. 回顧下都有哪些warning
雖然數量很多,但是種類來說,其實就那么幾條. 因為里面大部分warning都是C/C++代碼的warning,其實對iOS開發的指導意義并不大,這里挑選其中比較有用或者有意義的整理下:
3.1 方法棄用類
3.1.1 sizeWithFont
iOS 7.0以前獲取字體所占空間大小的方法,很好用.不過現在棄用了,這個很好改(用新方法:boundingRectWithSize
):
官方說明:
- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(NSLineBreakMode)lineBreakMode
NS_DEPRECATED_IOS(2_0, 7_0, "Use -boundingRectWithSize:options:attributes:context:") __TVOS_PROHIBITED;
// NSTextAlignment is not needed to determine size
FIX:
寫了個NSString的Category,里面實現了boundingRectWithSize
,所有用到的地方直接調用這個就可以了.
- (CGSize)sizeOfFont:(UIFont*)font andWidth:(float)width {
NSDictionary* attribute = @{NSFontAttributeName : font};
CGSize retSize =
[self boundingRectWithSize:CGSizeMake(width, 9999999)
options:NSStringDrawingTruncatesLastVisibleLine |
NSStringDrawingUsesLineFragmentOrigin |
NSStringDrawingUsesFontLeading
attributes:attribute
context:nil]
.size;
return retSize;
}
<br >
3.1.2 NSDateComponents.week
做過日歷的童鞋肯定懂,關于NSDateComponents的week,新增了weekOfMonth or weekOfYear
,以前直接調用week的方法棄用了.
官方說明:
- (NSInteger)week
NS_CALENDAR_DEPRECATED(10_4, 10_9, 2_0, 7_0, "Use weekOfMonth or weekOfYear, depending on which you mean");
- (void)setWeek:(NSInteger)v
NS_CALENDAR_DEPRECATED(10_4, 10_9, 2_0, 7_0, "Use setWeekOfMonth: or setWeekOfYear:, depending on which you mean");
這個改起來稍微麻煩一點,也還好,這個是在顯示時間的地方(顯示類似"3周前")代碼里使用了
NSDate+Helper
這個開源庫,但是源碼Github上找不到了,
隨徒手改之:
FIX:
- (NSInteger)weeksFrom:(NSDate*)date calendar:(NSCalendar*)calendar {
if (!calendar) {
calendar = [[self class] implicitCalendar];
}
NSDate* earliest = [self earlierDate:date];
NSDate* latest = (earliest == self) ? date : self;
NSInteger multiplier = (earliest == self) ? -1 : 1;
NSDateComponents* components = [calendar components:NSCalendarUnitWeekOfYear
fromDate:earliest
toDate:latest
options:0];
return multiplier * components.weekOfYear;
}
<br >
3.2 Directory not found for option ...
這個是編譯時找不到對應的framework,可能這個framework你已經不用了,但是Search Paths 沒有清除掉.在build setting->Framework Search Paths 刪除掉你Not found的目錄即可.
參照:
消除 Xcode7 中 directory not found for option 'xxxx' 警告
Apple Developer: warning: directory not found
<br >
3.3 The app icon set "AppIcon" has an unassigned child
這個是images.scassets 出了問題,找到你的AppIcon,刪除掉Unassigned的圖片即可,(如果是空的也要刪除)
參照:
http://stackoverflow.com/questions/29433670/app-icon-has-unassigned-image-error
<br >
3.4 'kCFStreamSSLAllowsExpiredCertificates' is deprecated: fitst deprecated in iOS 4.0
官方說明:
kCFStreamSSLAllowsExpiredCertificates:
kCFStreamSSLAllowsExpiredRoots:
kCFStreamSSLAllowsAnyRoot:
The SSL handshake flags which affect untrusted certificate chain evaluation are deprecated. Instead, use the single property kCFStreamSSLValidatesCertificateChain to disable certificate chain checking if the user has decided that it is appropriate to do so
So the simple solution is to remove the deprecated keys and their values. Keep only kCFStreamSSLValidatesCertificateChain and kCFStreamSSLPeerName in the sslProperties dictionary.
這個代碼沒有用AFNetwork,用的是ASIHttpRequest(看來也是代碼比較長久了...)
kCFStreamSSLAllowsExpiredCertificates
已經棄用了.
FIX:
方案A: 移除掉就可以了.
NSDictionary* sslProperties = [[NSDictionary alloc]
initWithObjectsAndKeys:[NSNumber numberWithBool:NO],
kCFStreamSSLValidatesCertificateChain, kCFNull,
kCFStreamSSLPeerName, nil];
方案B: 加一條
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
.
參照:
<br >
3.4 'delete' applied to a pointer that was allocated with 'new[]';did you mean 'delete[]'?
這是c++的代碼,delete刪除的時候,如果對象是new[]出來的,對應刪除需要采用delete[].這個估計是當時寫代碼的家伙手抖了,筆誤...
polem:
記住規則:malloc/free, new/delete, new[]/delete[])
官方說明
In the first alternative (delete object), the value of the operand of delete shall be a pointer to a non-array object or a pointer to a sub-object (1.8) representing a base class of such an object (clause 10). If not, the behavior is undefined.
In the second alternative (delete array), the value of the operand of delete shall be the pointer value which resulted from a previous array new-expression. If not, the behavior is undefined.
delete :
calls the appropriate destructor only for the element pointed to (if needed), then frees the memory chunk
delete[] :
calls the appropriate destructors for each element in its array (if needed), then frees the memory chunk
參照:
http://stackoverflow.com/questions/4255598/delete-vs-delete
FIX:
delete[] session_info_buf;
<br >
3.5 'Register' storage class specifier is deprecated
register作為關鍵字修飾的變量,意思其修飾的變量可能會被頻繁調用,所以期望保存在CPU的寄存器中(一般都是存在堆或者棧之中),這樣可以加快處理速度.(補充:標識符的類型知識可以看這里
)
但是如今的編譯器并不會太理會這些東西,所以有點"然并卵"的即視感. 后來,C++17中直接給棄用掉了.
鏈接:
http://en.cppreference.com/w/cpp/language/storage_duration
FIX:
方案A:直接刪掉register就好了
int myrandom32() {
if (_rg.Null()) {
int a;
int b;
tUInt32 c;
...
方案B:
忽略掉這個警告,-Wdeprecated-register
#pragma clang diagnostic ignored "-Wdeprecated-register"
參照這里:http://stackoverflow.com/questions/22422741...
<br >
3.6 Automatic Preferred Max Layout Width before iOS 8.0
瞧瞧,瞧瞧,多少這種warning,這種就是懶,在做layout 的時候,設置了labe的numberoflines 是0, 但是沒設置Preferred Width導致的.當然這里面有個比較麻煩的時候,如果xib有多個label,逐個去找哪個沒設置,是比較耗費時間和精力的,但是xcode的warning又沒有詳細的告訴你是哪個label出問題了(很不人性化),所以需要看Source Code里的id對應到label 的Object Id,具體看這里:
To Find the problem label(s) in a large storyboard...
Fix:
<br >
3.7 ignore waning
其他很多warning是c代碼里面的,unused或者類型不對的,什么long和int或者unsigned int等等,這些沒啥技術含量,逐個修改就好了.
最后還有一個萬能方法是:如果你已經百分百確定這個文件的warning不用修復,百分百確定是安全的,那么你可以忽略這個警告.
(如果有些同學是從MRC 過度到ARC的,那就知道這里(設置-fno-objc-arc
的地方))
加一個-w
即可
Target->Build Phases->Compile Sources->對應的文件
<br >
by polen