2013-10-28 55 views
0
NSArray *arrClient = [[NSArray alloc] initWithObjects:@"record 1", @"record 2", nil]; 
NSArray *arrServer = [[NSArray alloc] initWithObjects:@"record 1", @"record 3", nil]; 

arrServer我想應用謂詞來僅篩選那些在arrClient中不存在的條目。例如在這種情況下,record 1存在於兩個數組中,並且應該被忽略,因此只有具有「記錄3」字符串的條目的數組纔會被返回。如何使用一個數組作爲另一個數組的謂詞?

這可能嗎?下面

UPDATE

的答案是偉大的。我相信我需要舉一個真實的例子來驗證我所做的事情是否有意義。 (我仍然給下面的壓縮版本)

現在clientItems將類型FTRecord(核心數據)的

@interface FTRecord : NSManagedObject 
... 
@property (nonatomic) NSTimeInterval recordDate; 

@end 

@implementation FTRecord 
... 
@dynamic recordDate; 

@end 

下面這個類是從一個REST服務解析JSON的支架。因此,我們前面提到的serverItems將是這種類型的。

@interface FTjsonRecord : NSObject <JSONSerializable> 
{ 

} 

@property (nonatomic) NSDate *recordDate; 

@implementation FTjsonRecord 

- (NSUInteger)hash 
{ 
    return [[self recordDate] hash]; 
} 

- (BOOL)isEqual:(id)object 
{ 
    if ([object isKindOfClass:[FTjsonRecord self]]) { 
     FTjsonRecord *other = object; 
     return [[self recordDate] isEqualToDate:[other recordDate]]; 
    } 
    else if ([object isKindOfClass:[FTRecord self]]) { 
     FTRecord *other = object; 
     return [[self recordDate] isEqualToDate:[NSDate dateWithTimeIntervalSinceReferenceDate:[other recordDate]]]; 
    } 
    else { 
     return NO; 
    } 
} 

與Wain的例子一起,這似乎工作正常。現在可行嗎? 請記住,serverItems只是臨時的,僅用於與服務器同步,並將被丟棄。 clientItems是一個仍然存在的地方。

更新2:

這一次,我想馬努的解決方案:

我建立了我的客戶DBStore,這是由謂詞調用此方法。 我不能使用containsObject的原因是因爲serverItems和clientItems中的類類型不是同一類型。

-(BOOL)recordExistsForDate:(NSDate *)date 
{ 
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"recordDate == %@", date]; 
    NSArray *arr = [allRecords filteredArrayUsingPredicate:predicate]; 
    if (arr && [arr count] > 0) { 
     return YES; 
    } else { 
     return NO; 
    } 
} 

NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(FTjsonRecord *evaluatedObject, NSDictionary *bindings) { 
       return ![store recordExistsForDate:[evaluatedObject recordDate]]; 
}]; 

NSSet *set = [[serverRecords items] filteredSetUsingPredicate:predicate]; 

我擔心這個解決方案雖然是從我clientItems(allRecords)讀取線性。我不確定它是如何有效地使用數組上的謂詞,想知道是否有更好的方法來實現這一點。

+0

你看着使用'NSSet'而不是謂詞? – Wain

+0

你能舉個例子嗎? – Houman

回答

0

依賴於您要使用的謂詞:

可以在陣列

或使用在使用本

[NSPredicate predicateWithFormat:<#(NSString *)#> argumentArray:<#(NSArray *)#>]; 

使用的參數數組,並建立一個使用對象的謂詞一個帶謂詞的塊

[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { 
    <#code#> 
}] 

並且在該塊中形成ob JECT與對象比較其陣列中

可能的檢查,你可以做的是:

return ![arrClient containsObject:evaluatedObject]; 

將排除包含在arrClient

containsObject對象:使用「isEqual:方法」來比較的對象

+0

馬努,如果你是如此善良的檢查問題中的更新2,我將不勝感激。請記住,這兩個數組不包含相同的類型。 (在更新1中更詳細地提到)因此,我不能使用你建議的'containsObject'。所以我想知道我採取的這種方法是否好。我只關心性能。謝謝 – Houman

+0

在更新1中,你已經覆蓋了hash和isEqual,所以即使對象是不同的類,你仍然可以使用containsObject(當然兩個類都必須覆蓋isEqual),或者你可以簡單地在塊中做同樣的檢查在做過的isEqual – Manu

1

您可以使用NSSet獲得其他集合的聯合,相交和差異(減號)。這更準確地匹配你想要做的事情。

NSMutableSet *serverItems = [[NSMutableSet alloc] init]; 
[arrServerItems addObjectsFromArray:arrServer]; 

NSSet *clientItems = [[NSSet alloc] init]; 
[clientItems addObjectsFromArray:arrClient]; 

[arrServerItems minus:clientItems]; 

雖然這不會刪除訂購信息。

謂詞可以使用:

NSPredicate *filterPredicate = [NSPredicate predicateWithFormat:@"NOT (SELF IN %@)", arrClient]; 
+0

謝謝,這看起來非常好。現在我的serverItems和clientItems碰巧有不同的類型。在這種情況下,我需要在serverItem類型上實現'isEqual'以使'minusSet'工作正確嗎? – Houman

+0

是的,但沒有。你真的應該在你的問題中給出一個真實的例子。如果你把東西放在集合中,你不想改變'isEqual'。您最好使用自定義比較方法,並根據@Manu答案使用'predicateWithBlock'。 – Wain

+0

Mhh有趣。我確實得到了它的工作。你提到,但我不應該這樣做。我現在用真實的例子更新了這個問題。請你看看它是否有意義,或者我太過分了? – Houman

相關問題