2013-07-25 90 views
1

我有一個陣列,其中包含MyClass的各種實例,它具有四個屬性:int idint valueA,int valueBint valueC。有時,我需要修改一個特定實例的屬性(對於這個例子,假設它是id等於5的那個)。通過屬性查找數組中的特定實例

目前,我不喜歡這樣寫道:

MyClass *myClass = [[MyClass alloc] init]; 

for (int i = 0; i < [myMutableArray count]; i++) 
{ 
    myClass = [myMutableArray objectAtIndex:i]; 

    if(myClass.id == 5) 
    { 
     myClass.valueA = 100; 
     myClass.valueB = 200; 
     myClass.valueC = 300; 
     [myMutableArray replaceObjectAtIndex:i withObject: myClass]; 
    } 
} 

有沒有更好的(我很猶豫地說更有效)這樣的方式?

+1

不要命名變量ID - 這是一個保留關鍵字 – Mario

+0

好點。這個例子只是用它。懶得打出'身份證'。 – sangony

+0

有關該點的更多信息,請參閱[帶有「id」屬性的對象的NJSONSerialization](http://stackoverflow.com/q/17634584)。/cc @Mario –

回答

1

一個直接的,雖然羅嗦,方式,通過在所有的任何標準來獲取數組的特定成員是使用indexOfObjectPassingTest:objectAtIndex:

MyClass * theInstanceIWant; 
theInstanceIWant = [myArray objectAtIndex:[dates indexOfObjectPassingTest:^BOOL (id obj, NSUInteger idx, BOOL *stop) { 
                 return ([obj id] == 5); 
        }]; 

theInstanceIWant.valueA = 100; 
theInstanceIWant.valueB = 200; 
theInstanceIWant.valueC = 300; 

合併有沒有需要使用replaceObjectAtIndex:withObject: - 名稱theInstanceIWant引用數組中的實際對象,並且您仍然可以在陣列中更改其屬性。


(這是由一個類中的方法更愉快的NSArray。)

- (id)WSSObjectPassingTest:(BOOL (^)(id obj, NSInteger idx, BOOL *stop))test 
{ 
    NSUInteger testedIndex = [self indexOfObjectPassingTest:test]; 
    return [self objectAtIndex:testedIndex]; 
} 
+0

你的代碼有點不符合我的聯盟......根據Apple Docs。這個「返回數組中第一個通過給定塊測試的對象的索引」。我有點得到那部分,但我怎麼會替換/更新類實例,一旦屬性已被更改,在我的可變數組使用上述代碼? – sangony

+0

我已經更新了我的答案。 –

+0

也許我在這裏看不到明顯的。我理解使用你的代碼更新類屬性的部分。但是如何在事後更新我的數組中的類實例呢?在我的例子中,我使用[myMutableArray replaceObjectAtIndex:i withObject:myClass]命令。我如何使用你的代碼? – sangony

2

在開始過度優化之前,您確定這是性能瓶頸嗎?

一種替代方法是將實例保留在NSMutableDictionary中,其中密鑰是idNSNumber。然後,當您需要更新特定的實例時,您可以直接使用[myMutableDictionary objectForKey:@(someIntId)]來檢索實例。這會將你的O(n)循環變成一個O(1)哈希表查找[假設一個好的hash實現,或者在最壞的情況下它將是O(log n)]。

+0

我不認爲這將是一個瓶頸問題,因爲該陣列可能容納的對象不足200個。我正在努力學習這樣做的最佳/正確方法。 – sangony

3

如果您知道只有1個實例的id爲5,只需在完成更新後在if語句的末尾添加break;即可。這將終止循環迭代,可能是最有效的。

不應該過多關注運行時性能而不進行性能分析。

寫更少的代碼,你可以寫for爲:

for (MyClass *myClass in myMutableArray) { 

您可能需要使用一個數組爲您的存儲,如果你需要經常反正訪問個人物品的地方改變。

另外,不要做:

MyClass *myClass = [[MyClass alloc] init]; 

因爲你不必要創建你從來沒有使用實例,只是被扔掉。

+0

關於'break'聲明的很好的一點。我現在可以使用它,而無需改變現有的代碼。謝謝。 – sangony

2

我看到有兩種方法可以優化代碼。首先,你的新對象的原始賦值將替換數組中的myClass實例是不必要的 - 因爲它是一個指針,實際上是直接操作數組中的對象。其次,你是否保留了當前循環的增量,MyClass的原始分配是不必要的。你不需要對它做alloc和init,因爲你只需要一個指針。但是,您可以使用for for循環而不是遞增循環,並直接循環通過數組。

最終代碼:

for (MyClass *myClass in myMutableArray) 
{ 
    if(myClass.id == 5) 
    { 
     myClass.valueA = 100; 
     myClass.valueB = 200; 
     myClass.valueC = 300; 
    } 
} 
+0

感謝您的意見。 – sangony

0

第一件事,第一,你永遠不希望在目標命名varibale id - C. id指指向任何類型,它是一個保留關鍵字。

這樣做的更好/更有效的方法稱爲快速枚舉。快速枚舉是迭代列表/數組/集合中每個項目的特殊方式。代碼如下所示:

for (MyClass *iteratorObject in myMutableArray) { 
    if (iteratorObject.id == 5) { 
     //do what you want with that specific object 
     //insert your modified object back into mutable array 
    } 

儘管這將是最簡單的方法,但您打破了一條規則。在數組上執行快速枚舉時,您不應該編輯/添加/刪除對象。我的解決方案是簡單地調用[myMutableArray copy]返回一個immutableArray,然後遍歷它。

相關問題