在iOS開發過程中,我一直習慣於使用C語法里的基本類型,而很少用(除非必須使用)Foundation的數據類型。最近看了一些資料,發現自己這樣寫可能有風險,雖然目前沒遇到過相關的問題,但這是非常需要註意的一點。 新博客 "wossoneri.com" 壞習慣的開端 初寫iOS時,我做的是把原項目從
在iOS開發過程中,我一直習慣於使用C語法里的基本類型,而很少用(除非必須使用)Foundation的數據類型。最近看了一些資料,發現自己這樣寫可能有風險,雖然目前沒遇到過相關的問題,但這是非常需要註意的一點。
壞習慣的開端
初寫iOS時,我做的是把原項目從Android
端移植到iOS
端。因為涉及到不同語言,又因為不熟悉iOS
,加上還要與用C
寫的網路庫進行糾纏,我小心翼翼的用了基本數據類型完成大多數編碼。能用int
就堅決不用NSInteger
,能用float
就堅決不用CGFloat
。你可能會問,雖然這個過程用到的語言很雜,寫Objective-C
的時候就大膽的用Foundation
的數據類型唄。想法很好,只是當時我看不懂我們網路庫實現原因不敢亂改代碼,怕傷著哪個地方的邏輯,最後代碼移著移著,我的.m
文件就變成了.mm
文件——對,變成Objective-C
和C++
混編代碼了。當時就索性一股腦的用C
語言的基本數據類型去做了。現在想想我入門iOS
的過程真是坎坷呢,留下了一堆爛毛病。
不過好在我現在開始拼命的多看資料,一點點把走的彎路走回來。
一次突然的疑問
平時也會看Github
上面的一些代碼,發現代碼里用到int
的比較少,用NSInteger
的比較多,於是就考慮了一下這個問題:這兩種類型有啥區別?
這裡不得不吐槽一下
這本書,當初就是看這本書瞭解O-C語法的,可書上的介紹與代碼全是 int
的,完全沒見NSInteger
的影子。可見學習這事不能只靠一本書,畢竟書的內容覆蓋面有限。
關於NSInteger和int的優劣
從查看頭文件可以看到其實這樣定義的:
#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
typedef long NSInteger;
typedef unsigned long NSUInteger;
#else
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif
這段定義是說如果程式是在64位系統下運行的,NSInteger
就代表long
,如果是32位的就代表int
。
也就是說,如果你不知道程式將要在什麼系統環境下運行時,最好使用NSInteger
,這樣可以保證數據很大時不出現問題。簡而言之,就是如果你並不考慮位數對程式的影響或者說你覺得並不能游刃有餘的操作int
和long
,那麼NSInteger
是一個很安全的選擇。
那麼是不是說有了NSInteger
就可以不用int
了呢?
當然不,以上的前提都是基於一個很大範圍數字變數所要考慮的。當你的變數值的範圍在一個你可控的範圍內,使用int
反而更合適,比如說,你要保存一張手機照片的尺寸,那麼幾千的值是絕對夠了的,於是用int
也不會產生任何問題,而用NSInteger
反而增加代碼閱讀難度。畢竟int
作為通用的基本類型很直觀,相反的是NSInteger
的代碼往其他地方移植也會對別人產生困擾(是不是想太多了: D),而且,從效率上來講,直接用int
的效率還是略微要高一些的。
什麼時候用NSInteger
其實在Apple的文檔或者示例代碼里,int
和NSInteger
都會存在,大多數出現NSInteger
是在函數的返回值上。因為函數的返回值是根據參數而不斷變化的,範圍是不可控的,所以就會使用NSInteger
作為返回值。
所以,簡單說來,凡是API用到了NSInteger
,那就別用int
了。一般情況代碼計數不會出現很大的值,畢竟32位的int
範圍可達到-2147483648~2147483647。
然後說開去,說什麼
與NSInteger
類似,Foundation
數據類型里也有類似於與float
對應的CGFloat
/* Definition of `CGFLOAT_TYPE', `CGFLOAT_IS_DOUBLE', `CGFLOAT_MIN', and
`CGFLOAT_MAX'. */
#if defined(__LP64__) && __LP64__
# define CGFLOAT_TYPE double
# define CGFLOAT_IS_DOUBLE 1
# define CGFLOAT_MIN DBL_MIN
# define CGFLOAT_MAX DBL_MAX
#else
# define CGFLOAT_TYPE float
# define CGFLOAT_IS_DOUBLE 0
# define CGFLOAT_MIN FLT_MIN
# define CGFLOAT_MAX FLT_MAX
#endif
/* Definition of the `CGFloat' type and `CGFLOAT_DEFINED'. */
typedef CGFLOAT_TYPE CGFloat;
#define CGFLOAT_DEFINED 1
看完定義就明白,CGFloat
也是對於不同位的系統的容錯。
最後至於NSString
和std::string
那區別就沒那麼簡單了。
對於常用的數據類型,就這些了。
對於這些數據類型的格式化,可以參考這部分文檔:formatSpecifiers
你覺得我這就說完了
起初遇到這個問題時,我就簡單的上網查了一下,感覺沒什麼區別。不過最近看博客,發現有個大神這樣講
應避免使用基本類型,建議使用 Foundation 數據類型
當時我就一驚,我的代碼用的都是int
,壓根就沒打算用NSInteger
,我突然覺得自己養成了一個很差的編碼習慣,而且我的代碼可能會對我以後求職有影響。
驚詐之餘我就上網找起資料,認真閱讀不同人的不同說法,然後得到一個我自己的結論:寫int
並無大礙,而且用基本數據類型並沒什麼明顯缺陷,畢竟我也是知道什麼時候用int
啊,long
啊,'float'啊這些的。虛驚一場。
但這事還是有教訓的,那就是瞭解一個新東西一定要多瞭解一些,像我當初就對這個問題不以為意,突然提起來了心就虛了。
另外有一個收穫就是多看別人寫的博客多關註一些細微的知識點總是能學到新東西的。像今天這個問題一樣,對我已經寫好的代碼影響雖然不大,但我再寫這塊代碼時的確是更安心了對吧。
reference
When to use NSInteger vs. int