2015-07-10 56 views
1

這裏是我的代碼:我應該比較NSNotFound NSInteger或NSUInteger?

NSArray *allIds = [self.purchasableObjects valueForKey:@"productIdentifier"]; 
NSInteger index = [allIds indexOfObject:productId]; 

if (index == NSNotFound) 
    return; 

哪一個比較NSNotFound ... NSIntegerNSUInteger爲什麼?

+1

看看'NSArray indexOfObject:'的文檔。它的返回類型是什麼? – rmaddy

+1

這兩個工作。看到http://stackoverflow.com/questions/9338295/why-nsnotfound-isnt-1-but-nsintegermax –

回答

1

您應該使用NSUInteger

這背後的原因是「的數組索引是不會負(即對象在指數-5)」

typedef int NSInteger; 
typedef unsigned int NSUInteger; 

NSInteger的,必須使用時,有是正值或負值的概率。

希望它有幫助。 感謝

+0

當我試圖堅持這個無符號數組索引的概念,但我不能寫'for(NSUInteger索引我= [allIds count] - 1; i> = 0; i - )' – tia

+0

@tia 您不能在遞減運算符中使用NSUInteger。 因爲當你到達索引0,並且i--會嘗試使它-1(但它是NSUInteger,它是無符號的,所以它將失敗該操作,並且此迭代將無限。這就是不在循環中使用NSUInteger的原因) – NSSwift

+0

實際上,使用'NSUInteger'的原因是因爲它是'NSArray indexOfObject:'的返回類型。 – rmaddy

2

的原因就是他爲什麼問這個問題是因爲AppKit的是基金指數不一致,特別是對NSMenuNSTableView

id obj = ...; 
NSMenu * menu = ...; 

/* This returns an NSInteger, returning -1 (which when casted, is NSNotFound) */ 
NSInteger index = [ menu indexOfItemWithRepresentedObject:obj ]; 

/* This returns an NSUInteger, since arrays cannot have negative indices. */ 
NSUInteger idx = [ [ menu itemArray ] indexOfObjectIdenticalTo:obj ]; 

正因爲如此,我們必須投來回,但是這創造新問題:

因爲索引不能是負數,所以行數(或子菜單, 等)低於正常數組的一半。

如果您嘗試在UI元素中讀取或插入對象到否定索引(-2),則不會收到範圍異常。如果您轉換爲無符號,則索引未定義。所以這個代碼,這是錯誤的,編譯沒有錯誤:

id obj = ...; 
NSMenu * menu = ...; 
/* Or the result of some integer arithmetic. */ 
NSInteger idx = -2; 

/* Compiles, doesn't throw exception. Index COULD be NSIntegerMax - 1, but the ending index is undefined. */ 
[ menu insertItem:obj atIndex:idx ]; 

/* Compiles, but throws NSRangeException. */ 
[ [ menu mutableArrayValueForKey:@"items" ] insertObject:obj atIndex:(NSUInteger)idx ]; 

在第一種情況下,插入時的項目超出menu.numberOfItems(這是一個NSInteger),一般(但不能保證),該方法是相當於[ menu addItem ]。所以,指數因而轉化:

[ menu insertItem:obj atIndex:MIN(idx, menu.numberOfItems) ]; 

但在老版本了AppKit中,指數向上取整!:

[ menu insertItem:obj atIndex:MAX(MIN(idx, menu.numberOfItems), 0) ]; 

所以程序員必須在插入時和/或檢索從UI指標採取非常謹慎元素,或使用NSArrayController代替。

對於所有的情況,雖然它安全檢查都[ menu indexOfItem:obj ][ array indexOfObjectIdenticalTo:obj ]等於NSNotFound,只要您使用顯式類型轉換。雖然NSNotFound具有NSUInteger的聲明類型,但是定義爲NSUIntegerMax,當投射等於-1時。 從不檢查一個值是否小於NSNotFound,因爲您將創建另一個無限循環。但是自由感覺:

NSInteger index = [ menu indexOfItem:nonexistantObject ]; 
if((NSUInteger)index == NSNotFound) { 
...blah... 
} 

NSUInteger index = [ array indexOfItem:nonexistantObject ]; 
if(index == NSNotFound) { 
...blah... 
} 

但是,如果返回類型爲NSInteger,你應該假設,如果返回的索引是不是NSNotFound,它是有效的索引(特別是如果您使用第三方框架或庫)。相反,你應該檢查,看看如果返回的指數處於有效範圍:

NSInteger index = [ menu indexOfItem:nonexistantObject ]; 
if((NSUInteger)index == NSNotFound) { 
/* Can't find it, so insert or do something else. */ 
} else if(!(index >= 0 && index <= menu.numberOfItems)) { 
/* Throw an invalid range exception. There's a major bug! */ 
} else { 
/* woo hoo! we found it! */ 
} 

當然,入住的計算成本高昂,所以應該只在運行很少的代碼中使用,是在循環或調試代碼。如果你想確保您始終獲得一個有效的指標儘可能快地,你應該使用塊枚舉,這是比任何其他方法更快:

id obj = ..; 
/* Get an array from the UI, or just use a normal array. */ 
NSArray * array = [ menu itemArray ]; 

/* Find an index quickly */ 
NSUInteger index = [ array indexOfObjectWithOptions:NSEnumerationConcurrent passingTest:^BOOL(NSUInteger idx, id testObj, BOOL * stop) { 
if(obj == testObj) { 
*stop = TRUE; 
return TRUE; 
} 
} ]; 

返回指數保證是有效的,或者NSNotFound或者NSMakeRange(0, array.count - 1)。注意我沒有使用-isEqual:,因爲我正在檢查特定的實例不是可以解釋爲相同另一個的對象。

如果你需要做的與環中的索引的東西,你可以使用同樣的技術(注意指數被傳遞到塊,並總是有效):

[ array enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(NSUInteger idx, id obj, BOOL * stop) { 
/* do something to this object, like adding it to another array, etc */ 
} ]; 

使用塊上的方法總是得到你有效的索引,可以將其轉換爲NSIntegers以用於UI元素。還有範圍特定的塊方法可以進一步限制值。我建議通過NSArrayNSMutableArray文檔獲取指針。它也很容易誤塊,通過將代碼添加到[enumerate...withBlock:][3]方法,特別是如果你正在添加的對象複製到另一個集合類:

NSArray * source = ...; 
NSMutableArray * dest = ...; 

[ source enumerateObjectsUsingBlock:^(NSUInteger idx, id obj, BOOL * stop) { 
if(/* some test */) { 
/* This is wasteful, and possibly incorrect if you're using NSEnumerationConcurrent */ 
[ dest addObject:obj ]; 
} 
} ]; 

這是更好地做到這一點,而不是:

/* block removed for clarity */ 
NSArray * source = ...; 
NSMutableArray * dest = ...; 
NSIndexSet * indices = [ source indexesOfObjectsPassingTest:testBlock ]; 

[ dest addObjects:[ source objectsAtIndexes:indices ] ]; 

對不起對於囉嗦的迴應,但這是Cocoa索引(特別是NSNotFound)的一個問題,我的開發人員必須解決並重新解決這個問題,所以我認爲這將有助於分享。