1. 程式人生 > >NIL、NIL、NULL和NSNULL區別

NIL、NIL、NULL和NSNULL區別

前言

記得曾經有不少朋友問過筆者,在Objective-CnilNil以及NULL的區別。最重要的是,在面試中還有不少朋友常會被問到。記得當年剛找工作的時候,筆者就被面試官問到過,現在筆者在這裡統一詳細說明。

NULL

對於學習過C/C++語言的朋友,對NULL一定很熟悉吧?這就是在C/C++中的空指標。

C語言中,NULL是無型別的,只是一個巨集,它代表空。我們不研究C++中的NULL,因為在C++11以後又有了新的定義,我們不深究。

這就是C語言中所謂的NULLC++的定義比較複雜,這裡不說了):

#if defined(__need_NULL)
#undef NULL
#ifdef __cplusplus # if !defined(__MINGW32__) && !defined(_MSC_VER) # define NULL __null # else # define NULL 0 # endif #else # define NULL ((void*)0) #endif

這是在stddef.h標頭檔案中宣告的。這是使用了條件編譯的,__cplusplus這個巨集表示C++,對於我們Objective-C開發來說,NULL就表示((void*)0)

C語言中,我們定義了一個指標,當我們使用完以後,通常會設定指向NULL

。如果沒有設定,這個指標就成了所謂的野指標,然後其它地方不小心訪問了這個指標是很容易造成非法訪問的,常見的表現就是崩潰了。

既然Objective-C是基於C語言的面嚮物件語言,那麼也會使用到C語言型別的指標,比如使用const char *型別,判斷是否為空時,是使用p != NULL來判斷的。

nil

對於我們學習Objective-C的人來說,這個是非常熟悉的。如下為官方定義:

#ifndef nil
# if __has_feature(cxx_nullptr)
#   define nil nullptr
# else
#   define nil __DARWIN_NULL
# endif #endif

對於我們Objective-C開發來說,nil就是__DARWIN_NULL。看下官方定義:

#ifdef __cplusplus
#ifdef __GNUG__
#define __DARWIN_NULL __null
#else /* ! __GNUG__ */
#ifdef __LP64__
#define __DARWIN_NULL (0L)
#else /* !__LP64__ */
#define __DARWIN_NULL 0
#endif /* __LP64__ */
#endif /* __GNUG__ */
#else /* ! __cplusplus */
#define __DARWIN_NULL ((void *)0)
#endif /* __cplusplus */

這個也是條件編譯的,那麼對於我們Objective-C開發來說,nil就代表((void *)0)

我們使用nil表示Objective-C物件為空,如NSString *str = nil

Nil

先看看官方是如何宣告的:

#ifndef Nil
# if __has_feature(cxx_nullptr)
#   define Nil nullptr
# else
#   define Nil __DARWIN_NULL
# endif
#endif

根據條件,我們做Objective-C開發的,那麼Nil也就是代表__DARWIN_NULL,而對於__DARWIN_NULL的宣告如下:

#ifdef __cplusplus
#ifdef __GNUG__
#define __DARWIN_NULL __null
#else /* ! __GNUG__ */
#ifdef __LP64__
#define __DARWIN_NULL (0L)
#else /* !__LP64__ */
#define __DARWIN_NULL 0
#endif /* __LP64__ */
#endif /* __GNUG__ */
#else /* ! __cplusplus */
#define __DARWIN_NULL ((void *)0)
#endif /* __cplusplus */

這個也是條件編譯的,那麼對於我們Objective-C開發來說,Nil也就代表((void *)0)

但是它是用於代表空類的。比如:

Class myClass = Nil;

NSNull

先看看官方的宣告:

NS_ASSUME_NONNULL_BEGIN

@interface NSNull : NSObject <NSCopying, NSSecureCoding>

+ (NSNull *)null;

@end

NS_ASSUME_NONNULL_END

由此我們可知,NSNull是繼承於NSObject的型別。它是很特殊的類,它表示是空,什麼也不儲存,但是它卻是物件,只是一個佔位物件。

使用場景就不一樣了,比如說服務端介面中讓我們在值為空時,傳空。

NSDictionry *parameters = @{@"arg1" : @"value1",
                            @"arg2" : arg2.isEmpty ? [NSNull null] : arg2};

這只是隨手舉的例子,當然我們也可以不傳這人蔘數。如果我們要統一,比如通過runtime來動態將物件轉成我們的引數時,那麼可以統一將值為nil的都設定為[NSNull null]

區別

NULLnilNil這三者對於Objective-C中值是一樣的,都是(void *)0,那麼為什麼要區分呢?又與NSNull之間有什麼區別:

  • NULL是巨集,是對於C語言指標而使用的,表示空指標
  • nil是巨集,是對於Objective-C中的物件而使用的,表示物件為空
  • Nil是巨集,是對於Objective-C中的類而使用的,表示類指向空
  • NSNull是類型別,是用於表示空的佔位物件,與JS或者服務端的null類似的含意

寫在最後

以上只是筆者個人見解,不代表百分百正確,如果疑問之處,請在評論處留言,筆者會回覆!!!

以上只是筆者個人見解,不代表百分百正確,如果疑問之處,請在評論處留言,筆者會回覆!!!

以上只是筆者個人見解,不代表百分百正確,如果疑問之處,請在評論處留言,筆者會回覆!!!

閱讀原文

關注我