问题
I'm using Stig Brautaset's JSON framework serialize some objects, including NSDates (which are not directly supported).
I decided to use NSDate's description as the JSONFragment representation of a date (I don't care about the minor loss of precision incurred in doing so).
To extend Stig Brautaset's JSON framework to include NSDates, I defined a category:
@interface NSDate (NSDate_JSON) <JSONInitializer>
-(NSString *) JSONFragment;
@end
To recreate an NSDate (and other classes) from JSON, I defined a protocol with the following initializer:
@protocol JSONInitializer <NSObject>
-(id) initWithJSONRepresentation: (NSString *) aJSONRepresentation;
@end
I'm having issues with this initializer. In NSDate's case, it just calls initWithString:, and that's were I get into trouble: it always returns nil. This is the implementation:
#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
I'm not sure what's going on. Besides, the compiler warns me that the initWithString: method in initWithJSONRepresentation: could not be found.
Anybody knows what might be going on?
The full source code for a test case is available here.
回答1:
Your test program is:
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];
Your -JSONFragment
category method is:
-(NSString *) JSONFragment{
NSString *strRepr = [self description];
return [strRepr JSONFragment];
}
What’s happening in this method is that you obtain a string representation of that date using -description
, and then a JSON representation of that string using -JSONFragment
.
In SBJSON, -JSONFragment
returns the representation of a given object as JSON data. The JSON specification requires that strings are quoted. In your program:
NSString *repr = [d1 JSONFragment];
repr
contains a string like @"\"2011-04-29 10:20:30 -0600\""
. Because of the quotes, that string is not a valid string to be used with -[NSDate initWithString:]
.
If you change:
NSString *repr = [d1 JSONFragment];
to:
NSString *repr = [[d1 JSONFragment] JSONFragmentValue];
so that SBJSON parses that fragment and returns a string without the quotes, it should work.
回答2:
You should always use an NSDateFormatter
when attempting to convert a string into a date or vice versa. -initWithString:
does exist on the Mac, but not on iOS. It requires the string to be in an extremely precise format. Using a date formatter is by far the superior solution.
And as a side note, your code would break if Apple ever decided to change the format of -[NSDate description]
.
回答3:
The reason initWithString:
can't be found is that unless you're importing Foundation and didn't show us here, your code can't see NSDate.h, so it doesn't know that initWithString:
exists.
Dave's quite right about relying on description
and using an NSDateFormatter
instead. It doesn't seem likely that description
will change, but there's no guarantee that it will continue to be valid input for initWithString:
which has a strict input requirement:
A string that specifies a date and time value in the international string representation format —
YYYY-MM-DD HH:MM:SS ±HHMM
, where±HHMM
is a time zone offset in hours and minutes from GMT (for example, “2001-03-24 10:45:32 +0600
”).You must specify all fields of the format string, including the time zone offset, which must have a plus or minus sign prefix.
If your string differs in any way (including, as has become apparent, having quotes in it), you'll get nil
.
来源:https://stackoverflow.com/questions/5837777/nsdates-initwithstring-is-returning-nil