出于测试目的,您可以使用一种称为method swizzling 的技术。诀窍是用您自己的一种方法替换NSDate 的一种方法。
如果您将 +[NSDate date] 替换为您自己的实现,NSDataDetector 将在您指定的任何时间考虑“现在”。
在生产代码中混用系统类方法是有风险的。以下示例代码利用知道它私下使用NSDate 来忽略NSDataDetector 的Encapsulation。许多潜在的陷阱之一是,如果 iOS 的下一次更新更改了 NSDataDetector 的内部结构,您的生产应用程序可能会意外停止为最终用户正常工作。
像这样向NSDate 添加一个类别(顺便说一句:如果您正在构建库以在设备上运行,you may need to specify the -all_load linker flag 从库中加载类别):
#include <objc/runtime.h>
@implementation NSDate(freezeDate)
static NSDate *_freezeDate;
// Freeze NSDate to a point in time.
// PROBABLY NOT A GOOD IDEA FOR PRODUCTION CODE
+(void)freezeToDate:(NSDate*)date
{
if(_freezeDate != nil) [NSDate unfreeze];
_freezeDate = date;
Method _original_date_method = class_getClassMethod([NSDate class], @selector(date));
Method _fake_date_method = class_getClassMethod([self class], @selector(fakeDate));
method_exchangeImplementations(_original_date_method, _fake_date_method);
}
// Unfreeze NSDate so that now will really be now.
+ (void)unfreeze
{
if(_freezeDate == nil) return;
_freezeDate = nil;
Method _original_date_method = class_getClassMethod([NSDate class], @selector(date));
Method _fake_date_method = class_getClassMethod([self class], @selector(fakeDate));
method_exchangeImplementations(_original_date_method, _fake_date_method);
}
+ (NSDate *)fakeDate
{
return _freezeDate;
}
@end
这里正在使用它:
- (void)someTestingFunction:(NSNotification *)aNotification
{
// Set date to be frozen at a point one week ago from now.
[NSDate freezeToDate:[NSDate dateWithTimeIntervalSinceNow:(-3600*24*7)]];
NSString *userInput = @"tomorrow at 7pm";
NSError *error = nil;
NSRange range = NSMakeRange(0, userInput.length);
NSDataDetector *dd = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeDate error:&error];
[dd enumerateMatchesInString:userInput
options:0
range:range
usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop) {
NSLog(@"From one week ago: %@", match);
}];
// Return date to normal
[NSDate unfreeze];
[dd enumerateMatchesInString:userInput
options:0
range:range
usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop) {
NSLog(@"From now: %@", match);
}];
}
哪些输出:
2014-01-20 19:35:57.525 TestObjectiveC2[6167:303] 从一周前开始:{0, 15}{2014-01-15 03:00:00 +0000}
2014-01-20 19:35:57.526 TestObjectiveC2[6167:303] 从现在开始:{0, 15}{2014-01-22 03:00:00 +0000}