【问题标题】:NSDate's initWithString: is returning nilNSDate 的 initWithString: 返回 nil
【发布时间】:2011-04-29 21:52:39
【问题描述】:

我正在使用Stig Brautaset 的 JSON 框架序列化一些对象,包括 NSDates(不直接支持)。

我决定使用 NSDate 的描述作为日期的 JSONFragment 表示(我不关心这样做会导致精度的轻微损失)。

为了扩展 Stig Brautaset 的 JSON 框架以包含 NSDates,我定义了一个类别:

@interface NSDate  (NSDate_JSON) <JSONInitializer>

-(NSString *) JSONFragment;

@end

为了从 JSON 重新创建 NSDate(和其他类),我使用以下初始化程序定义了一个协议:

@protocol JSONInitializer <NSObject>

-(id) initWithJSONRepresentation: (NSString *) aJSONRepresentation;

@end

我遇到了这个初始化程序的问题。在 NSDate 的情况下,它只是调用 initWithString:,这就是我遇到的麻烦:它总是返回 nil。这是实现:

#import "NSDate+JSON.h"


@implementation NSDate (NSDate_JSON)

-(NSString *) JSONFragment{
    NSString *strRepr = [self description];
    return [strRepr JSONFragment];
}

-(id) initWithJSONRepresentation:(NSString *)aJSONRepresentation{


    return [self initWithString: aJSONRepresentation]; //returns nil!
}
@end

我不确定发生了什么。此外,编译器警告我 initWithJSONRepresentation: 中的 initWithString: 方法找不到。

有人知道会发生什么吗?

测试用例的完整源代码可在here 获得。

【问题讨论】:

  • aJSONRepresentation 长什么样子?
  • 和NSDate的描述一模一样
  • @Bavarious 好的,你是对的,AJSONRepresentation 是双引号内的描述。

标签: objective-c cocoa protocols nsdate categories


【解决方案1】:

您应该始终在尝试将字符串转换为日期时使用NSDateFormatter,反之亦然。 -initWithString: 确实存在于 Mac 上,但不存在于 iOS 上。它要求字符串的格式非常精确。到目前为止,使用日期格式化程序是最好的解决方案。

附带说明一下,如果 Apple 决定更改 -[NSDate description] 的格式,您的代码将会中断。

【讨论】:

  • 如果iOS上不存在该方法,而我使用的是iOS,应用程序不应该崩溃吗?
  • 它可能就在那里,只是不是作为 API,你不应该依赖未记录的方法。 NSDateFormatter 仍然是正确答案。
【解决方案2】:

你的测试程序是:

NSDate *d1 = [[[NSDate alloc] init] autorelease];
NSString *repr = [d1 JSONFragment];

NSDate *dd = [[[NSDate alloc] initWithString:[d1 description]] autorelease ];
NSDate *d2 = [[[NSDate alloc] initWithJSONRepresentation:repr] autorelease];

您的-JSONFragment 类别方法是:

-(NSString *) JSONFragment{
    NSString *strRepr = [self description];
    return [strRepr JSONFragment];
}

在这个方法中发生的事情是,您使用 -description 获得该日期的字符串表示,然后使用 -JSONFragment 获得该字符串的 JSON 表示。

在 SBJSON 中,-JSONFragment 将给定对象的表示形式返回为 JSON 数据。 JSON 规范要求引用字符串。在你的程序中:

NSString *repr = [d1 JSONFragment];

repr 包含类似@"\"2011-04-29 10:20:30 -0600\"" 的字符串。由于引号,该字符串不是与-[NSDate initWithString:] 一起使用的有效字符串。

如果你改变:

NSString *repr = [d1 JSONFragment];

到:

NSString *repr = [[d1 JSONFragment] JSONFragmentValue];

以便 SBJSON 解析该片段并返回不带引号的字符串,它应该可以工作。

【讨论】:

  • +1:不过,Dave 依赖description 的输出可能仍然是正确的。
  • @Josh 我不确定。 -[NSDate description]-[NSDate initWithString:] 的文档对字符串表示非常具体。
  • 是的,我会向您在这方面的卓越经验低头,但如果我不得不猜测,鉴于没有文档说“descriptioninitWithString 的有效输入”,我会说苹果更愿意改变记录方法的行为而不是创建对象的方法。或者,我不知道,description 应该用于其他用途吗?
  • @Josh Ha,我对你所说的这种卓越体验一无所知——这不是真的。 :-P 引起我注意的是,正如您所说,-description 通常用于日志记录。但是,他们已经记录了返回值的非常具体的格式。他们当然知道更改该方法以返回不同的格式可能会破坏应用程序,所以我猜他们不会这样做。相反,他们会提供另一种方法。
  • 我将更改我的代码以使用 timeIntervalSinceReferenceDate,希望它应该更可靠并且在 OSX 和 iOS 中都可以工作。
【解决方案3】:

找不到initWithString:的原因是,除非你导入Foundation并且没有在这里显示,否则你的代码看不到NSDate.h,所以它不知道initWithString:存在.

Dave 完全正确地依赖 description 并改用 NSDateFormatterdescription 似乎不太可能发生变化,但不能保证它将继续是initWithString: 的有效输入,其中has a strict input requirement

以国际字符串表示格式指定日期和时间值的字符串 — YYYY-MM-DD HH:MM:SS ±HHMM,其中 ±HHMM 是与 GMT 的时区偏移(以小时和分钟为单位)(例如,“2001-03-24 10:45:32 +0600”)。

必须指定格式字符串的所有字段,包括时区偏移量,必须有加号或减号前缀。

如果您的字符串有任何不同(包括,很明显,其中包含引号),您将得到nil

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-07
    • 2023-03-14
    • 1970-01-01
    • 2015-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多