-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathAsyncDownloader.m
153 lines (120 loc) · 4.6 KB
/
AsyncDownloader.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
* Copyright Andy Duplain (c)2014.
*
* See: https://github.com/trojanfoe/RunLoopController
*
* Licensed under the MIT License.
*/
#import "AsyncDownloader.h"
#ifdef LOGGING
#define LOG(fmt, ...) NSLog(fmt, ## __VA_ARGS__)
#else
#define LOG(fmt, ...) /* nothing */
#endif
NSString * const AsyncDownloaderFinishedNotification = @"AsyncDownloaderFinishedNotification";
NSString * const AsyncDownloaderFinishedNotificationSucceededKey = @"AsyncDownloaderFinishedNotificationSucceeded";
NSString * const AsyncDownloaderFinishedNotificationErrorKey = @"AsyncDownloaderFinishedNotificationError";
static NSString * const _asyncDownloaderErrorDomain = @"AsyncDownloaderErrorDomain";
// Private Methods
@interface AsyncDownloader ()
- (void)_sendFinishedNotification;
- (void)_setErrorWithString:(NSString *)message
underlyingError:(NSError *)underlyingError;
@end
@implementation AsyncDownloader
@synthesize cancel = _cancel;
@synthesize url = _url;
@synthesize responseEncoding = _responseEncoding;
@synthesize finished = _finished;
@synthesize error = _error;
- (BOOL)downloadFromURL:(NSURL *)url {
_url = url;
_connection = nil;
_responseData = nil;
_cancel = NO;
_responseEncoding = NSUTF8StringEncoding;
_error = nil;
NSURLRequest *request = [NSURLRequest requestWithURL:url];
if (!request) {
_finished = YES;
[self _setErrorWithString:@"Failed to create NSURLRequest object"
underlyingError:nil];
[self _sendFinishedNotification];
return NO;
}
_connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
if (!_connection) {
_finished = YES;
[self _setErrorWithString:@"Failed to create NSURLConnection object"
underlyingError:nil];
[self _sendFinishedNotification];
return NO;
}
LOG(@"Request to '%@' sent", url);
return YES;
}
#pragma mark - NSURLConnectionDelegate methods
- (void)connection:(NSURLConnection *)connection
didReceiveResponse:(NSURLResponse *)response {
if (_cancel)
return;
NSString *textEncodingName = response.textEncodingName;
LOG(@"Received response from '%@'. Encoding=%@", _url, textEncodingName);
_responseData = [NSMutableData new];
if (textEncodingName) {
CFStringEncoding cfEncoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)textEncodingName);
_responseEncoding = CFStringConvertEncodingToNSStringEncoding(cfEncoding);
} else {
_responseEncoding = NSUTF8StringEncoding;
}
}
- (void)connection:(NSURLConnection *)connection
didReceiveData:(NSData *)data {
if (_cancel)
return;
LOG(@"Received %lu bytes from '%@'", (unsigned long)[data length], _url);
[_responseData appendData:data];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse *)cachedResponse {
return nil; // Not necessary
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
LOG(@"Finished downloading from '%@'", _url);
_finished = YES;
[self _sendFinishedNotification];
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error {
LOG(@"Error downloading from '%@': %@", _url, [error localizedDescription]);
_finished = YES;
[self _setErrorWithString:@"Failed to download"
underlyingError:error];
[self _sendFinishedNotification];
}
- (void)_sendFinishedNotification {
NSAssert(_finished, @"Download didn't finish!");
NSMutableDictionary *userInfo = [NSMutableDictionary new];
if (_error) {
userInfo[AsyncDownloaderFinishedNotificationSucceededKey] = @(NO);
userInfo[AsyncDownloaderFinishedNotificationErrorKey] = _error;
} else {
userInfo[AsyncDownloaderFinishedNotificationSucceededKey] = @(YES);
}
[[NSNotificationCenter defaultCenter] postNotificationName:AsyncDownloaderFinishedNotification
object:self
userInfo:userInfo];
}
- (void)_setErrorWithString:(NSString *)message
underlyingError:(NSError *)underlyingError {
NSMutableDictionary *userInfo = [NSMutableDictionary new];
if (message)
userInfo[NSLocalizedDescriptionKey] = message;
if (underlyingError)
userInfo[NSUnderlyingErrorKey] = underlyingError;
_error = [NSError errorWithDomain:_asyncDownloaderErrorDomain
code:0
userInfo:userInfo];
}
@end