Skip to content

Instantly share code, notes, and snippets.

@Shilo
Created October 17, 2012 03:50
Show Gist options
  • Save Shilo/3903607 to your computer and use it in GitHub Desktop.
Save Shilo/3903607 to your computer and use it in GitHub Desktop.
An extension for Sparrow that allows SPImage/SPTexture to load web files, NSData, and asynchronously. (Requires ARC)
//
// SPTexture+Web.h
// SPTexture+Web
//
// Created by Shilo White on 10/16/12.
//
// (Requires Automatic Reference Counting)
#import "SPTexture.h"
#import "SPImage.h"
#import "SPEvent.h"
#define SP_EVENT_TYPE_IMAGE_LOADED @"imageLoaded"
#define SP_EVENT_TYPE_IMAGE_FAILED @"imageFailed"
@interface SPTexture (Web)
- (SPTexture *)initWithContentsOfWebFile:(NSString *)path;
- (SPTexture *)initWithContentsOfWebFile:(NSString *)path options:(NSDataReadingOptions)options error:(NSError *__autoreleasing *)error;
- (SPTexture *)initWithData:(NSData *)data;
+ (SPTexture *)textureWithContentsOfWebFile:(NSString *)path;
+ (SPTexture *)textureWithContentsOfWebFile:(NSString *)path options:(NSDataReadingOptions)options error:(NSError *__autoreleasing *)error;
+ (SPTexture *)textureWithData:(NSData *)data;
@end
@interface SPImage (Web)
- (SPImage *)initWithContentsOfWebFile:(NSString *)path;
- (SPImage *)initWithContentsOfWebFile:(NSString *)path options:(NSDataReadingOptions)options error:(NSError *__autoreleasing *)error;
- (SPImage *)initWithData:(NSData *)data;
- (SPImage *)initWithContentsOfAsyncFile:(NSString *)path;
- (SPImage *)initWithContentsOfAsyncWebFile:(NSString *)path;
+ (SPImage *)imageWithContentsOfWebFile:(NSString *)path;
+ (SPImage *)imageWithContentsOfWebFile:(NSString *)path options:(NSDataReadingOptions)options error:(NSError *__autoreleasing *)error;
+ (SPImage *)imageWithData:(NSData *)data;
+ (SPImage *)imageWithContentsOfAsyncFile:(NSString *)path;
+ (SPImage *)imageWithContentsOfAsyncWebFile:(NSString *)path;
@end
@interface SPImageEvent : SPEvent
- (SPImageEvent *)initWithType:(NSString*)type bubbles:(BOOL)bubbles error:(NSError *)error;
+ (SPImageEvent *)imageEventWithType:(NSString*)type bubbles:(BOOL)bubbles error:(NSError *)error;
@property (nonatomic, readonly) NSError *error;
@end
//
// SPTexture+Web.m
// SPTexture+Web
//
// Created by Shilo White on 10/16/12.
//
// (Requires Automatic Reference Counting)
#import "SPTexture+Web.h"
#import <objc/runtime.h>
#define ASYNC_TIMEOUT 60.0f
#define DEFAULT_CAPACITY 102400
@implementation SPTexture (Web)
- (SPTexture *)initWithContentsOfWebFile:(NSString *)path
{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:path]];
return [self initWithData:data];
}
- (SPTexture *)initWithContentsOfWebFile:(NSString *)path options:(NSDataReadingOptions)options error:(NSError *__autoreleasing *)error
{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:path] options:options error:error];
return [self initWithData:data];
}
- (SPTexture *)initWithData:(NSData *)data
{
return [self initWithContentsOfImage:[UIImage imageWithData:data]];
}
+ (SPTexture *)textureWithContentsOfWebFile:(NSString *)path
{
return [[self alloc] initWithContentsOfWebFile:path];
}
+ (SPTexture *)textureWithContentsOfWebFile:(NSString *)path options:(NSDataReadingOptions)options error:(NSError *__autoreleasing *)error
{
return [[self alloc] initWithContentsOfWebFile:path options:options error:error];
}
+ (SPTexture *)textureWithData:(NSData *)data
{
return [[self alloc] initWithData:data];
}
@end
@interface SPImage (WebPrivate)
@property (nonatomic, strong) NSURLConnection *connection;
@property (nonatomic, strong) NSMutableData *data;
@end
@implementation SPImage (WebPrivate)
- (void)setConnection:(NSURLConnection *)connection
{
objc_setAssociatedObject(self, (__bridge const void *)@"connection", connection, OBJC_ASSOCIATION_RETAIN);
}
- (NSURLConnection *)connection
{
return objc_getAssociatedObject(self, (__bridge const void *)@"connection");
}
- (void)setData:(NSMutableData *)data
{
objc_setAssociatedObject(self, (__bridge const void *)@"data", data, OBJC_ASSOCIATION_RETAIN);
}
- (NSMutableData *)data
{
return objc_getAssociatedObject(self, (__bridge const void *)@"data");
}
@end
@implementation SPImage (Web)
- (SPImage *)initWithContentsOfWebFile:(NSString *)path
{
SPTexture *texture = [SPTexture textureWithContentsOfWebFile:path];
return [self initWithTexture:texture];
}
- (SPImage *)initWithContentsOfWebFile:(NSString *)path options:(NSDataReadingOptions)options error:(NSError *__autoreleasing *)error
{
SPTexture *texture = [SPTexture textureWithContentsOfWebFile:path options:options error:error];
return [self initWithTexture:texture];
}
- (SPImage *)initWithData:(NSData *)data
{
SPTexture *texture = [SPTexture textureWithData:data];
return [self initWithTexture:texture];
}
- (SPImage *)initWithContentsOfAsyncFile:(NSString *)path
{
if ((self = [super init]))
{
NSString *fullPath = [SPUtils absolutePathToFile:path withScaleFactor:[SPStage contentScaleFactor]];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:fullPath] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:ASYNC_TIMEOUT];
self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
return self;
}
- (SPImage *)initWithContentsOfAsyncWebFile:(NSString *)path
{
if ((self = [super init]))
{
NSURL *url = [NSURL URLWithString:path];
if (!url.scheme) url = [NSURL URLWithString:[@"http://" stringByAppendingString:path]];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:ASYNC_TIMEOUT];
self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
return self;
}
+ (SPImage *)imageWithContentsOfWebFile:(NSString *)path
{
return [[self alloc] initWithContentsOfWebFile:path];
}
+ (SPImage *)imageWithContentsOfWebFile:(NSString *)path options:(NSDataReadingOptions)options error:(NSError *__autoreleasing *)error
{
return [[self alloc] initWithContentsOfWebFile:path options:options error:error];
}
+ (SPImage *)imageWithData:(NSData *)data
{
return [[self alloc] initWithData:data];
}
+ (SPImage *)imageWithContentsOfAsyncFile:(NSString *)path
{
return [[self alloc] initWithContentsOfAsyncFile:path];
}
+ (SPImage *)imageWithContentsOfAsyncWebFile:(NSString *)path
{
return [[self alloc] initWithContentsOfAsyncWebFile:path];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
long long capacity = (response.expectedContentLength != NSURLResponseUnknownLength) ? response.expectedContentLength : DEFAULT_CAPACITY;
self.data = [[NSMutableData alloc] initWithCapacity:capacity];
}
- (void)connection:(NSURLConnection *)urlConnection didReceiveData:(NSData *)data
{
[self.data appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
SPTexture *texture = [SPTexture textureWithData:self.data];
(void)[self initWithTexture:texture];
self.data = nil;
self.connection = nil;
SPEvent *loadedEvent = [SPEvent eventWithType:SP_EVENT_TYPE_IMAGE_LOADED];
[self dispatchEvent:loadedEvent];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
SPImageEvent *failedImageEvent = [SPImageEvent imageEventWithType:SP_EVENT_TYPE_IMAGE_FAILED bubbles:NO error:error];
[self dispatchEvent:failedImageEvent];
self.data = nil;
self.connection = nil;
}
@end
@implementation SPImageEvent
{
NSError *_error;
}
@synthesize error = _error;
- (SPImageEvent *)initWithType:(NSString*)type bubbles:(BOOL)bubbles error:(NSError *)error
{
if (self = [super initWithType:type bubbles:bubbles])
{
_error = error;
}
return self;
}
+ (SPImageEvent *)imageEventWithType:(NSString*)type bubbles:(BOOL)bubbles error:(NSError *)error
{
return [[self alloc] initWithType:type bubbles:bubbles error:error];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment