Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Support ARC #1

Open
wants to merge 6 commits into from

5 participants

@mbaltaks

I have not done extensive testing, but this patch does seem to work under ARC in my current project, for what testing I've done.

@boredzo

This reverts Rachel's fix to the format string (which should be %lu, but %ld is closer than %d).

Owner

@rudyrichter: I've already applied that change in the upstream source. https://github.com/boredzo/iso-8601-date-formatter/blob/master/ISO8601DateFormatter.m#L750 @mbaltaks's version is behind on that (and I don't know how easy it would be to reintegrate them at this point).

@boredzo

It looks really weird to have code that releases the array (under MRC), then code that sends a message to it. Should be the other way, just for non-weirdness.

@boredzo

This reverts the other of Rachel's fixes.

@mbaltaks

My mistake, for some reason I didn't pick that up previously. I've sorted that out, and used the compiler recommendation for %u in the format string.

@boredzo
Owner

I added -fobjc-arc in the Makefile and got this:

make test                       %~/Projects/@reusable/iso-8601-date-formatter-mbaltaks(0)
/usr/bin/clang -std=c99 -fobjc-arc -g -Werror -Wmissing-field-initializers -Wreturn-type -Wmissing-braces -Wparentheses -Wswitch -Wunused-function -Wunused-label -Wunused-variable -Wunused-value -Wshadow -Wsign-compare -Wnewline-eof -Wshorten-64-to-32 -Wundeclared-selector -Wmissing-prototypes -Wformat -Wunknown-pragmas   -c -o testparser.o testparser.m
testparser.m:5:2: error: 'NSAutoreleasePool' is unavailable: not available in automatic
      reference counting mode
        NSAutoreleasePool *pool = [NSAutoreleasePool new];
        ^
/System/Library/Frameworks/Foundation.framework/Headers/NSAutoreleasePool.h:8:12: note: 
      declaration has been explicitly marked unavailable here
@interface NSAutoreleasePool : NSObject {
           ^
testparser.m:5:29: error: 'NSAutoreleasePool' is unavailable: not available in automatic
      reference counting mode
        NSAutoreleasePool *pool = [NSAutoreleasePool new];
                                   ^
/System/Library/Frameworks/Foundation.framework/Headers/NSAutoreleasePool.h:8:12: note: 
      declaration has been explicitly marked unavailable here
@interface NSAutoreleasePool : NSObject {
           ^
testparser.m:15:37: error: 'autorelease' is unavailable: not available in automatic
      reference counting mode
        ISO8601DateFormatter *formatter = [[[ISO8601DateFormatter alloc] init] ...
                                           ^
/System/Library/Frameworks/Foundation.framework/Headers/NSObject.h:37:1: note: 
      declaration has been explicitly marked unavailable here
- (id)autorelease NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
^
testparser.m:15:37: error: ARC forbids explicit message send of 'autorelease'
  ...*formatter = [[[ISO8601DateFormatter alloc] init] autorelease];
                   ^                                   ~~~~~~~~~~~
testparser.m:25:3: error: 'release' is unavailable: not available in automatic reference
      counting mode
        [pool release];
         ^
/System/Library/Frameworks/Foundation.framework/Headers/NSObject.h:36:1: note: 
      declaration has been explicitly marked unavailable here
- (oneway void)release NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
^
testparser.m:25:3: error: ARC forbids explicit message send of 'release'
        [pool release];
         ^    ~~~~~~~
6 errors generated.
make: *** [testparser.o] Error 1

Similar errors result in all of the other test-program files, which have not been ARCified or dual-moded. (Ideally, all of the files should be dual-mode, so that the parser and unparser can be regularly tested in either mode.)

@mbaltaks

Ok, I've not looked into running with and without ARC automatically, but if you manually add the compiler flag it all seems to look just as it does without the flag. The test output is quite verbose though, and there is no output from the time trial so I may be misunderstanding something there.

@blakewatters

Can we not just drop non-ARC support in the next version instead of doing this conditional compilation hackery?

@billinghamj

What's the state on this?

@boredzo
Owner

The state is:

  • This patch can't be automatically merged. Enough changes have happened and will happen that it'll probably be best/easiest to redo it. I'm just treating this as an issue ticket at this point.
  • There are still people using the ISO 8601 Date Formatter who support 32-bit OS X, and so cannot have ARC code in their projects—it must all use MRC. The biggest ones are Growl, who are maintaining 32-bit support in their framework, and Karelia. I intend to support this through at least the next release, and my current plan (subject to change) is to go ARC after then.
  • Also, ARC and other whole-project reworks are on hold until test coverage is at least a lot closer to 100%. There are still significant parts of the code that are not yet tested.

If anybody wants to help ARC happen in this project sooner, the best way is to contribute test cases. Coveralls will tell you what's currently not tested; here's the main source file as of the current latest build for anyone who's interested.

I should note that there are some test cases that have been removed because they fail, and some ported test-monster cases that fail. IIRC, I stubbed these out because they couldn't be fixed without the sort of major refactoring that I'm leaving until I have more test cases.

You're welcome to write test cases that fail. If they can't be fixed without major refactoring, I'll keep them on a separate branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
66 ARCMacros.h
@@ -0,0 +1,66 @@
+//
+// ARCMacros.h
+// InnerBand
+//
+// For an explanation of why these work, see:
+//
+// http://raptureinvenice.com/arc-support-without-branches/
+//
+// Created by John Blanco on 1/28/12.
+// Copyright (c) 2012 Rapture In Venice. All rights reserved.
+//
+// NOTE: __bridge_tranfer is not included here because releasing would be inconsistent.
+// Avoid it unless you're using ARC exclusively or managing it with __has_feature(objc_arc).
+//
+
+#if !defined(__clang__) || __clang_major__ < 3
+ #ifndef __bridge
+ #define __bridge
+ #endif
+
+ #ifndef __bridge_retain
+ #define __bridge_retain
+ #endif
+
+ #ifndef __bridge_retained
+ #define __bridge_retained
+ #endif
+
+ #ifndef __autoreleasing
+ #define __autoreleasing
+ #endif
+
+ #ifndef __strong
+ #define __strong
+ #endif
+
+ #ifndef __unsafe_unretained
+ #define __unsafe_unretained
+ #endif
+
+ #ifndef __weak
+ #define __weak
+ #endif
+#endif
+
+#if __has_feature(objc_arc)
+ #define SAFE_ARC_PROP_RETAIN strong
+ #define SAFE_ARC_RETAIN(x) (x)
+ #define SAFE_ARC_RELEASE(x)
+ #define SAFE_ARC_AUTORELEASE(x) (x)
+ #define SAFE_ARC_BLOCK_COPY(x) (x)
+ #define SAFE_ARC_BLOCK_RELEASE(x)
+ #define SAFE_ARC_SUPER_DEALLOC()
+ #define SAFE_ARC_AUTORELEASE_POOL_START() @autoreleasepool {
+ #define SAFE_ARC_AUTORELEASE_POOL_END() }
+#else
+ #define SAFE_ARC_PROP_RETAIN retain
+ #define SAFE_ARC_RETAIN(x) ([(x) retain])
+ #define SAFE_ARC_RELEASE(x) ([(x) release])
+ #define SAFE_ARC_AUTORELEASE(x) ([(x) autorelease])
+ #define SAFE_ARC_BLOCK_COPY(x) (Block_copy(x))
+ #define SAFE_ARC_BLOCK_RELEASE(x) (Block_release(x))
+ #define SAFE_ARC_SUPER_DEALLOC() ([super dealloc])
+ #define SAFE_ARC_AUTORELEASE_POOL_START() NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ #define SAFE_ARC_AUTORELEASE_POOL_END() [pool release];
+#endif
View
46 ISO8601DateFormatter.m
@@ -6,6 +6,7 @@
#import <Foundation/Foundation.h>
#import "ISO8601DateFormatter.h"
+#import "ARCMacros.h"
#ifndef DEFAULT_TIME_SEPARATOR
# define DEFAULT_TIME_SEPARATOR ':'
@@ -44,11 +45,14 @@ + (void) initialize {
+ (void) purgeGlobalCaches {
NSMutableDictionary *oldCache = timeZonesByOffset;
timeZonesByOffset = nil;
- [oldCache release];
+ #if __has_feature(objc_arc)
+ [oldCache removeAllObjects];
+ #endif
+ SAFE_ARC_RELEASE(oldCache);
}
- (NSCalendar *) makeCalendarWithDesiredConfiguration {
- NSCalendar *calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
+ NSCalendar *calendar = SAFE_ARC_AUTORELEASE([[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]);
calendar.firstWeekday = 2; //Monday
calendar.timeZone = [NSTimeZone defaultTimeZone];
return calendar;
@@ -56,8 +60,8 @@ - (NSCalendar *) makeCalendarWithDesiredConfiguration {
- (id) init {
if ((self = [super init])) {
- parsingCalendar = [[self makeCalendarWithDesiredConfiguration] retain];
- unparsingCalendar = [[self makeCalendarWithDesiredConfiguration] retain];
+ parsingCalendar = SAFE_ARC_RETAIN([self makeCalendarWithDesiredConfiguration]);
+ unparsingCalendar = SAFE_ARC_RETAIN([self makeCalendarWithDesiredConfiguration]);
format = ISO8601DateFormatCalendar;
timeSeparator = ISO8601DefaultTimeSeparatorCharacter;
@@ -67,21 +71,21 @@ - (id) init {
return self;
}
- (void) dealloc {
- [defaultTimeZone release];
+ SAFE_ARC_RELEASE(defaultTimeZone);
- [unparsingFormatter release];
- [lastUsedFormatString release];
- [parsingCalendar release];
- [unparsingCalendar release];
+ SAFE_ARC_RELEASE(unparsingFormatter);
+ SAFE_ARC_RELEASE(lastUsedFormatString);
+ SAFE_ARC_RELEASE(parsingCalendar);
+ SAFE_ARC_RELEASE(unparsingCalendar);
- [super dealloc];
+ SAFE_ARC_SUPER_DEALLOC();
}
@synthesize defaultTimeZone;
- (void) setDefaultTimeZone:(NSTimeZone *)tz {
if (defaultTimeZone != tz) {
- [defaultTimeZone release];
- defaultTimeZone = [tz retain];
+ SAFE_ARC_RELEASE(defaultTimeZone);
+ defaultTimeZone = SAFE_ARC_RETAIN(tz);
unparsingCalendar.timeZone = defaultTimeZone;
}
@@ -105,7 +109,7 @@ - (void) setDefaultTimeZone:(NSTimeZone *)tz {
*YYYY-MM-DD
*YYYY-MM
*YYYY
- *YY //century
+ *YY //century
* //Implied century: YY is 00-99
* YYMMDD
* YY-MM-DD
@@ -156,7 +160,7 @@ - (NSDateComponents *) dateComponentsFromString:(NSString *)string timeZone:(out
- (NSDateComponents *) dateComponentsFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone range:(out NSRange *)outRange {
NSDate *now = [NSDate date];
- NSDateComponents *components = [[[NSDateComponents alloc] init] autorelease];
+ NSDateComponents *components = SAFE_ARC_AUTORELEASE([[NSDateComponents alloc] init]);
NSDateComponents *nowComponents = [parsingCalendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:now];
NSUInteger
@@ -642,7 +646,7 @@ - (BOOL)getObjectValue:(id *)outValue forString:(NSString *)string errorDescript
- (NSString *) replaceColonsInString:(NSString *)timeFormat withTimeSeparator:(unichar)timeSep {
if (timeSep != ':') {
- NSMutableString *timeFormatMutable = [[timeFormat mutableCopy] autorelease];
+ NSMutableString *timeFormatMutable = SAFE_ARC_AUTORELEASE([timeFormat mutableCopy]);
[timeFormatMutable replaceOccurrencesOfString:@":"
withString:[NSString stringWithCharacters:&timeSep length:1U]
options:NSBackwardsSearch | NSLiteralSearch
@@ -667,7 +671,7 @@ - (NSString *) stringFromDate:(NSDate *)date timeZone:(NSTimeZone *)timeZone {
case ISO8601DateFormatOrdinal:
return [self stringFromDate:date formatString:ISO_ORDINAL_DATE_FORMAT timeZone:timeZone];
default:
- [NSException raise:NSInternalInconsistencyException format:@"self.format was %ld, not calendar (%d), week (%d), or ordinal (%d)", self.format, ISO8601DateFormatCalendar, ISO8601DateFormatWeek, ISO8601DateFormatOrdinal];
+ [NSException raise:NSInternalInconsistencyException format:@"self.format was %u, not calendar (%d), week (%d), or ordinal (%d)", self.format, ISO8601DateFormatCalendar, ISO8601DateFormatWeek, ISO8601DateFormatOrdinal];
return nil;
}
}
@@ -679,11 +683,11 @@ - (NSString *) stringFromDate:(NSDate *)date formatString:(NSString *)dateFormat
unparsingCalendar.timeZone = timeZone;
if (dateFormat != lastUsedFormatString) {
- [unparsingFormatter release];
+ SAFE_ARC_RELEASE(unparsingFormatter);
unparsingFormatter = nil;
- [lastUsedFormatString release];
- lastUsedFormatString = [dateFormat retain];
+ SAFE_ARC_RELEASE(lastUsedFormatString);
+ lastUsedFormatString = SAFE_ARC_RETAIN(dateFormat);
}
if (!unparsingFormatter) {
@@ -701,7 +705,7 @@ - (NSString *) stringFromDate:(NSDate *)date formatString:(NSString *)dateFormat
if (offset == 0)
str = [str stringByAppendingString:ISO_TIMEZONE_UTC_FORMAT];
else
- str = [str stringByAppendingFormat:ISO_TIMEZONE_OFFSET_FORMAT, (int)(offset / 60), (int)(offset % 60)];
+ str = [str stringByAppendingFormat:ISO_TIMEZONE_OFFSET_FORMAT, (int)offset / 60, (int)offset % 60];
}
//Undo the change we made earlier
@@ -783,7 +787,7 @@ - (NSString *) weekDateStringForDate:(NSDate *)date timeZone:(NSTimeZone *)timeZ
timeString = [formatter stringForObjectValue:date];
- [formatter release];
+ SAFE_ARC_RELEASE(formatter);
} else
timeString = @"";
View
19 Makefile
@@ -1,4 +1,8 @@
-CLANG=/Developer/usr/bin/clang
+ifeq ($(wildcard /Developer/usr/bin/clang),)
+ CLANG=/usr/bin/clang
+else
+ CLANG=/Developer/usr/bin/clang
+endif
CC=$(CLANG)
CFLAGS+=-std=c99 -g -Werror -Wmissing-field-initializers -Wreturn-type -Wmissing-braces -Wparentheses -Wswitch -Wunused-function -Wunused-label -Wunused-variable -Wunused-value -Wshadow -Wsign-compare -Wnewline-eof -Wshorten-64-to-32 -Wundeclared-selector -Wmissing-prototypes -Wformat -Wunknown-pragmas
LDFLAGS+=-framework Foundation
@@ -30,3 +34,16 @@ ISO8601DateFormatter-analysis.plist: ISO8601DateFormatter.m
$(CLANG) $^ --analyze -o /dev/null
timetrial: timetrial.o ISO8601DateFormatter.o
+
+clean:
+ rm *.o
+ rm *.out
+ rm testparser
+ rm testparser.sh
+ rm testunparsewithtime
+ rm timetrial
+ rm unparse-date
+ rm unparse-ordinaldate
+ rm unparse-weekdate
+
+alltests: test testunparsewithtime timetrial
View
7 testparser.m
@@ -1,8 +1,9 @@
#import <Foundation/Foundation.h>
#import "ISO8601DateFormatter.h"
+#import "ARCMacros.h"
int main(int argc, const char **argv) {
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
+ SAFE_ARC_AUTORELEASE_POOL_START()
BOOL parseStrictly = NO;
if((argc > 1) && (strcmp(argv[1], "--strict") == 0)) {
@@ -12,7 +13,7 @@ int main(int argc, const char **argv) {
[NSTimeZone setDefaultTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:+0]];
- ISO8601DateFormatter *formatter = [[[ISO8601DateFormatter alloc] init] autorelease];
+ ISO8601DateFormatter *formatter = SAFE_ARC_AUTORELEASE([[ISO8601DateFormatter alloc] init]);
formatter.parsesStrictly = parseStrictly;
while(--argc) {
@@ -22,6 +23,6 @@ int main(int argc, const char **argv) {
fputs([[NSString stringWithFormat:@"%@ %C %@\n", str, 0x2192, date] UTF8String], stdout);
}
- [pool release];
+ SAFE_ARC_AUTORELEASE_POOL_END()
return 0;
}
View
11 testunparsewithtime.m
@@ -1,11 +1,12 @@
#import <Foundation/Foundation.h>
#import "ISO8601DateFormatter.h"
+#import "ARCMacros.h"
static void testFormatStrings(int hour, int minute);
int main(void) {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- ISO8601DateFormatter *formatter = [[[ISO8601DateFormatter alloc] init] autorelease];
+ SAFE_ARC_AUTORELEASE_POOL_START()
+ ISO8601DateFormatter *formatter = SAFE_ARC_AUTORELEASE([[ISO8601DateFormatter alloc] init]);
formatter.includeTime = YES;
NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:336614400.0];
NSLog(@"2011-09-01 at 5 PM ET: %@", [formatter stringFromDate:date]);
@@ -14,7 +15,7 @@ int main(void) {
testFormatStrings(2, 6);
testFormatStrings(-2, 6);
- [pool drain];
+ SAFE_ARC_AUTORELEASE_POOL_END()
return EXIT_SUCCESS;
}
@@ -32,7 +33,7 @@ static void testFormatStrings(int hour, int minute) {
}
printf("Testing with printf:\n");
for (NSString *format in formatStrings) {
- format = [format stringByReplacingOccurrencesOfString:@"%@" withString:@"%s"];
- printf([[format stringByAppendingString:@"\n"] UTF8String], [format UTF8String], hour, minute);
+ NSString *cFormat = [format stringByReplacingOccurrencesOfString:@"%@" withString:@"%s"];
+ printf([[cFormat stringByAppendingString:@"\n"] UTF8String], [cFormat UTF8String], hour, minute);
}
}
View
31 timetrial.m
@@ -1,13 +1,13 @@
#import <Foundation/Foundation.h>
#import "ISO8601DateFormatter.h"
+#import "ARCMacros.h"
-int main(void) {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- sleep(1);
-
- ISO8601DateFormatter *formatter = [[[ISO8601DateFormatter alloc] init] autorelease];
+void test_part_one(void);
+void test_part_one(void)
+{
+ SAFE_ARC_AUTORELEASE_POOL_START()
+ ISO8601DateFormatter *formatter = SAFE_ARC_AUTORELEASE([[ISO8601DateFormatter alloc] init]);
NSString *inString = @"2011-04-12T13:15:17-0800";
NSUInteger numResults = 0;
NSDate *start, *end;
@@ -26,12 +26,23 @@ int main(void) {
NSLog(@"Number of dates and strings computed: %lu each", (unsigned long)numResults);
NSLog(@"Time taken per date: %f seconds", [end timeIntervalSinceDate:start] / numReps);
- [pool drain];
- pool = [[NSAutoreleasePool alloc] init];
+ SAFE_ARC_AUTORELEASE_POOL_END()
+}
+
+int main(void) {
sleep(1);
- numResults = 0;
+ test_part_one();
+
+ SAFE_ARC_AUTORELEASE_POOL_START()
+
+ sleep(1);
+
+ NSString *inString = @"2011-04-12T13:15:17-0800";
+ NSUInteger numResults = 0;
+ NSDate *start, *end;
+ enum { numReps = 10000 };
NSLog(@"Timing C standard library parsing and unparsing");
@@ -63,6 +74,6 @@ int main(void) {
sleep(1);
- [pool drain];
+ SAFE_ARC_AUTORELEASE_POOL_END()
return EXIT_SUCCESS;
}
View
8 unparse-date.m
@@ -1,9 +1,11 @@
#import "ISO8601DateFormatter.h"
+#import "ARCMacros.h"
+
int main(int argc, const char **argv) {
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
+ SAFE_ARC_AUTORELEASE_POOL_START()
- ISO8601DateFormatter *formatter = [[[ISO8601DateFormatter alloc] init] autorelease];
+ ISO8601DateFormatter *formatter = SAFE_ARC_AUTORELEASE([[ISO8601DateFormatter alloc] init]);
formatter.format = ISO8601DateFormatCalendar;
BOOL forceUTC = NO;
@@ -28,6 +30,6 @@ int main(int argc, const char **argv) {
printf("%s\n", [[NSString stringWithFormat:@"%@:\t%@", arg, [formatter stringFromDate:date timeZone:timeZone]] UTF8String]);
}
- [pool release];
+ SAFE_ARC_AUTORELEASE_POOL_END()
return 0;
}
View
7 unparse-ordinaldate.m
@@ -1,9 +1,10 @@
#import "ISO8601DateFormatter.h"
+#import "ARCMacros.h"
int main(int argc, const char **argv) {
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
+ SAFE_ARC_AUTORELEASE_POOL_START()
- ISO8601DateFormatter *formatter = [[[ISO8601DateFormatter alloc] init] autorelease];
+ ISO8601DateFormatter *formatter = SAFE_ARC_AUTORELEASE([[ISO8601DateFormatter alloc] init]);
formatter.format = ISO8601DateFormatOrdinal;
while(--argc) {
@@ -12,6 +13,6 @@ int main(int argc, const char **argv) {
printf("%s\n", [[NSString stringWithFormat:@"%@:\t%@", arg, [formatter stringFromDate:[formatter dateFromString:arg timeZone:&timeZone] timeZone:timeZone]] UTF8String]);
}
- [pool release];
+ SAFE_ARC_AUTORELEASE_POOL_END()
return 0;
}
View
7 unparse-weekdate.m
@@ -1,9 +1,10 @@
#import "ISO8601DateFormatter.h"
+#import "ARCMacros.h"
int main(int argc, const char **argv) {
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
+ SAFE_ARC_AUTORELEASE_POOL_START()
- ISO8601DateFormatter *formatter = [[[ISO8601DateFormatter alloc] init] autorelease];
+ ISO8601DateFormatter *formatter = SAFE_ARC_AUTORELEASE([[ISO8601DateFormatter alloc] init]);
formatter.format = ISO8601DateFormatWeek;
while(--argc) {
@@ -12,6 +13,6 @@ int main(int argc, const char **argv) {
printf("%s\n", [[NSString stringWithFormat:@"%@:\t%@", arg, [formatter stringFromDate:[formatter dateFromString:arg timeZone:&timeZone] timeZone:timeZone]] UTF8String]);
}
- [pool release];
+ SAFE_ARC_AUTORELEASE_POOL_END()
return 0;
}
Something went wrong with that request. Please try again.