diff --git a/Classes/ASIAuthenticationDialog.m b/Classes/ASIAuthenticationDialog.m index 64c220e9..88e0e4cf 100644 --- a/Classes/ASIAuthenticationDialog.m +++ b/Classes/ASIAuthenticationDialog.m @@ -239,6 +239,7 @@ - (void)viewDidDisappear:(BOOL)animated sharedDialog = nil; [self performSelector:@selector(presentNextDialog) withObject:nil afterDelay:0]; [self release]; + [super viewDidDisappear:animated]; } - (void)dismiss diff --git a/Classes/ASIHTTPRequest.m b/Classes/ASIHTTPRequest.m index cb6bbeea..cc2b347d 100644 --- a/Classes/ASIHTTPRequest.m +++ b/Classes/ASIHTTPRequest.m @@ -24,7 +24,7 @@ #import "ASIDataCompressor.h" // Automatically set on build -NSString *ASIHTTPRequestVersion = @"v1.8.1-61 2011-09-19"; +NSString *ASIHTTPRequestVersion = @"v1.8.2-14 2014-09-19"; static NSString *defaultUserAgent = nil; @@ -4434,7 +4434,7 @@ + (NSString *)defaultUserAgentString if (err != noErr) return nil; err = Gestalt(gestaltSystemVersionBugFix, &versionBugFix); if (err != noErr) return nil; - OSVersion = [NSString stringWithFormat:@"%u.%u.%u", versionMajor, versionMinor, versionBugFix]; + OSVersion = [NSString stringWithFormat:@"%u.%u.%u", (int)versionMajor, (int)versionMinor, (int)versionBugFix]; #endif // Takes the form "My Application 1.0 (Macintosh; Mac OS X 10.5.7; en_GB)" @@ -4622,7 +4622,7 @@ + (unsigned long)maxUploadReadLength // We'll split our bandwidth allowance into 4 (which is the default for an ASINetworkQueue's max concurrent operations count) to give all running requests a fighting chance of reading data this cycle long long toRead = maxBandwidthPerSecond/4; - if (maxBandwidthPerSecond > 0 && (bandwidthUsedInLastSecond + toRead > maxBandwidthPerSecond)) { + if (maxBandwidthPerSecond > 0 && (((long long)bandwidthUsedInLastSecond + toRead) > (long long)maxBandwidthPerSecond)) { toRead = (long long)maxBandwidthPerSecond-(long long)bandwidthUsedInLastSecond; if (toRead < 0) { toRead = 0; diff --git a/Classes/ASIInputStream.h b/Classes/ASIInputStream.h index 7b9f93ed..275ce127 100644 --- a/Classes/ASIInputStream.h +++ b/Classes/ASIInputStream.h @@ -14,13 +14,19 @@ // Subclassing NSInputStream seems to be tricky, and may involve overriding undocumented methods, so we'll cheat instead. // It is used by ASIHTTPRequest whenever we have a request body, and handles measuring and throttling the bandwidth used for uploading -@interface ASIInputStream : NSObject { - NSInputStream *stream; - ASIHTTPRequest *request; +@interface ASIInputStream : NSObject{ + NSInputStream *stream; + id delegate; + + CFReadStreamClientCallBack copiedCallback; + CFStreamClientContext copiedContext; + CFOptionFlags requestedEvents; + ASIHTTPRequest *request; } + + (id)inputStreamWithFileAtPath:(NSString *)path request:(ASIHTTPRequest *)request; + (id)inputStreamWithData:(NSData *)data request:(ASIHTTPRequest *)request; +- (id)initWithInputStream:(NSInputStream *)stream; -@property (retain, nonatomic) NSInputStream *stream; @property (assign, nonatomic) ASIHTTPRequest *request; @end diff --git a/Classes/ASIInputStream.m b/Classes/ASIInputStream.m index dc998eb9..1573066f 100644 --- a/Classes/ASIInputStream.m +++ b/Classes/ASIInputStream.m @@ -8,6 +8,7 @@ #import "ASIInputStream.h" #import "ASIHTTPRequest.h" +#import // Used to ensure only one request can read data at once static NSLock *readLock = nil; @@ -16,60 +17,49 @@ @implementation ASIInputStream + (void)initialize { - if (self == [ASIInputStream class]) { - readLock = [[NSLock alloc] init]; - } + if (self == [ASIInputStream class]) { + readLock = [[NSLock alloc] init]; + } } + (id)inputStreamWithFileAtPath:(NSString *)path request:(ASIHTTPRequest *)theRequest { - ASIInputStream *theStream = [[[self alloc] init] autorelease]; - [theStream setRequest:theRequest]; - [theStream setStream:[NSInputStream inputStreamWithFileAtPath:path]]; - return theStream; + ASIInputStream *theStream = [[[ASIInputStream alloc] initWithInputStream:[NSInputStream inputStreamWithFileAtPath:path]] autorelease]; + [theStream setRequest:theRequest]; + return theStream; } + (id)inputStreamWithData:(NSData *)data request:(ASIHTTPRequest *)theRequest { - ASIInputStream *theStream = [[[self alloc] init] autorelease]; - [theStream setRequest:theRequest]; - [theStream setStream:[NSInputStream inputStreamWithData:data]]; - return theStream; + ASIInputStream *theStream = [[[ASIInputStream alloc] initWithInputStream:[NSInputStream inputStreamWithData:data]] autorelease]; + [theStream setRequest:theRequest]; + return theStream; } -- (void)dealloc +#pragma mark - Object lifecycle + +- (id)initWithInputStream:(NSInputStream *)aStream { - [stream release]; - [super dealloc]; + self = [super init]; + if (self) { + // Initialization code here. + stream = [aStream retain]; + [stream setDelegate:self]; + + [self setDelegate:self]; + } + + return self; } -// Called when CFNetwork wants to read more of our request body -// When throttling is on, we ask ASIHTTPRequest for the maximum amount of data we can read -- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len +- (void)dealloc { - [readLock lock]; - unsigned long toRead = len; - if ([ASIHTTPRequest isBandwidthThrottled]) { - toRead = [ASIHTTPRequest maxUploadReadLength]; - if (toRead > len) { - toRead = len; - } else if (toRead == 0) { - toRead = 1; - } - [request performThrottling]; - } - [readLock unlock]; - NSInteger rv = [stream read:buffer maxLength:toRead]; - if (rv > 0) - [ASIHTTPRequest incrementBandwidthUsedInLastSecond:(NSUInteger)rv]; - return rv; -} - -/* - * Implement NSInputStream mandatory methods to make sure they are implemented - * (necessary for MacRuby for example) and avoid the overhead of method - * forwarding for these common methods. - */ + [stream release]; + [super dealloc]; +} + +#pragma mark - NSStream subclass methods + - (void)open { [stream open]; @@ -80,14 +70,19 @@ - (void)close [stream close]; } -- (id)delegate +- (id )delegate { - return [stream delegate]; + return delegate; } -- (void)setDelegate:(id)delegate +- (void)setDelegate:(id)aDelegate { - [stream setDelegate:delegate]; + if (aDelegate == nil) { + delegate = self; + } + else { + delegate = aDelegate; + } } - (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode @@ -120,19 +115,161 @@ - (NSError *)streamError return [stream streamError]; } +#pragma mark - NSInputStream subclass methods + +// Called when CFNetwork wants to read more of our request body +// When throttling is on, we ask ASIHTTPRequest for the maximum amount of data we can read +- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len +{ + [readLock lock]; + unsigned long toRead = len; + if ([ASIHTTPRequest isBandwidthThrottled]) { + toRead = [ASIHTTPRequest maxUploadReadLength]; + if (toRead > len) { + toRead = len; + } else if (toRead == 0) { + toRead = 1; + } + [request performThrottling]; + } + [readLock unlock]; + NSInteger rv = [stream read:buffer maxLength:toRead]; + if (rv > 0) + [ASIHTTPRequest incrementBandwidthUsedInLastSecond:(unsigned long)rv]; + return rv; +} + + +- (BOOL)getBuffer:(uint8_t **)buffer length:(NSUInteger *)len +{ + // We cannot implement our character-counting in O(1) time, + // so we return NO as indicated in the NSInputStream + // documentation. + return NO; +} + +- (BOOL)hasBytesAvailable +{ + return [stream hasBytesAvailable]; +} + +#pragma mark - Undocumented CFReadStream bridged methods + ++ (BOOL)resolveInstanceMethod:(SEL) selector +{ + NSString *name = NSStringFromSelector(selector); + + if ([name hasPrefix:@"_"]){ + name = [name substringFromIndex:1]; + SEL aSelector = NSSelectorFromString(name); + Method method = class_getInstanceMethod(self, aSelector); + + if (method) + { + class_addMethod(self, + selector, + method_getImplementation(method), + method_getTypeEncoding(method)); + return YES; + } + } + return [super resolveInstanceMethod:selector]; +} + +- (void)scheduleInCFRunLoop:(CFRunLoopRef)aRunLoop forMode:(CFStringRef)aMode +{ + CFReadStreamScheduleWithRunLoop((CFReadStreamRef)stream, aRunLoop, aMode); +} + +- (BOOL)setCFClientFlags:(CFOptionFlags)inFlags callback:(CFReadStreamClientCallBack)inCallback context:(CFStreamClientContext *)inContext +{ + if (inCallback != NULL) { + requestedEvents = inFlags; + copiedCallback = inCallback; + memcpy(&copiedContext, inContext, sizeof(CFStreamClientContext)); + + if (copiedContext.info && copiedContext.retain) { + copiedContext.retain(copiedContext.info); + } + } + else { + requestedEvents = kCFStreamEventNone; + copiedCallback = NULL; + if (copiedContext.info && copiedContext.release) { + copiedContext.release(copiedContext.info); + } + + memset(&copiedContext, 0, sizeof(CFStreamClientContext)); + } + + return YES; +} + +- (void)unscheduleFromCFRunLoop:(CFRunLoopRef)aRunLoop forMode:(CFStringRef)aMode +{ + CFReadStreamUnscheduleFromRunLoop((CFReadStreamRef)stream, aRunLoop, aMode); +} + +#pragma mark - NSStreamDelegate methods + +- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode +{ + assert(aStream == stream); + + switch (eventCode) { + case NSStreamEventOpenCompleted: + if (requestedEvents & kCFStreamEventOpenCompleted) { + copiedCallback((CFReadStreamRef)self, + kCFStreamEventOpenCompleted, + copiedContext.info); + } + break; + + case NSStreamEventHasBytesAvailable: + if (requestedEvents & kCFStreamEventHasBytesAvailable) { + copiedCallback((CFReadStreamRef)self, + kCFStreamEventHasBytesAvailable, + copiedContext.info); + } + break; + + case NSStreamEventErrorOccurred: + if (requestedEvents & kCFStreamEventErrorOccurred) { + copiedCallback((CFReadStreamRef)self, + kCFStreamEventErrorOccurred, + copiedContext.info); + } + break; + + case NSStreamEventEndEncountered: + if (requestedEvents & kCFStreamEventEndEncountered) { + copiedCallback((CFReadStreamRef)self, + kCFStreamEventEndEncountered, + copiedContext.info); + } + break; + + case NSStreamEventHasSpaceAvailable: + // This doesn't make sense for a read stream + break; + + default: + break; + } +} + // If we get asked to perform a method we don't have (probably internal ones), // we'll just forward the message to our stream - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { - return [stream methodSignatureForSelector:aSelector]; + return [stream methodSignatureForSelector:aSelector]; } - + - (void)forwardInvocation:(NSInvocation *)anInvocation { - [anInvocation invokeWithTarget:stream]; + [anInvocation invokeWithTarget:stream]; } -@synthesize stream; @synthesize request; @end diff --git a/Mac Sample/AppDelegate.m b/Mac Sample/AppDelegate.m index 8d96372d..b57e9d96 100644 --- a/Mac Sample/AppDelegate.m +++ b/Mac Sample/AppDelegate.m @@ -358,15 +358,15 @@ - (void)tableViewDataFetchFinished:(ASIHTTPRequest *)request - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView { - return [[self rowData] count]; + return (NSInteger)[[self rowData] count]; } - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { if ([[aTableColumn identifier] isEqualToString:@"image"]) { - return [[[self rowData] objectAtIndex:rowIndex] objectForKey:@"image"]; + return [[[self rowData] objectAtIndex:(NSUInteger)rowIndex] objectForKey:@"image"]; } else { - return [[[self rowData] objectAtIndex:rowIndex] objectForKey:@"description"]; + return [[[self rowData] objectAtIndex:(NSUInteger)rowIndex] objectForKey:@"description"]; } } diff --git a/Mac.xcodeproj/project.pbxproj b/Mac.xcodeproj/project.pbxproj index d6fa1b47..9e5ac752 100644 --- a/Mac.xcodeproj/project.pbxproj +++ b/Mac.xcodeproj/project.pbxproj @@ -713,7 +713,7 @@ GCC_OPTIMIZATION_LEVEL = 0; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.6; + MACOSX_DEPLOYMENT_TARGET = 10.5; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; }; @@ -726,7 +726,7 @@ GCC_C_LANGUAGE_STANDARD = "compiler-default"; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.6; + MACOSX_DEPLOYMENT_TARGET = 10.5; SDKROOT = macosx; }; name = Release; diff --git a/iPhone.xcodeproj/project.pbxproj b/iPhone.xcodeproj/project.pbxproj index 704320fe..df0399d8 100644 --- a/iPhone.xcodeproj/project.pbxproj +++ b/iPhone.xcodeproj/project.pbxproj @@ -828,6 +828,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD)"; CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -840,7 +841,7 @@ GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = "${SDK_DIR}/usr/include/libxml2"; INFOPLIST_FILE = "iPhone Sample/iPhoneInfo.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 3.1.3; + IPHONEOS_DEPLOYMENT_TARGET = 5.1.1; PRODUCT_NAME = "ASIHTTPRequest iPhone"; "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; TARGETED_DEVICE_FAMILY = 1; @@ -851,6 +852,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD)"; CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -860,7 +862,7 @@ GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = "${SDK_DIR}/usr/include/libxml2"; INFOPLIST_FILE = "iPhone Sample/iPhoneInfo.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 3.1.3; + IPHONEOS_DEPLOYMENT_TARGET = 5.1.1; PRODUCT_NAME = "ASIHTTPRequest iPhone"; "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; TARGETED_DEVICE_FAMILY = 1;