Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions ImageFiller.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
5014695D18C8D68200785E1B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5014695B18C8D68200785E1B /* InfoPlist.strings */; };
5014695F18C8D68200785E1B /* ImageFillerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5014695E18C8D68200785E1B /* ImageFillerTests.m */; };
5014696918C8DCAB00785E1B /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5014696818C8DCAB00785E1B /* AssetsLibrary.framework */; };
772F2BE918FF8AFC005258DD /* CHHTTPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 772F2BE818FF8AFC005258DD /* CHHTTPConnection.m */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -55,6 +56,8 @@
5014695C18C8D68200785E1B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
5014695E18C8D68200785E1B /* ImageFillerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ImageFillerTests.m; sourceTree = "<group>"; };
5014696818C8DCAB00785E1B /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; };
772F2BE718FF8AFC005258DD /* CHHTTPConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CHHTTPConnection.h; sourceTree = "<group>"; };
772F2BE818FF8AFC005258DD /* CHHTTPConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CHHTTPConnection.m; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -116,6 +119,8 @@
5014693918C8D68200785E1B /* ImageFiller */ = {
isa = PBXGroup;
children = (
772F2BE718FF8AFC005258DD /* CHHTTPConnection.h */,
772F2BE818FF8AFC005258DD /* CHHTTPConnection.m */,
5014694218C8D68200785E1B /* IFAppDelegate.h */,
5014694318C8D68200785E1B /* IFAppDelegate.m */,
5014694518C8D68200785E1B /* Main.storyboard */,
Expand Down Expand Up @@ -257,6 +262,7 @@
5014694018C8D68200785E1B /* main.m in Sources */,
5014694418C8D68200785E1B /* IFAppDelegate.m in Sources */,
5014694A18C8D68200785E1B /* IFViewController.m in Sources */,
772F2BE918FF8AFC005258DD /* CHHTTPConnection.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -386,6 +392,7 @@
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "ImageFiller/ImageFiller-Prefix.pch";
INFOPLIST_FILE = "ImageFiller/ImageFiller-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 6.0;
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
Expand All @@ -399,6 +406,7 @@
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "ImageFiller/ImageFiller-Prefix.pch";
INFOPLIST_FILE = "ImageFiller/ImageFiller-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 6.0;
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
Expand Down Expand Up @@ -465,6 +473,7 @@
5014696418C8D68200785E1B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
5014696518C8D68200785E1B /* Build configuration list for PBXNativeTarget "ImageFillerTests" */ = {
isa = XCConfigurationList;
Expand All @@ -473,6 +482,7 @@
5014696718C8D68200785E1B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
Expand Down
20 changes: 20 additions & 0 deletions ImageFiller/CHHTTPConnection.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// CHHTTPConnection.h
// ImageFiller
//
// Created by hangchen on 4/17/14.
// Copyright (c) 2014 Hang Chen (https://github.com/cyndibaby905)

#import <Foundation/Foundation.h>


typedef void (^OnComplete) (NSHTTPURLResponse *response, NSData *data, NSError *error);


@interface CHHTTPConnection : NSObject

- (id)initWithRequest:(NSURLRequest *)urlRequest;

- (BOOL)executeRequestOnComplete:(OnComplete)OnCompleteBlock;

@end
79 changes: 79 additions & 0 deletions ImageFiller/CHHTTPConnection.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//
// CHHTTPConnection.m
// ImageFiller
//
// Created by hangchen on 4/17/14.
// Copyright (c) 2014 Hang Chen (https://github.com/cyndibaby905)

#import "CHHTTPConnection.h"


@interface CHHTTPConnection ()

@property (nonatomic, strong) NSURLRequest *request;
@property (nonatomic, strong) NSHTTPURLResponse *response;
@property (nonatomic, strong) NSMutableData *data;
@property (nonatomic, readonly) NSString *body;

@property (nonatomic, copy) OnComplete onComplete;

@end


@implementation CHHTTPConnection

- (id)initWithRequest:(NSURLRequest *)urlRequest
{
self = [super init];
if (self) {
self.request = urlRequest;
}
return self;
}

- (NSString *)body
{
return [[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding];
}

- (BOOL)executeRequestOnComplete:(OnComplete)OnCompleteBlock
{
self.onComplete = OnCompleteBlock;

[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self];
return connection != nil;
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)aResponse
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)aResponse;
self.response = httpResponse;

self.data = [NSMutableData data];
[self.data setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)bytes
{
[self.data appendData:bytes];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

if (self.onComplete)
self.onComplete(self.response, self.data, error);
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

if (self.onComplete)
self.onComplete(self.response, self.data, nil);
}

@end
161 changes: 107 additions & 54 deletions ImageFiller/IFViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,22 @@
#import <ImageIO/ImageIO.h>

#import "IFViewController.h"
#import "CHHTTPConnection.h"
//You can define the max concurrent count when writing to photo library

#if TARGET_IPHONE_SIMULATOR
#define MAXConcurrentCount NSIntegerMax
#else
#define MAXConcurrentCount 100//Tested in iTouch 4, iOS 6, 100 is safe to use. You can adjust the count if needed.
#endif

@interface IFViewController ()

@property (strong) NSURLSession *session;
@property (assign) NSInteger totalImageDownloadCount;
@property (assign) NSInteger totalImageWriteCount;
@property (assign) NSInteger totalImagesWrittenCount;
@property (strong) NSMutableArray *images;
@property (strong) NSMutableArray *imagePATHs;

@property (strong) ALAssetsLibrary *assetsLibrary;

Expand Down Expand Up @@ -49,30 +57,44 @@ - (void)addImagesToLibrary
[exifDateFormatter setDateFormat:@"yyyy:MM:dd HH:mm:ss"];

self.totalImagesWrittenCount = 0;
__block NSInteger maxConcurrentCount = MAXConcurrentCount;

dispatch_async(dispatch_get_main_queue(), ^{
for (NSInteger index = 0; index < self.totalImageWriteCount; index++) {
UIImage *image = self.images[arc4random() % self.images.count];

NSDate *date = [NSDate dateWithTimeIntervalSinceNow:-(float)(arc4random() % (5 * 365 * 24 * 3600))];

NSDictionary *exifData = @{ (NSString *)kCGImagePropertyExifDateTimeOriginal: [exifDateFormatter stringFromDate:date] };

NSDictionary *metadata = @{ (NSString *)kCGImagePropertyExifDictionary: exifData };

[self.assetsLibrary writeImageToSavedPhotosAlbum:image.CGImage
metadata:metadata
completionBlock:^(NSURL *assetURL, NSError *error) {
self.totalImagesWrittenCount += 1;
[self progress:self.totalImagesWrittenCount
of:self.totalImageWriteCount];

if (self.totalImageWriteCount == self.totalImagesWrittenCount) {
[self log:@"complete!"];
}
}];
for (NSInteger index = 0; index < self.totalImageWriteCount; index++) {
UIImage *image = [UIImage imageWithContentsOfFile:self.imagePATHs[arc4random() % self.imagePATHs.count]];

NSDate *date = [NSDate dateWithTimeIntervalSinceNow:-(float)(arc4random() % (5 * 365 * 24 * 3600))];

NSDictionary *exifData = @{ (NSString *)kCGImagePropertyExifDateTimeOriginal: [exifDateFormatter stringFromDate:date] };

NSDictionary *metadata = @{ (NSString *)kCGImagePropertyExifDictionary: exifData };


maxConcurrentCount--;
[self.assetsLibrary writeImageToSavedPhotosAlbum:image.CGImage
metadata:metadata
completionBlock:^(NSURL *assetURL, NSError *error) {
self.totalImagesWrittenCount += 1;

[self progress:self.totalImagesWrittenCount
of:self.totalImageWriteCount];

if (self.totalImageWriteCount == self.totalImagesWrittenCount) {
[self log:@"complete!"];
}

maxConcurrentCount++;
}];

//Wati until write operation finished when target is a real device, otherwise memory pressure will cause crash
NSTimeInterval checkEveryInterval = 0.1;
while(maxConcurrentCount < 0) {
@autoreleasepool {
if (![[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:checkEveryInterval]])
[NSThread sleepForTimeInterval:checkEveryInterval];
}
}
});
}

}

- (void)log:(NSString *)log
Expand All @@ -92,43 +114,74 @@ - (void)progress:(NSInteger)progress of:(NSInteger)total

- (IBAction)loadImages:(id)sender {
[self log:@"loading images"];

self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];

self.images = [NSMutableArray array];
self.imagePATHs = [NSMutableArray array];

NSURL *tempURL = [NSURL fileURLWithPath:NSTemporaryDirectory()];

if (NSClassFromString(@"NSURLSession")) {
self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
}


for (NSInteger index = 0; index < self.totalImageDownloadCount; index++) {
NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"http://lorempixel.com/400/400/?%i", arc4random()]];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithRequest:request
completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
NSString *filename = [NSString stringWithFormat:@"image%i.jpg", arc4random()];
NSURL *imageURL = [tempURL URLByAppendingPathComponent:filename];

NSError *fileError;
[[NSFileManager defaultManager] moveItemAtURL:location
toURL:imageURL
error:&fileError];
NSAssert(fileError == nil, @"something happended");

UIImage *image = [[UIImage alloc] initWithContentsOfFile:imageURL.path];

NSAssert(image.size.width != 0 && image.size.height != 0, @"image is no image");

[self.images addObject:image];
[self log:[NSString stringWithFormat:@"loaded %lu of %li images", (unsigned long)self.images.count, (long)self.totalImageDownloadCount]];

[self progress:self.images.count
of:self.totalImageDownloadCount];


if (self.images.count == self.totalImageDownloadCount) {
[self addImagesToLibrary];
}
}];
[downloadTask resume];
if (self.session) {
NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithRequest:request
completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
NSString *filename = [NSString stringWithFormat:@"image%i.jpg", arc4random()];
NSURL *imageURL = [tempURL URLByAppendingPathComponent:filename];

NSError *fileError;
[[NSFileManager defaultManager] moveItemAtURL:location
toURL:imageURL
error:&fileError];
NSAssert(fileError == nil, @"something happended");

UIImage *image = [[UIImage alloc] initWithContentsOfFile:imageURL.path];

NSAssert(image.size.width != 0 && image.size.height != 0, @"image is no image");

[self.imagePATHs addObject:imageURL.path];
[self log:[NSString stringWithFormat:@"loaded %lu of %li images", (unsigned long)self.imagePATHs.count, (long)self.totalImageDownloadCount]];

[self progress:self.imagePATHs.count
of:self.totalImageDownloadCount];


if (self.imagePATHs.count == self.totalImageDownloadCount) {
[self addImagesToLibrary];
}
}];
[downloadTask resume];
}
else {
CHHTTPConnection *connection = [[CHHTTPConnection alloc] initWithRequest:request];

[connection executeRequestOnComplete:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
NSAssert(data != nil, @"Data is nil");
NSString *filename = [NSString stringWithFormat:@"image%i.jpg", arc4random()];
NSURL *imageURL = [tempURL URLByAppendingPathComponent:filename];

BOOL result = [data writeToURL:imageURL atomically:YES];
NSAssert(result == YES, @"Write fail");


[self.imagePATHs addObject:imageURL.path];


[self progress:self.imagePATHs.count
of:self.totalImageDownloadCount];


if (self.imagePATHs.count == self.totalImageDownloadCount) {
[self addImagesToLibrary];
}

}];
}
}


}
@end