diff --git a/Podfile b/Podfile index 942cd15..ec7bc7b 100644 --- a/Podfile +++ b/Podfile @@ -1,10 +1,10 @@ source 'https://github.com/CocoaPods/Specs.git' platform :ios, '7.0' -pod 'AFNetworking', '~> 2.5' -pod 'CocoaLumberjack', '= 2.0.0' + +pod 'CocoaLumberjack', '~> 2.2.0' target 'WordPress-iOS-SharedTests', :exclusive => true do - pod 'OHHTTPStubs', '3.1.1' + pod 'OHHTTPStubs' pod 'OCMock' end diff --git a/Podfile.lock b/Podfile.lock index 5babc7b..b26cabf 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,46 +1,35 @@ PODS: - - AFNetworking (2.5.4): - - AFNetworking/NSURLConnection (= 2.5.4) - - AFNetworking/NSURLSession (= 2.5.4) - - AFNetworking/Reachability (= 2.5.4) - - AFNetworking/Security (= 2.5.4) - - AFNetworking/Serialization (= 2.5.4) - - AFNetworking/UIKit (= 2.5.4) - - AFNetworking/NSURLConnection (2.5.4): - - AFNetworking/Reachability - - AFNetworking/Security - - AFNetworking/Serialization - - AFNetworking/NSURLSession (2.5.4): - - AFNetworking/Reachability - - AFNetworking/Security - - AFNetworking/Serialization - - AFNetworking/Reachability (2.5.4) - - AFNetworking/Security (2.5.4) - - AFNetworking/Serialization (2.5.4) - - AFNetworking/UIKit (2.5.4): - - AFNetworking/NSURLConnection - - AFNetworking/NSURLSession - - CocoaLumberjack (2.0.0): - - CocoaLumberjack/Default (= 2.0.0) - - CocoaLumberjack/Extensions (= 2.0.0) - - CocoaLumberjack/Core (2.0.0) - - CocoaLumberjack/Default (2.0.0): + - CocoaLumberjack (2.2.0): + - CocoaLumberjack/Default (= 2.2.0) + - CocoaLumberjack/Extensions (= 2.2.0) + - CocoaLumberjack/Core (2.2.0) + - CocoaLumberjack/Default (2.2.0): - CocoaLumberjack/Core - - CocoaLumberjack/Extensions (2.0.0): + - CocoaLumberjack/Extensions (2.2.0): - CocoaLumberjack/Default - - OCMock (3.1.2) - - OHHTTPStubs (3.1.1) + - OCMock (3.2.2) + - OHHTTPStubs (5.0.0): + - OHHTTPStubs/Default (= 5.0.0) + - OHHTTPStubs/Core (5.0.0) + - OHHTTPStubs/Default (5.0.0): + - OHHTTPStubs/Core + - OHHTTPStubs/JSON + - OHHTTPStubs/NSURLSession + - OHHTTPStubs/OHPathHelpers + - OHHTTPStubs/JSON (5.0.0): + - OHHTTPStubs/Core + - OHHTTPStubs/NSURLSession (5.0.0): + - OHHTTPStubs/Core + - OHHTTPStubs/OHPathHelpers (5.0.0) DEPENDENCIES: - - AFNetworking (~> 2.5) - - CocoaLumberjack (= 2.0.0) + - CocoaLumberjack (~> 2.2.0) - OCMock - - OHHTTPStubs (= 3.1.1) + - OHHTTPStubs SPEC CHECKSUMS: - AFNetworking: 05edc0ac4c4c8cf57bcf4b84be5b0744b6d8e71e - CocoaLumberjack: a6f77d987d65dc7ba86b0f84db7d0b9084f77bcb - OCMock: a10ea9f0a6e921651f96f78b6faee95ebc813b92 - OHHTTPStubs: cc1b9cb45b963daf891aa736f35d29d74308f0c9 + CocoaLumberjack: 17fe8581f84914d5d7e6360f7c70022b173c3ae0 + OCMock: 18c9b7e67d4c2770e95bb77a9cc1ae0c91fe3835 + OHHTTPStubs: a5d2e9eea07869d42ec03338325f398bc520e159 COCOAPODS: 0.39.0 diff --git a/WordPress-iOS-Shared-Example/Podfile.lock b/WordPress-iOS-Shared-Example/Podfile.lock index 1c2e1ec..e57f4e5 100644 --- a/WordPress-iOS-Shared-Example/Podfile.lock +++ b/WordPress-iOS-Shared-Example/Podfile.lock @@ -1,25 +1,4 @@ PODS: - - AFNetworking (2.6.3): - - AFNetworking/NSURLConnection (= 2.6.3) - - AFNetworking/NSURLSession (= 2.6.3) - - AFNetworking/Reachability (= 2.6.3) - - AFNetworking/Security (= 2.6.3) - - AFNetworking/Serialization (= 2.6.3) - - AFNetworking/UIKit (= 2.6.3) - - AFNetworking/NSURLConnection (2.6.3): - - AFNetworking/Reachability - - AFNetworking/Security - - AFNetworking/Serialization - - AFNetworking/NSURLSession (2.6.3): - - AFNetworking/Reachability - - AFNetworking/Security - - AFNetworking/Serialization - - AFNetworking/Reachability (2.6.3) - - AFNetworking/Security (2.6.3) - - AFNetworking/Serialization (2.6.3) - - AFNetworking/UIKit (2.6.3): - - AFNetworking/NSURLConnection - - AFNetworking/NSURLSession - CocoaLumberjack (2.2.0): - CocoaLumberjack/Default (= 2.2.0) - CocoaLumberjack/Extensions (= 2.2.0) @@ -28,8 +7,7 @@ PODS: - CocoaLumberjack/Core - CocoaLumberjack/Extensions (2.2.0): - CocoaLumberjack/Default - - WordPress-iOS-Shared (0.5.3): - - AFNetworking (~> 2.5) + - WordPress-iOS-Shared (0.5.5): - CocoaLumberjack (~> 2.2.0) DEPENDENCIES: @@ -40,8 +18,7 @@ EXTERNAL SOURCES: :path: ../ SPEC CHECKSUMS: - AFNetworking: cb8d14a848e831097108418f5d49217339d4eb60 CocoaLumberjack: 17fe8581f84914d5d7e6360f7c70022b173c3ae0 - WordPress-iOS-Shared: 43f55f24f0685e431167084071b7914d7c7134a8 + WordPress-iOS-Shared: e9e81a6a3cc3b45de93c8a565422c11395813c49 COCOAPODS: 0.39.0 diff --git a/WordPress-iOS-Shared.podspec b/WordPress-iOS-Shared.podspec index 87622d6..116dda2 100644 --- a/WordPress-iOS-Shared.podspec +++ b/WordPress-iOS-Shared.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "WordPress-iOS-Shared" - s.version = "0.5.4" + s.version = "0.5.5" s.summary = "Shared components used in building the WordPress iOS apps and other library components." s.description = <<-DESC @@ -9,9 +9,9 @@ Pod::Spec.new do |s| This is the first step required to build WordPress-iOS with UI components. DESC - s.homepage = "http://apps.wordpress.org" + s.homepage = "http://apps.wordpress.com" s.license = "GPLv2" - s.author = { "Aaron Douglas" => "astralbodies@gmail.com" } + s.author = { "Automattic" => "mobile@automattic.com", "Aaron Douglas" => "astralbodies@gmail.com", "Sergio Estevao" => "sergioestevao@gmail.com" } s.social_media_url = "http://twitter.com/WordPressiOS" s.platform = :ios, "7.0" s.source = { :git => "https://github.com/wordpress-mobile/WordPress-iOS-Shared.git", :tag => s.version.to_s } @@ -23,6 +23,5 @@ Pod::Spec.new do |s| s.requires_arc = true s.header_dir = 'WordPressShared' - s.dependency 'AFNetworking', '~> 2.5' s.dependency 'CocoaLumberjack', '~> 2.2.0' end diff --git a/WordPress-iOS-Shared.xcodeproj/project.pbxproj b/WordPress-iOS-Shared.xcodeproj/project.pbxproj index d9f59f1..bb210a6 100644 --- a/WordPress-iOS-Shared.xcodeproj/project.pbxproj +++ b/WordPress-iOS-Shared.xcodeproj/project.pbxproj @@ -12,7 +12,6 @@ 744DA846194F3A76002CD6E9 /* UIImage+Util.m in Sources */ = {isa = PBXBuildFile; fileRef = 744DA845194F3A76002CD6E9 /* UIImage+Util.m */; }; 7462F3401961FAAB00CC8EED /* WPFontManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 74F535F71961F7E6002D4320 /* WPFontManager.m */; }; 9309B52D192BEECC00B69F69 /* WordPressShared.m in Sources */ = {isa = PBXBuildFile; fileRef = 9309B52C192BEECC00B69F69 /* WordPressShared.m */; }; - 9309B533192F9C2000B69F69 /* WPAnimatedImageResponseSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 9309B532192F9C2000B69F69 /* WPAnimatedImageResponseSerializer.m */; }; 931A0FEE192A9CDD00D3CC11 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 931A0FED192A9CDD00D3CC11 /* Foundation.framework */; }; 931A0FFC192A9CDD00D3CC11 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 931A0FFB192A9CDD00D3CC11 /* XCTest.framework */; }; 931A0FFD192A9CDD00D3CC11 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 931A0FED192A9CDD00D3CC11 /* Foundation.framework */; }; @@ -29,10 +28,10 @@ 931A102E192A9E3200D3CC11 /* WPTableViewSectionHeaderFooterView.m in Sources */ = {isa = PBXBuildFile; fileRef = 931A102B192A9E3200D3CC11 /* WPTableViewSectionHeaderFooterView.m */; }; 931A1035192AA03600D3CC11 /* UIColor+Helpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 931A1034192AA03600D3CC11 /* UIColor+Helpers.m */; }; 931A1038192AA34300D3CC11 /* WPImageSourceTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 931A1037192AA34300D3CC11 /* WPImageSourceTest.m */; }; - 931A103B192AA35B00D3CC11 /* AsyncTestHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 931A103A192AA35B00D3CC11 /* AsyncTestHelper.m */; }; 931A103E192AA3DB00D3CC11 /* test-image.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 931A103D192AA3DB00D3CC11 /* test-image.jpg */; }; F45AF04D6E344F4CBD2A4B65 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AB8B405468864FD7A0D16B74 /* libPods.a */; }; FF8DDCE11B5E91050098826F /* WPTextFieldTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FF8DDCE01B5E91050098826F /* WPTextFieldTableViewCell.m */; }; + FFBC2B371CBBE10300B0379E /* anim-reader.gif in Resources */ = {isa = PBXBuildFile; fileRef = FFBC2B361CBBE10300B0379E /* anim-reader.gif */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -68,8 +67,6 @@ 897FA2B40A6E81DB4E7F0435 /* Pods-WordPress-iOS-SharedTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPress-iOS-SharedTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-WordPress-iOS-SharedTests/Pods-WordPress-iOS-SharedTests.debug.xcconfig"; sourceTree = ""; }; 9309B52B192BEECC00B69F69 /* WordPressShared.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WordPressShared.h; path = Exclude/WordPressShared.h; sourceTree = ""; }; 9309B52C192BEECC00B69F69 /* WordPressShared.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WordPressShared.m; path = Exclude/WordPressShared.m; sourceTree = ""; }; - 9309B531192F9C2000B69F69 /* WPAnimatedImageResponseSerializer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WPAnimatedImageResponseSerializer.h; sourceTree = ""; }; - 9309B532192F9C2000B69F69 /* WPAnimatedImageResponseSerializer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WPAnimatedImageResponseSerializer.m; sourceTree = ""; }; 931A0FEA192A9CDD00D3CC11 /* libWordPress-iOS-Shared.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libWordPress-iOS-Shared.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 931A0FED192A9CDD00D3CC11 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 931A0FF1192A9CDD00D3CC11 /* WordPress-iOS-Shared-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WordPress-iOS-Shared-Prefix.pch"; sourceTree = ""; }; @@ -98,14 +95,17 @@ 931A1033192AA03600D3CC11 /* UIColor+Helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIColor+Helpers.h"; path = "Core/UIColor+Helpers.h"; sourceTree = ""; }; 931A1034192AA03600D3CC11 /* UIColor+Helpers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIColor+Helpers.m"; path = "Core/UIColor+Helpers.m"; sourceTree = ""; }; 931A1037192AA34300D3CC11 /* WPImageSourceTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WPImageSourceTest.m; sourceTree = ""; }; - 931A1039192AA35B00D3CC11 /* AsyncTestHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AsyncTestHelper.h; sourceTree = ""; }; - 931A103A192AA35B00D3CC11 /* AsyncTestHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AsyncTestHelper.m; sourceTree = ""; }; 931A103D192AA3DB00D3CC11 /* test-image.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "test-image.jpg"; sourceTree = ""; }; 98398B801DD76BC0326A4729 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; A7CDA9068CC847B2AD67DE41 /* libPods-WordPress-iOS-SharedTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-WordPress-iOS-SharedTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; AB8B405468864FD7A0D16B74 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; E95607083C359C14B48BA503 /* Pods-WordPress-iOS-SharedTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPress-iOS-SharedTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-WordPress-iOS-SharedTests/Pods-WordPress-iOS-SharedTests.release.xcconfig"; sourceTree = ""; }; + FF14587C1CBE6D37004A5A0B /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + FF14587D1CBE6D37004A5A0B /* Podfile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Podfile; sourceTree = ""; }; + FF14587E1CBE6D37004A5A0B /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; + FF1458801CBE6D59004A5A0B /* WordPress-iOS-Shared.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "WordPress-iOS-Shared.podspec"; sourceTree = ""; }; FF8DDCE01B5E91050098826F /* WPTextFieldTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WPTextFieldTableViewCell.m; path = Core/WPTextFieldTableViewCell.m; sourceTree = ""; }; + FFBC2B361CBBE10300B0379E /* anim-reader.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = "anim-reader.gif"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -136,6 +136,7 @@ 931A0FE1192A9CDD00D3CC11 = { isa = PBXGroup; children = ( + FF14587B1CBE6D24004A5A0B /* Podspec Metadata */, 931A0FEF192A9CDD00D3CC11 /* WordPress-iOS-Shared */, 931A1003192A9CDD00D3CC11 /* WordPress-iOS-SharedTests */, 931A0FEC192A9CDD00D3CC11 /* Frameworks */, @@ -168,7 +169,6 @@ 931A0FEF192A9CDD00D3CC11 /* WordPress-iOS-Shared */ = { isa = PBXGroup; children = ( - E13D93EF1BF235BA00CCBA7C /* Private */, E154809F1A43035700FA4EDD /* Core */, 931A0FF0192A9CDD00D3CC11 /* Supporting Files */, ); @@ -198,8 +198,6 @@ 931A1004192A9CDD00D3CC11 /* Supporting Files */ = { isa = PBXGroup; children = ( - 931A1039192AA35B00D3CC11 /* AsyncTestHelper.h */, - 931A103A192AA35B00D3CC11 /* AsyncTestHelper.m */, 931A1005192A9CDD00D3CC11 /* WordPress-iOS-SharedTests-Info.plist */, 931A1006192A9CDD00D3CC11 /* InfoPlist.strings */, ); @@ -259,20 +257,12 @@ 931A103C192AA3B500D3CC11 /* Test Data */ = { isa = PBXGroup; children = ( + FFBC2B361CBBE10300B0379E /* anim-reader.gif */, 931A103D192AA3DB00D3CC11 /* test-image.jpg */, ); name = "Test Data"; sourceTree = ""; }; - E13D93EF1BF235BA00CCBA7C /* Private */ = { - isa = PBXGroup; - children = ( - 9309B531192F9C2000B69F69 /* WPAnimatedImageResponseSerializer.h */, - 9309B532192F9C2000B69F69 /* WPAnimatedImageResponseSerializer.m */, - ); - path = Private; - sourceTree = ""; - }; E154809F1A43035700FA4EDD /* Core */ = { isa = PBXGroup; children = ( @@ -293,6 +283,17 @@ name = Pods; sourceTree = ""; }; + FF14587B1CBE6D24004A5A0B /* Podspec Metadata */ = { + isa = PBXGroup; + children = ( + FF1458801CBE6D59004A5A0B /* WordPress-iOS-Shared.podspec */, + FF14587C1CBE6D37004A5A0B /* README.md */, + FF14587D1CBE6D37004A5A0B /* Podfile */, + FF14587E1CBE6D37004A5A0B /* LICENSE */, + ); + name = "Podspec Metadata"; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -369,6 +370,7 @@ buildActionMask = 2147483647; files = ( 931A1008192A9CDD00D3CC11 /* InfoPlist.strings in Resources */, + FFBC2B371CBBE10300B0379E /* anim-reader.gif in Resources */, 931A103E192AA3DB00D3CC11 /* test-image.jpg in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -468,7 +470,6 @@ 744DA846194F3A76002CD6E9 /* UIImage+Util.m in Sources */, 931A1020192A9DD500D3CC11 /* WPNoResultsView.m in Sources */, 931A1026192A9E0B00D3CC11 /* WPNUXUtility.m in Sources */, - 9309B533192F9C2000B69F69 /* WPAnimatedImageResponseSerializer.m in Sources */, 931A1035192AA03600D3CC11 /* UIColor+Helpers.m in Sources */, 931A1019192A9D6E00D3CC11 /* NSString+XMLExtensions.m in Sources */, 931A101C192A9DA500D3CC11 /* WPImageSource.m in Sources */, @@ -480,7 +481,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 931A103B192AA35B00D3CC11 /* AsyncTestHelper.m in Sources */, 931A1038192AA34300D3CC11 /* WPImageSourceTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/WordPress-iOS-Shared/Core/WPImageSource.m b/WordPress-iOS-Shared/Core/WPImageSource.m index 6a9e92c..5f549d8 100644 --- a/WordPress-iOS-Shared/Core/WPImageSource.m +++ b/WordPress-iOS-Shared/Core/WPImageSource.m @@ -1,16 +1,17 @@ -#import #import "WPImageSource.h" -#import "WPAnimatedImageResponseSerializer.h" - NSString * const WPImageSourceErrorDomain = @"WPImageSourceErrorDomain"; -@implementation WPImageSource { - NSOperationQueue *_downloadingQueue; - NSMutableSet *_urlDownloadsInProgress; - NSMutableDictionary *_successBlocks; - NSMutableDictionary *_failureBlocks; -} +@interface WPImageSource() + +@property (nonatomic, strong) NSURLSession *downloadsSession; +@property (nonatomic, strong) NSMutableSet *urlDownloadsInProgress; +@property (nonatomic, strong) NSMutableDictionary *successBlocks; +@property (nonatomic, strong) NSMutableDictionary *failureBlocks; + +@end + +@implementation WPImageSource + (instancetype)sharedSource { @@ -24,17 +25,19 @@ + (instancetype)sharedSource - (void)dealloc { - [_downloadingQueue cancelAllOperations]; + [_downloadsSession invalidateAndCancel]; } -- (id)init +- (instancetype)init { self = [super init]; if (self) { - _downloadingQueue = [[NSOperationQueue alloc] init]; _urlDownloadsInProgress = [[NSMutableSet alloc] init]; _successBlocks = [[NSMutableDictionary alloc] init]; _failureBlocks = [[NSMutableDictionary alloc] init]; + + NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; + _downloadsSession = [NSURLSession sessionWithConfiguration:configuration]; } return self; } @@ -49,8 +52,8 @@ - (void)downloadImageForURL:(NSURL *)url authToken:(NSString *)authToken withSuc [self addCallbackForURL:url withSuccess:success failure:failure]; - if (![_urlDownloadsInProgress containsObject:url]) { - [_urlDownloadsInProgress addObject:url]; + if (![self.urlDownloadsInProgress containsObject:url]) { + [self.urlDownloadsInProgress addObject:url]; [self startDownloadForURL:url authToken:authToken]; } } @@ -82,33 +85,29 @@ - (void)startDownloadForURL:(NSURL *)url authToken:(NSString *)authToken { [request addValue:[NSString stringWithFormat:@"Bearer %@", token] forHTTPHeaderField:@"Authorization"]; } - AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; - - operation.responseSerializer = [[WPAnimatedImageResponseSerializer alloc] init]; - operation.responseSerializer.acceptableContentTypes - = [operation.responseSerializer.acceptableContentTypes setByAddingObject:@"image/jpg"]; - - [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) - { - UIImage* image = (UIImage*)responseObject; - - if (!image) { - [self downloadSucceededWithNilImageForURL:url response:operation.response]; - return; - } - [self downloadedImage:image forURL:url]; - } failure:^(AFHTTPRequestOperation *operation, NSError *error) - { - [self downloadFailedWithError:error forURL:url]; - }]; - - [_downloadingQueue addOperation:operation]; + NSURLSessionDownloadTask *task = [self.downloadsSession downloadTaskWithRequest:request + completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { + if (error) { + [self downloadFailedWithError:error forURL:url]; + return; + } + NSError *readError; + NSData *data = [NSData dataWithContentsOfURL:location options:NSDataReadingUncached error:&readError]; + UIImage *image = [UIImage imageWithData:data]; + if (!image) { + [self downloadSucceededWithNilImageForURL:url response:response]; + return; + } + + [self downloadedImage:image forURL:url]; + }]; + [task resume]; }); } - (void)downloadedImage:(UIImage *)image forURL:(NSURL *)url { - NSArray *successBlocks = [_successBlocks objectForKey:url]; + NSArray *successBlocks = [self.successBlocks objectForKey:url]; dispatch_async(dispatch_get_main_queue(), ^{ [self removeCallbacksForURL:url]; for (void (^success)(UIImage *) in successBlocks) { @@ -119,7 +118,7 @@ - (void)downloadedImage:(UIImage *)image forURL:(NSURL *)url - (void)downloadFailedWithError:(NSError *)error forURL:(NSURL *)url { - NSArray *failureBlocks = [_failureBlocks objectForKey:url]; + NSArray *failureBlocks = [self.failureBlocks objectForKey:url]; dispatch_async(dispatch_get_main_queue(), ^{ [self removeCallbacksForURL:url]; for (void (^failure)(NSError *) in failureBlocks) { @@ -128,9 +127,12 @@ - (void)downloadFailedWithError:(NSError *)error forURL:(NSURL *)url }); } -- (void)downloadSucceededWithNilImageForURL:(NSURL *)url response:(NSHTTPURLResponse *)response +- (void)downloadSucceededWithNilImageForURL:(NSURL *)url response:(NSURLResponse *)response { - DDLogError(@"WPImageSource download completed sucessfully but the image was nil. Headers: %@", [response allHeaderFields]); + if ([response isKindOfClass:[NSHTTPURLResponse class]]){ + NSHTTPURLResponse *httpURLResponse = (NSHTTPURLResponse *)response; + DDLogError(@"WPImageSource download completed sucessfully but the image was nil. Headers: %@", [httpURLResponse allHeaderFields]); + } NSString *description = [NSString stringWithFormat:@"A download request ended successfully but the image was nil. URL: %@", [url absoluteString]]; NSError *error = [NSError errorWithDomain:WPImageSourceErrorDomain code:WPImageSourceErrorNilImage @@ -143,31 +145,31 @@ - (void)downloadSucceededWithNilImageForURL:(NSURL *)url response:(NSHTTPURLResp - (void)addCallbackForURL:(NSURL *)url withSuccess:(void (^)(UIImage *))success failure:(void (^)(NSError *))failure { if (success) { - NSArray *successBlocks = [_successBlocks objectForKey:url]; + NSArray *successBlocks = [self.successBlocks objectForKey:url]; if (!successBlocks) { successBlocks = @[[success copy]]; } else { successBlocks = [successBlocks arrayByAddingObject:[success copy]]; } - [_successBlocks setObject:successBlocks forKey:url]; + [self.successBlocks setObject:successBlocks forKey:url]; } if (failure) { - NSArray *failureBlocks = [_failureBlocks objectForKey:url]; + NSArray *failureBlocks = [self.failureBlocks objectForKey:url]; if (!failureBlocks) { failureBlocks = @[[failure copy]]; } else { failureBlocks = [failureBlocks arrayByAddingObject:[failure copy]]; } - [_failureBlocks setObject:failureBlocks forKey:url]; + [self.failureBlocks setObject:failureBlocks forKey:url]; } } - (void)removeCallbacksForURL:(NSURL *)url { - [_successBlocks removeObjectForKey:url]; - [_failureBlocks removeObjectForKey:url]; - [_urlDownloadsInProgress removeObject:url]; + [self.successBlocks removeObjectForKey:url]; + [self.failureBlocks removeObjectForKey:url]; + [self.urlDownloadsInProgress removeObject:url]; } @end diff --git a/WordPress-iOS-Shared/Private/WPAnimatedImageResponseSerializer.h b/WordPress-iOS-Shared/Private/WPAnimatedImageResponseSerializer.h deleted file mode 100644 index eb5ca46..0000000 --- a/WordPress-iOS-Shared/Private/WPAnimatedImageResponseSerializer.h +++ /dev/null @@ -1,10 +0,0 @@ -#import - -/** - * @brief A custom response serializer to handle GIF animations. - * @details The default serializer for AFNetworking does not contemplate animated images. This - * class is a good replacement. Most of its behaviour is inherited from - * AFImageResponseSerializer. - */ -@interface WPAnimatedImageResponseSerializer : AFImageResponseSerializer -@end diff --git a/WordPress-iOS-Shared/Private/WPAnimatedImageResponseSerializer.m b/WordPress-iOS-Shared/Private/WPAnimatedImageResponseSerializer.m deleted file mode 100644 index 4ed2a6e..0000000 --- a/WordPress-iOS-Shared/Private/WPAnimatedImageResponseSerializer.m +++ /dev/null @@ -1,43 +0,0 @@ -#import "WPAnimatedImageResponseSerializer.h" - -@implementation WPAnimatedImageResponseSerializer - -#pragma mark - AFImageResponseSerializer - -/** - * @brief Override to handle GIFs. - * @details Error handling and other image formats are left for the superclass to handle. - * - * @param response The request response. - * @param data The image data if all went well. - * @param error Request errors. - * - * @returns The image. - */ -- (id)responseObjectForResponse:(NSURLResponse *)response - data:(NSData *)data - error:(NSError *__autoreleasing *)error -{ - UIImage* image = nil; - - static NSString* kGifMimeType = @"image/gif"; - - // if the image is not a GIF - BOOL mustBeHandledBySuperclass = ![response.MIMEType isEqualToString:kGifMimeType]; - if (!mustBeHandledBySuperclass) { - mustBeHandledBySuperclass = ![self validateResponse:(NSHTTPURLResponse*)response data:data error:error]; - } - - if (mustBeHandledBySuperclass) { - image = [super responseObjectForResponse:response - data:data - error:error]; - } else { - image = [[UIImage alloc] initWithData:data - scale:self.imageScale]; - } - - return image; -} - -@end diff --git a/WordPress-iOS-SharedTests/AsyncTestHelper.h b/WordPress-iOS-SharedTests/AsyncTestHelper.h deleted file mode 100644 index d654d1d..0000000 --- a/WordPress-iOS-SharedTests/AsyncTestHelper.h +++ /dev/null @@ -1,45 +0,0 @@ -#import -#import - -extern dispatch_semaphore_t ATHSemaphore; -extern const NSTimeInterval AsyncTestCaseDefaultTimeout; - -#define ATHStart() do {\ - ATHSemaphore = dispatch_semaphore_create(0);\ -} while (0) - -#define ATHNotify() do {\ - dispatch_semaphore_signal(ATHSemaphore);\ -} while (0) - -#define ATHWait() do {\ - BOOL timedOut;\ - NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:AsyncTestCaseDefaultTimeout];\ - long lockStatus = 0;\ - while ((lockStatus = dispatch_semaphore_wait(ATHSemaphore, DISPATCH_TIME_NOW)) && [timeoutDate compare:[NSDate date]] == NSOrderedDescending)\ - [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode\ - beforeDate:[NSDate dateWithTimeIntervalSinceNow:AsyncTestCaseDefaultTimeout]];\ - timedOut = (lockStatus != 0);\ - XCTAssertFalse(timedOut, @"Lock timed out");\ -} while (0) - -#define ATHNeverCalled(timeout) do {\ - BOOL timedOut;\ - NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeout];\ - long lockStatus = 0;\ - while ((lockStatus = dispatch_semaphore_wait(ATHSemaphore, DISPATCH_TIME_NOW)) && [timeoutDate compare:[NSDate date]] == NSOrderedDescending)\ - [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode\ - beforeDate:[NSDate dateWithTimeIntervalSinceNow:timeout]];\ - timedOut = (lockStatus != 0);\ - XCTAssertTrue(timedOut, @"Lock timed out");\ -} while (0) - -#define ATHEnd() do {\ - ATHWait(); \ - ATHSemaphore = nil;\ -} while (0) - -#define ATHEndNeverCalled(timeout) do {\ - ATHNeverCalled(timeout); \ - ATHSemaphore = nil;\ -} while (0) \ No newline at end of file diff --git a/WordPress-iOS-SharedTests/AsyncTestHelper.m b/WordPress-iOS-SharedTests/AsyncTestHelper.m deleted file mode 100644 index 183a06d..0000000 --- a/WordPress-iOS-SharedTests/AsyncTestHelper.m +++ /dev/null @@ -1,4 +0,0 @@ -#import "AsyncTestHelper.h" - -dispatch_semaphore_t ATHSemaphore; -const NSTimeInterval AsyncTestCaseDefaultTimeout = 10; diff --git a/WordPress-iOS-SharedTests/WPImageSourceTest.m b/WordPress-iOS-SharedTests/WPImageSourceTest.m index 5861192..19527da 100644 --- a/WordPress-iOS-SharedTests/WPImageSourceTest.m +++ b/WordPress-iOS-SharedTests/WPImageSourceTest.m @@ -1,6 +1,6 @@ #import +#import #import -#import "AsyncTestHelper.h" #import "WPImageSource.h" @@ -31,21 +31,22 @@ - (void)testSendTokensToWordPressDotCom lastAuthHeader = [request valueForHTTPHeaderField:@"Authorization"]; return YES; } withStubResponse:^OHHTTPStubsResponse *(NSURLRequest *request) { - return [OHHTTPStubsResponse responseWithFileAtPath:OHPathForFileInBundle(@"test-image.jpg", nil) statusCode:200 headers:@{@"Content-Type" : @"image/jpeg"}]; + return [OHHTTPStubsResponse responseWithFileAtPath:OHPathForFileInBundle(@"test-image.jpg", [NSBundle bundleForClass:[self class]]) statusCode:200 headers:@{@"Content-Type" : @"image/jpeg"}]; }]; WPImageSource *source = [WPImageSource sharedSource]; - ATHStart(); + XCTestExpectation *expectation = [self expectationWithDescription:@"Download image with token"]; + [source downloadImageForURL:url authToken:@"TOKEN" withSuccess:^(UIImage *image) { - ATHNotify(); + [expectation fulfill]; } failure:^(NSError *error) { + [expectation fulfill]; XCTFail(); - ATHNotify(); }]; - ATHEnd(); + [self waitForExpectationsWithTimeout:5.0 handler:nil]; XCTAssertEqualObjects(lastAuthHeader, @"Bearer TOKEN"); } @@ -59,21 +60,23 @@ - (void)testDontSendTokensOutsideWordPressDotCom lastAuthHeader = [request valueForHTTPHeaderField:@"Authorization"]; return YES; } withStubResponse:^OHHTTPStubsResponse *(NSURLRequest *request) { - return [OHHTTPStubsResponse responseWithFileAtPath:OHPathForFileInBundle(@"test-image.jpg", nil) statusCode:200 headers:@{@"Content-Type" : @"image/jpeg"}]; + return [OHHTTPStubsResponse responseWithFileAtPath:OHPathForFileInBundle(@"test-image.jpg", [NSBundle bundleForClass:[self class]]) statusCode:200 headers:@{@"Content-Type" : @"image/jpeg"}]; }]; WPImageSource *source = [WPImageSource sharedSource]; - ATHStart(); + XCTestExpectation *expectation = [self expectationWithDescription:@"Download image without token"]; [source downloadImageForURL:url authToken:@"TOKEN" withSuccess:^(UIImage *image) { - ATHNotify(); + [expectation fulfill]; } failure:^(NSError *error) { + [expectation fulfill]; XCTFail(); - ATHNotify(); }]; - ATHEnd(); + + [self waitForExpectationsWithTimeout:5.0 handler: nil]; + XCTAssertNil(lastAuthHeader); } @@ -87,41 +90,69 @@ - (void)testImagesArentDownloadedTwice return [[request.URL absoluteString] isEqualToString:requestUrl]; } withStubResponse:^OHHTTPStubsResponse *(NSURLRequest *request) { downloadCount++; - return [OHHTTPStubsResponse responseWithFileAtPath:OHPathForFileInBundle(@"test-image.jpg", nil) statusCode:200 headers:@{@"Content-Type" : @"image/jpeg"}]; + return [OHHTTPStubsResponse responseWithFileAtPath:OHPathForFileInBundle(@"test-image.jpg", [NSBundle bundleForClass:[self class]]) statusCode:200 headers:@{@"Content-Type" : @"image/jpeg"}]; }]; WPImageSource *source = [WPImageSource sharedSource]; - ATHStart(); + XCTestExpectation *originalDownloadExpectation = [self expectationWithDescription:@"Start 1st download"]; [source downloadImageForURL:url withSuccess:^(UIImage *image) { - ATHNotify(); + [originalDownloadExpectation fulfill]; } failure:^(NSError *error) { + [originalDownloadExpectation fulfill]; XCTFail(); - ATHNotify(); }]; + + XCTestExpectation *duplicateDownloadExpectation = [self expectationWithDescription:@"Start 1st download"]; [source downloadImageForURL:url withSuccess:^(UIImage *image) { - ATHNotify(); + [duplicateDownloadExpectation fulfill]; } failure:^(NSError *error) { + [duplicateDownloadExpectation fulfill]; XCTFail(); - ATHNotify(); }]; - ATHWait(); - ATHEnd(); + [self waitForExpectationsWithTimeout:5.0 handler: nil]; XCTAssertEqual(downloadCount, 1, @"it should download the image once"); - ATHStart(); + XCTestExpectation *anotherDownloadExpectation = [self expectationWithDescription:@"Start 1st download"]; [source downloadImageForURL:url withSuccess:^(UIImage *image) { - ATHNotify(); + [anotherDownloadExpectation fulfill]; } failure:^(NSError *error) { + [anotherDownloadExpectation fulfill]; XCTFail(); - ATHNotify(); }]; - ATHEnd(); + + [self waitForExpectationsWithTimeout:5.0 handler: nil]; XCTAssertEqual(downloadCount, 2, @"it should download the image"); } +- (void)testDownloadOfAnimatedGif +{ + NSString *requestUrl = @"http://test.blog/images/anim-reader.gif"; + NSURL *url = [NSURL URLWithString:requestUrl]; + [OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) { + return YES; + } withStubResponse:^OHHTTPStubsResponse *(NSURLRequest *request) { + return [OHHTTPStubsResponse responseWithFileAtPath:OHPathForFileInBundle(@"anim-reader.gif", [NSBundle bundleForClass:[self class]]) statusCode:200 headers:@{@"Content-Type" : @"image/gif"}]; + }]; + + WPImageSource *source = [WPImageSource sharedSource]; + + XCTestExpectation *expectation = [self expectationWithDescription:@"Download image without token"]; + [source downloadImageForURL:url + authToken:@"TOKEN" + withSuccess:^(UIImage *image) { + [expectation fulfill]; + } failure:^(NSError *error) { + [expectation fulfill]; + XCTFail(); + }]; + + [self waitForExpectationsWithTimeout:5.0 handler: nil]; + +} + @end diff --git a/WordPress-iOS-SharedTests/anim-reader.gif b/WordPress-iOS-SharedTests/anim-reader.gif new file mode 100644 index 0000000..9e0b181 Binary files /dev/null and b/WordPress-iOS-SharedTests/anim-reader.gif differ