2015-02-02 4 views
-1

Im делает предикат для извлечения всей транзакции в определенном диапазоне дат в зависимости от типа транзакции.NSPredicate: Unable To Parse String

Вот предикат:

NSString *predicate = [NSString stringWithFormat:@"(date >= %@ AND date < %@) AND (%@)", from, to, defaultType]; 

Вот полный код:

- (NSArray *)transactionFromMonth:(NSInteger)fromMonth toMonth:(NSInteger)toMonth ofTypes:(NSArray *)transactionTypes 
{ 
    // get the current calendar of the device 
    NSCalendar *calendar = [NSCalendar currentCalendar]; 

    // create date components using current calendar 
    NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitDay 
           | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:[NSDate date]]; 

    // get year 
    NSInteger currentYear = [components year]; 

    // create fromDate (The first day of the month) using the current year, passing month, and 1 as the day 
    // to form the starting day of the month 
    // e.g when toMonth has a value of 1, then the resulting 
    // date will be January 1, (current year of the device's calendar) 
    NSDateComponents *comps = [[NSDateComponents alloc] init]; 
    [comps setDay:1]; 
    [comps setMonth:fromMonth]; 
    [comps setYear:currentYear]; 
    NSDate *from = [[NSCalendar currentCalendar] dateFromComponents:comps]; 


    // create toDate 
    // 
    // Set your month here 
    [comps setMonth:toMonth]; 

    // get the number of days of "to" month 
    NSRange range = [calendar rangeOfUnit:NSDayCalendarUnit 
           inUnit:NSMonthCalendarUnit 
           forDate:[calendar dateFromComponents:comps]]; 

    [comps setDay:range.length+1]; 

    NSDate *to = [[NSCalendar currentCalendar] dateFromComponents:comps]; 

    NSLog(@"to Months %@", to); 
    NSString *defaultType = [NSString stringWithFormat:@"type = %d", [[transactionTypes objectAtIndex:0] integerValue]]; 

    NSMutableString *types = [[NSMutableString alloc] initWithString: defaultType ]; 
    for (int i = 1; i < transactionTypes.count; i++) 
    { 
     [defaultType stringByAppendingFormat:@" OR type = %d", [[transactionTypes objectAtIndex:i] integerValue] ]; 
    } 

    // here is the predicate causing the error 
    // 
    // 
    NSString *predicate = [NSString stringWithFormat:@"(date >= %@ AND date < %@) AND (%@)", from, to, defaultType]; 
    return [self.transaction filteredSetUsingPredicate: [NSPredicate predicateWithFormat:predicate]].allObjects; 
} 

Вот декларация транзакционной модели: Примечание: .h и .m из приведенных ниже моделей автогенерируемая.

enter image description here

Вот пример вызова:

// I want to retrieve all transaction from January 1 to January 31 in device's current calendar year of type kTransactionTypeAddFund (which has the value of 0) 
[self transactionFromMonth:1 toMonth:1 ofTypes:@[ @(kTransactionTypeAddFund) ]]; 

Результат:

причина: «Невозможно разобрать строку формата«(дата> = 2014-12-31 16:00:00 +0000 AND date < 2015-01-31 16:00:00 +0000) AND (type = 0) "'

+0

На первый взгляд (я не испытывая это, и я не использую NSPredicate в довольно долгое время), я бы сказал, что вы либо выход эти даты как целые числа или вам нужно цитировать их, но я m not sure –

+0

Добавление котировок на сегодняшний день будет относиться к ним как к NSString. Поэтому сравнение даты было бы невозможно. – Hokage

+1

Какой _is_ ваш предикат? Вы указали сообщение об ошибке, но не код. Покажите, что вы делаете, пожалуйста. – matt

ответ

4

Ваша проблема в том, что stringWithFormat: и predicateWithFormat: функция по-разному. В частности, predicateWithFormat: будет избегать и/или приводить строки, если необходимо, где stringWithFormat не будет. Вам нужно создать отдельные предикаты с predicateWithFormat:, а затем создать союз с помощью конъюнкции предикат:

NSMutableArray* types = [NSMutableArray new]; 

for (int i = 0; i < transactionTypes.count; i++) 
{ 
    [types addObject:[NSPredicate predicateWithFormat:@"type = %@", [transactionTypes objectAtIndex:i]]]; 
} 

// Make a compound predicate with "or" for all the types 
NSPredicate* typePredicate = [NSCompoundPredicate orPredicateWithSubpredicates:types]; 

// Create the date part of the predicate 
NSPredicate* datePredicate = [NSPredicate predicateWithFormat:@"(date >= %@ AND date < %@)", from, to]; 

// merge the type and date parts of the predicate into a single 
// and predicate 
NSPredicate* predicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[ typePredicate, datePredicate]]; 

В качестве альтернативы, и проще, просто воспользоваться предикатами IN оператора ...

NSPredicate* predicate = [NSPredicate predicateWithFormat:@"date >= %@ AND date < %@ AND type IN %@", from, to, transactionTypes]; 
+0

Спасибо. Альтернативный ответ проще. – Hokage

2

Что я предлагаю вам сделать: (1) вытащить эту последнюю строку на большее количество утверждений и (2) отбросить всю вещь stringWithFormat:, потому что predicateWithFormat:- строка формата, поэтому вы просто путаете себя с дополнительным уровнем косвенности. Этот тест компилирует и работает просто отлично:

NSPredicate *predicate = 
    [NSPredicate predicateWithFormat: 
     @"(date >= %@ AND date < %@) AND (type = %@)", 
     [NSDate new], [NSDate new], @0]; 

Это говорит о том, что вы должны быть в состоянии делать то, что вы пытаетесь сделать, если вы упростить и сделать это в легкой стадии, что вы можете понять и отладки. Делайте то, что я здесь делаю - форма просто предикат на одной строке, используя predicateWithFormat:, как и предполагалось. Как только у вас будет предикат для компиляции, все остальное легко.

Обратите внимание, что я проезжаю объект (NSNumber), где ожидается %@. Вы не можете использовать скаляры здесь (например, обычный старый 0). Если вы хотите пройти 0, вам нужно что-то вроде %d.

Окончательное предложение: похоже, вы пытаетесь сформировать сложный предикат, условия которого условны, например, иногда добавляют дополнительные OR-термины. Способ сделать это - узнать о таких вещах, как NSCompoundPredicate, - вот для чего это. Не пытайтесь обманывать и делать все с помощью одной строки.

+0

Спасибо за ваш ответ. Это приводит меня к правильному решению. – Hokage