我尝试使用NSURLConnection通过进程回调实现同步下载。 当调用[连接开始]时,没有任何反应 - 委托回调方法不仅仅被调用(我在XCTestCase中对OSX进行测试)。怎么了?
// header
@interface ASDownloadHelper : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate>
{
NSMutableData *_receivedData;
NSUInteger _expectedBytes;
id<ASDownloadHelperListener> _listener;
NSError *_error;
BOOL _finished;
id _finishedSyncObject;
}
- (void) download: (NSString*)url file:(NSString*)file listener:(id<ASDownloadHelperListener>)listener;
@end
// impl
@implementation ASDownloadHelper
// delegate
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[_receivedData setLength:0];
_expectedBytes = [response expectedContentLength];
}
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[_receivedData appendData:data];
int percent = round( _receivedData.length * 100.0 / _expectedBytes );
[_listener onDownloadProgress:_receivedData.length total:_expectedBytes percent:percent];
}
- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
_error = error;
[self setFinished:YES];
}
- (NSCachedURLResponse *) connection:(NSURLConnection*)connection
willCacheResponse:(NSCachedURLResponse*)cachedResponse {
return nil;
}
- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
[self setFinished: YES];
}
- (BOOL) isFinished {
@synchronized(_finishedSyncObject) {
return _finished;
}
}
- (void) setFinished: (BOOL)finished {
@synchronized(_finishedSyncObject) {
_finished = finished;
}
}
// ---
- (void) download: (NSString*)downloadUrl file:(NSString*)file listener:(id<ASDownloadHelperListener>)listener {
_listener = listener;
_finished = NO;
_finishedSyncObject = [[NSObject alloc] init];
_error = nil;
NSURL *url = [NSURL URLWithString:downloadUrl];
NSURLRequest *request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:30];
_receivedData = [[NSMutableData alloc] initWithLength:0];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
[connection start];
// block the thread until downloading finished
while (![self isFinished]) { };
// error?
if (_error != nil) {
@throw _error;
return;
}
// success
[_receivedData writeToFile:file atomically:YES];
_receivedData = nil;
}
@end
答案 0 :(得分:0)
您的等待循环将CPU主线程锁定为100%,使用以下命令修补等待循环:
...
// block the thread until downloading finished
while (![self isFinished])
{
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
};
...
答案 1 :(得分:0)
感谢 quellish 我发现调用队列不应该被阻止,因为回调调用(委托方法)是在调用者线程上下文中完成的。在我的情况下,我在主测试线程中运行它,所以我不得不做解决方法(并在主线程中睡几秒钟让下载完成):
- (void)testDownload
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
// ...
[_downloadHelper download:repositoryUrl file:downloadedFile listener:downloadlistener];
// progress callbacks are invoked in this thread context, so it can't be blocked
// ...
XCTAssertNotNil( ... );
});
// block main test queue until downloading is finished
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
}