NSPredicate:无法解析字符串

时间:2015-02-02 03:11:28

标签: ios nspredicate

我根据事务类型执行谓词以获取特定日期范围内的所有事务。

这是谓词:

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) ]];

结果:

  

原因:&#39;无法解析格式字符串&#34;(日期&gt; = 2014-12-31   16:00:00 +0000和日期&lt; 2015-01-31 16:00:00 +0000)AND(type = 0)&#34;&#39;

2 个答案:

答案 0 :(得分: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];

答案 1 :(得分:3)

我建议你做的是(1)将最后一行分成更多的陈述,(2)删除整个stringWithFormat:的东西,因为predicateWithFormat: a格式化字符串,所以你只是混淆了额外的间接级别。这个测试编译并运行得很好:

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

这表明,如果您在简单的阶段进行简化并且可以理解和调试,那么您应该能够执行您尝试执行的操作。做我在这里做的事情 - 在一行中使用{{1>}形成只是谓词。一旦你有了编译的谓词,剩下的就很容易了。

顺便提一下,请注意我传递了一个对象(一个NSNumber),其中predicateWithFormat:是预期的。你不能在这里使用标量(比如普通的%@)。如果您想通过0,则需要0

最后一个建议:看起来你正试图形成一个复杂的谓词,其条款是有条件的,就像有时会添加额外的OR术语一样。这样做的方法是了解像NSCompoundPredicate这样的东西 - 这是它的用途。不要试图欺骗并用一根绳子完成所有操作。