假设今天是2014年1月20日.如果我使用NSDataDetector从“明天下午4点”字符串中提取日期,我将得到2014-01-21T16:00.大.
但是,假设我希望NSDataDetector假装当前日期是2014年1月14日.这样,当我解析“明天下午4点”时,我将得到2014-01-15T16:00.如果我在设备上更改系统时间,我会得到我想要的.但是,有没有办法以编程方式指定它?
谢谢.
解决方法
出于测试目的,您可以使用名为
method swizzling的技术.诀窍是用您自己的方法替换NSDate的方法之一.
如果用您自己的实现替换[NSDate date],NSDataDetector将在您指定的任何时候考虑“Now”.
生产代码中的混合系统类方法存在风险.以下示例代码通过利用知道它私有地使用NSDate来忽略NSDataDetector的Encapsulation.许多潜在的缺陷之一是,如果iOS的下一次更新改变了NSDataDetector的内部结构,您的生产应用程序可能会意外停止为您的最终用户正常工作.
像这样在NSDate中添加一个类别(另外:如果要构建要在设备上运行的库,则在you may need to specify the -all_load linker flag中从libs加载类别):
#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],_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,BOOL *stop) { NSLog(@"From Now: %@",match); }]; }
哪个输出:
2014-01-20 19:35:57.525 TestObjectiveC2[6167:303] From one week ago: {0,15}{2014-01-15 03:00:00 +0000} 2014-01-20 19:35:57.526 TestObjectiveC2[6167:303] From Now: {0,15}{2014-01-22 03:00:00 +0000}