NSPredicate:无法解析字符串
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是自动生成的。
调用示例如下:
// 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) ]];
结果:
reason: 'Unable to parse the format string "(date >= 2014-12-31
16:00:00 +0000 AND date < 2015-01-31 16:00:00 +0000) AND (type = 0)"'
我建议你做的是 (1) 将最后一行分成更多的语句,并且 (2) 删除整个 stringWithFormat:
东西,因为 predicateWithFormat:
是 格式字符串,因此您只是将自己与额外的间接级别混淆了。这个测试编译并运行得很好:
NSPredicate *predicate =
[NSPredicate predicateWithFormat:
@"(date >= %@ AND date < %@) AND (type = %@)",
[NSDate new], [NSDate new], @0];
这表明,如果您在可以理解和调试的简单阶段进行简化和完成,您应该能够完成您想要做的事情。做我在这里做的事情——在一行中形成 谓词 ,按预期使用 predicateWithFormat:
。一旦你有了要编译的谓词,剩下的就很简单了。
请注意,顺便说一句,我正在传递一个 object(一个 NSNumber),其中 %@
是预期的。你不能在这里使用标量(比如普通的 0
)。如果你想通过 0
你需要像 %d
.
这样的东西
最后一个建议:看起来您正在尝试形成一个复杂的谓词,其条件是有条件的,例如有时添加额外的 OR 条件。这样做的方法是学习 NSCompoundPredicate 之类的东西——这就是它的用途。不要试图欺骗并用一个字符串完成所有操作。
您的问题是 stringWithFormat:
和 predicateWithFormat:
的功能不同。具体来说,predicateWithFormat:
将根据需要转义 and/or 引号字符串,而 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];
我正在做谓词以根据交易类型获取特定日期范围内的所有交易。
这是谓词:
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是自动生成的。
调用示例如下:
// 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) ]];
结果:
reason: 'Unable to parse the format string "(date >= 2014-12-31 16:00:00 +0000 AND date < 2015-01-31 16:00:00 +0000) AND (type = 0)"'
我建议你做的是 (1) 将最后一行分成更多的语句,并且 (2) 删除整个 stringWithFormat:
东西,因为 predicateWithFormat:
是 格式字符串,因此您只是将自己与额外的间接级别混淆了。这个测试编译并运行得很好:
NSPredicate *predicate =
[NSPredicate predicateWithFormat:
@"(date >= %@ AND date < %@) AND (type = %@)",
[NSDate new], [NSDate new], @0];
这表明,如果您在可以理解和调试的简单阶段进行简化和完成,您应该能够完成您想要做的事情。做我在这里做的事情——在一行中形成 谓词 ,按预期使用 predicateWithFormat:
。一旦你有了要编译的谓词,剩下的就很简单了。
请注意,顺便说一句,我正在传递一个 object(一个 NSNumber),其中 %@
是预期的。你不能在这里使用标量(比如普通的 0
)。如果你想通过 0
你需要像 %d
.
最后一个建议:看起来您正在尝试形成一个复杂的谓词,其条件是有条件的,例如有时添加额外的 OR 条件。这样做的方法是学习 NSCompoundPredicate 之类的东西——这就是它的用途。不要试图欺骗并用一个字符串完成所有操作。
您的问题是 stringWithFormat:
和 predicateWithFormat:
的功能不同。具体来说,predicateWithFormat:
将根据需要转义 and/or 引号字符串,而 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];