CustomImageView updates :

-> The MediaLoader is not not anymore cancelled when an Image URL is set. The media downloaded is done in background

-> check if there is a pending download to the image URL before starting a new one.
The medias could have been downloaded several times with the UITableViewCell reuse management or when the image was zoomed in full screen.
The MediaManager warns by now when the media download is ended.
This commit is contained in:
ylecollen 2015-01-07 17:26:37 +01:00
parent 10ea385d6b
commit 9ec7818640
3 changed files with 205 additions and 80 deletions

View file

@ -24,16 +24,21 @@ extern NSString *const kMediaManagerProgressStringKey;
extern NSString *const kMediaManagerProgressRemaingTimeKey; extern NSString *const kMediaManagerProgressRemaingTimeKey;
extern NSString *const kMediaManagerProgressDownloadRateKey; extern NSString *const kMediaManagerProgressDownloadRateKey;
// provide the download progress // provide the download/upload progress
// object: URL // object: URL
// userInfo: kMediaManagerProgressRateKey : progress value nested in a NSNumber (range 0->1) // userInfo: kMediaManagerProgressRateKey : progress value nested in a NSNumber (range 0->1)
// : kMediaManagerProgressStringKey : progress string XXX KB / XXX MB" // : kMediaManagerProgressStringKey : progress string XXX KB / XXX MB" (optional)
// : kMediaManagerProgressRemaingTimeKey : remaining time string "XX s left" // : kMediaManagerProgressRemaingTimeKey : remaining time string "XX s left" (optional)
// : kMediaManagerProgressDownloadRateKey : string like XX MB/s // : kMediaManagerProgressDownloadRateKey : string like XX MB/s (optional)
extern NSString *const kMediaDownloadProgressNotification; extern NSString *const kMediaDownloadProgressNotification;
extern NSString *const kMediaUploadProgressNotification; extern NSString *const kMediaUploadProgressNotification;
// notify when a media download is finished
// object: URL
extern NSString *const kMediaDownloadDidFinishNotification;
extern NSString *const kMediaDownloadDidFailNotification;
// The callback blocks // The callback blocks
typedef void (^blockMediaManager_onImageReady)(UIImage *image); typedef void (^blockMediaManager_onImageReady)(UIImage *image);
typedef void (^blockMediaManager_onMediaReady)(NSString *cacheFilePath); typedef void (^blockMediaManager_onMediaReady)(NSString *cacheFilePath);
@ -45,6 +50,10 @@ typedef void (^blockMediaManager_onError)(NSError *error);
+ (UIImage *)resize:(UIImage *)image toFitInSize:(CGSize)size; + (UIImage *)resize:(UIImage *)image toFitInSize:(CGSize)size;
// get a picture from the local cache
// do not start any remote requests
+ (UIImage*)loadCachePicture:(NSString*)pictureURL;
// Load a picture from the local cache or download it if it is not available yet. // Load a picture from the local cache or download it if it is not available yet.
// In this second case a mediaLoader reference is returned in order to let the user cancel this action. // In this second case a mediaLoader reference is returned in order to let the user cancel this action.
+ (id)loadPicture:(NSString *)pictureURL + (id)loadPicture:(NSString *)pictureURL
@ -56,6 +65,14 @@ typedef void (^blockMediaManager_onError)(NSError *error);
mimeType:(NSString *)mimeType mimeType:(NSString *)mimeType
success:(blockMediaManager_onMediaReady)success success:(blockMediaManager_onMediaReady)success
failure:(blockMediaManager_onError)failure; failure:(blockMediaManager_onError)failure;
// try to find out a media loder from a media URL
+ (id)mediaLoaderForURL:(NSString*)url;
// same dictionary as the kMediaDownloadProgressNotification one
+ (NSDictionary*)downloadStatsDict:(id)mediaLoader;
// cancel a media loader
+ (void)cancel:(id)mediaLoader; + (void)cancel:(id)mediaLoader;
+ (NSString *)cacheMediaData:(NSData *)mediaData forURL:(NSString *)mediaURL mimeType:(NSString *)mimeType; + (NSString *)cacheMediaData:(NSData *)mediaData forURL:(NSString *)mediaURL mimeType:(NSString *)mimeType;

View file

@ -22,6 +22,9 @@ NSString *const kMediaManagerPrefixForDummyURL = @"dummyUrl-";
NSString *const kMediaDownloadProgressNotification = @"kMediaDownloadProgressNotification"; NSString *const kMediaDownloadProgressNotification = @"kMediaDownloadProgressNotification";
NSString *const kMediaUploadProgressNotification = @"kMediaUploadProgressNotification"; NSString *const kMediaUploadProgressNotification = @"kMediaUploadProgressNotification";
NSString *const kMediaDownloadDidFinishNotification = @"kMediaDownloadDidFinishNotification";
NSString *const kMediaDownloadDidFailNotification = @"kMediaDownloadDidFailNotification";
NSString *const kMediaManagerProgressRateKey = @"kMediaManagerProgressRateKey"; NSString *const kMediaManagerProgressRateKey = @"kMediaManagerProgressRateKey";
NSString *const kMediaManagerProgressStringKey = @"kMediaManagerProgressStringKey"; NSString *const kMediaManagerProgressStringKey = @"kMediaManagerProgressStringKey";
NSString *const kMediaManagerProgressRemaingTimeKey = @"kMediaManagerProgressRemaingTimeKey"; NSString *const kMediaManagerProgressRemaingTimeKey = @"kMediaManagerProgressRemaingTimeKey";
@ -49,15 +52,47 @@ static MediaManager *sharedMediaManager = nil;
CFAbsoluteTime downloadStartTime; CFAbsoluteTime downloadStartTime;
CFAbsoluteTime lastProgressEventTimeStamp; CFAbsoluteTime lastProgressEventTimeStamp;
NSTimer* progressCheckTimer; NSTimer* progressCheckTimer;
// keep to a copy of the upload dict
NSMutableDictionary* uploadDict;
} }
+ (MediaLoader*)mediaLoaderForURL:(NSString*)url;
@property (strong, nonatomic) NSMutableDictionary* downloadStatsDict;
@end @end
#pragma mark - MediaLoader #pragma mark - MediaLoader
@implementation MediaLoader @implementation MediaLoader
@synthesize downloadStatsDict;
// find a MediaLoader
static NSMutableDictionary* pendingMediaLoadersByURL = nil;
+ (MediaLoader*)mediaLoaderForURL:(NSString*)url {
MediaLoader* res = nil;
if (pendingMediaLoadersByURL && url) {
res = [pendingMediaLoadersByURL valueForKey:url];
}
return res;
}
+ (void) setMediaLoader:(MediaLoader*)mediaLoader forURL:(NSString*)url {
if (!pendingMediaLoadersByURL) {
pendingMediaLoadersByURL = [[NSMutableDictionary alloc] init];
}
// sanity check
if (mediaLoader && url) {
[pendingMediaLoadersByURL setValue:mediaLoader forKey:url];
}
}
+ (void) removeMediaLoaderWithUrl:(NSString*)url {
if (url) {
[pendingMediaLoadersByURL removeObjectForKey:url];
}
}
- (NSString*)validateContentURL:(NSString*)contentURL { - (NSString*)validateContentURL:(NSString*)contentURL {
// Detect matrix content url // Detect matrix content url
@ -70,27 +105,37 @@ static MediaManager *sharedMediaManager = nil;
return contentURL; return contentURL;
} }
- (void)downloadPicture:(NSString*)pictureURL - (void)downloadPicture:(NSString*)pictureURL
success:(blockMediaManager_onImageReady)success success:(blockMediaManager_onImageReady)success
failure:(blockMediaManager_onError)failure { failure:(blockMediaManager_onError)failure {
[MediaLoader setMediaLoader:self forURL:pictureURL];
// Download picture content // Download picture content
[self downloadMedia:pictureURL mimeType:@"image/jpeg" success:^(NSString *cacheFilePath) { [self downloadMedia:pictureURL mimeType:@"image/jpeg" success:^(NSString *cacheFilePath) {
[MediaLoader removeMediaLoaderWithUrl:pictureURL];
if (success) { if (success) {
NSData* imageContent = [NSData dataWithContentsOfFile:cacheFilePath options:(NSDataReadingMappedAlways | NSDataReadingUncached) error:nil]; NSData* imageContent = [NSData dataWithContentsOfFile:cacheFilePath options:(NSDataReadingMappedAlways | NSDataReadingUncached) error:nil];
if (imageContent) { if (imageContent) {
UIImage *image = [UIImage imageWithData:imageContent]; UIImage *image = [UIImage imageWithData:imageContent];
if (image) { if (image) {
success(image); success(image);
[[NSNotificationCenter defaultCenter] postNotificationName:kMediaDownloadDidFinishNotification object:pictureURL userInfo:nil];
} else { } else {
NSLog(@"ERROR: picture download failed: %@", pictureURL); NSLog(@"ERROR: picture download failed: %@", pictureURL);
if (failure){ if (failure){
[[NSNotificationCenter defaultCenter] postNotificationName:kMediaDownloadDidFailNotification object:pictureURL userInfo:nil];
failure(nil); failure(nil);
} }
} }
} }
} }
} failure:^(NSError *error) { } failure:^(NSError *error) {
[MediaLoader removeMediaLoaderWithUrl:pictureURL];
failure(error); failure(error);
[[NSNotificationCenter defaultCenter] postNotificationName:kMediaDownloadDidFailNotification object:pictureURL userInfo:nil];
}]; }];
} }
@ -107,6 +152,8 @@ static MediaManager *sharedMediaManager = nil;
downloadStartTime = statsStartTime = CFAbsoluteTimeGetCurrent(); downloadStartTime = statsStartTime = CFAbsoluteTimeGetCurrent();
lastProgressEventTimeStamp = -1; lastProgressEventTimeStamp = -1;
[MediaLoader setMediaLoader:self forURL:mediaURL];
// Start downloading // Start downloading
NSURL *url = [NSURL URLWithString:[self validateContentURL:aMediaURL]]; NSURL *url = [NSURL URLWithString:[self validateContentURL:aMediaURL]];
downloadData = [[NSMutableData alloc] init]; downloadData = [[NSMutableData alloc] init];
@ -114,6 +161,7 @@ static MediaManager *sharedMediaManager = nil;
} }
- (void)cancel { - (void)cancel {
[MediaLoader removeMediaLoaderWithUrl:mediaURL];
// Reset blocks // Reset blocks
onMediaReady = nil; onMediaReady = nil;
onError = nil; onError = nil;
@ -138,9 +186,13 @@ static MediaManager *sharedMediaManager = nil;
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(@"ERROR: media download failed: %@, %@", error, mediaURL); NSLog(@"ERROR: media download failed: %@, %@", error, mediaURL);
[MediaLoader removeMediaLoaderWithUrl:mediaURL];
// send the latest known upload info // send the latest known upload info
[self progressCheckTimeout:nil]; [self progressCheckTimeout:nil];
uploadDict = nil; downloadStatsDict = nil;
[[NSNotificationCenter defaultCenter] postNotificationName:kMediaDownloadDidFailNotification object:mediaURL userInfo:nil];
if (onError) { if (onError) {
onError (error); onError (error);
@ -184,15 +236,13 @@ static MediaManager *sharedMediaManager = nil;
statsStartTime = currentTime; statsStartTime = currentTime;
// only one parameter by now // build the user info dictionary
NSMutableDictionary* dict = [[NSMutableDictionary alloc] init]; NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
[dict setValue:[NSNumber numberWithFloat:rate] forKey:kMediaManagerProgressRateKey]; [dict setValue:[NSNumber numberWithFloat:rate] forKey:kMediaManagerProgressRateKey];
NSString* progressString = [NSString stringWithFormat:@"%@ / %@", [NSByteCountFormatter stringFromByteCount:downloadData.length countStyle:NSByteCountFormatterCountStyleFile], [NSByteCountFormatter stringFromByteCount:expectedSize countStyle:NSByteCountFormatterCountStyleFile]]; NSString* progressString = [NSString stringWithFormat:@"%@ / %@", [NSByteCountFormatter stringFromByteCount:downloadData.length countStyle:NSByteCountFormatterCountStyleFile], [NSByteCountFormatter stringFromByteCount:expectedSize countStyle:NSByteCountFormatterCountStyleFile]];
[dict setValue:progressString forKey:kMediaManagerProgressStringKey]; [dict setValue:progressString forKey:kMediaManagerProgressStringKey];
NSMutableString* remaingTimeStr = [[NSMutableString alloc] init]; NSMutableString* remaingTimeStr = [[NSMutableString alloc] init];
if (dataRemainingTime < 1) { if (dataRemainingTime < 1) {
@ -218,7 +268,7 @@ static MediaManager *sharedMediaManager = nil;
NSString* downloadRateStr = [NSString stringWithFormat:@"%@/s", [NSByteCountFormatter stringFromByteCount:meanRate * 1024 countStyle:NSByteCountFormatterCountStyleFile]]; NSString* downloadRateStr = [NSString stringWithFormat:@"%@/s", [NSByteCountFormatter stringFromByteCount:meanRate * 1024 countStyle:NSByteCountFormatterCountStyleFile]];
[dict setValue:downloadRateStr forKey:kMediaManagerProgressDownloadRateKey]; [dict setValue:downloadRateStr forKey:kMediaManagerProgressDownloadRateKey];
uploadDict = dict; downloadStatsDict = dict;
// after 0.1s, resend the progress info // after 0.1s, resend the progress info
// the upload can be stuck // the upload can be stuck
@ -228,8 +278,7 @@ static MediaManager *sharedMediaManager = nil;
// trigger the event only each 0.1s to avoid send to many events // trigger the event only each 0.1s to avoid send to many events
if ((lastProgressEventTimeStamp == -1) || ((currentTime - lastProgressEventTimeStamp) > 0.1)) { if ((lastProgressEventTimeStamp == -1) || ((currentTime - lastProgressEventTimeStamp) > 0.1)) {
lastProgressEventTimeStamp = currentTime; lastProgressEventTimeStamp = currentTime;
[[NSNotificationCenter defaultCenter] postNotificationName:kMediaDownloadProgressNotification object:mediaURL userInfo:downloadStatsDict];
[[NSNotificationCenter defaultCenter] postNotificationName:kMediaDownloadProgressNotification object:mediaURL userInfo:uploadDict];
} }
} }
} }
@ -237,18 +286,19 @@ static MediaManager *sharedMediaManager = nil;
- (IBAction) progressCheckTimeout:(id)sender - (IBAction) progressCheckTimeout:(id)sender
{ {
// remove the bitrate -> can be invalid // remove the bitrate -> can be invalid
[uploadDict removeObjectForKey:kMediaManagerProgressDownloadRateKey]; [downloadStatsDict removeObjectForKey:kMediaManagerProgressDownloadRateKey];
[[NSNotificationCenter defaultCenter] postNotificationName:kMediaDownloadProgressNotification object:mediaURL userInfo:uploadDict]; [[NSNotificationCenter defaultCenter] postNotificationName:kMediaDownloadProgressNotification object:mediaURL userInfo:downloadStatsDict];
[progressCheckTimer invalidate]; [progressCheckTimer invalidate];
progressCheckTimer = nil; progressCheckTimer = nil;
} }
- (void)connectionDidFinishLoading:(NSURLConnection *)connection { - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[MediaLoader removeMediaLoaderWithUrl:mediaURL];
// send the latest known upload info // send the latest known upload info
[self progressCheckTimeout:nil]; [self progressCheckTimeout:nil];
uploadDict = nil; downloadStatsDict = nil;
if (downloadData.length) { if (downloadData.length) {
// Cache the downloaded data // Cache the downloaded data
@ -257,11 +307,14 @@ static MediaManager *sharedMediaManager = nil;
if (onMediaReady) { if (onMediaReady) {
onMediaReady(cacheFilePath); onMediaReady(cacheFilePath);
} }
[[NSNotificationCenter defaultCenter] postNotificationName:kMediaDownloadDidFinishNotification object:mediaURL userInfo:nil];
} else { } else {
NSLog(@"ERROR: media download failed: %@", mediaURL); NSLog(@"ERROR: media download failed: %@", mediaURL);
if (onError){ if (onError){
onError(nil); onError(nil);
} }
[[NSNotificationCenter defaultCenter] postNotificationName:kMediaDownloadDidFailNotification object:mediaURL userInfo:nil];
} }
downloadData = nil; downloadData = nil;
@ -375,6 +428,15 @@ static MediaManager *sharedMediaManager = nil;
return ret; return ret;
} }
// try to find out a media loder from a media URL
+ (id)mediaLoaderForURL:(NSString*)url {
return [MediaLoader mediaLoaderForURL:url];
}
+ (NSDictionary*)downloadStatsDict:(id)mediaLoader {
return ((MediaLoader*)mediaLoader).downloadStatsDict;
}
+ (void)cancel:(id)mediaLoader { + (void)cancel:(id)mediaLoader {
[((MediaLoader*)mediaLoader) cancel]; [((MediaLoader*)mediaLoader) cancel];
} }

View file

@ -79,13 +79,13 @@
- (void)dealloc { - (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMediaDownloadProgressNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:kMediaDownloadProgressNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMediaDownloadDidFinishNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMediaDownloadDidFailNotification object:nil];
[self stopActivityIndicator]; [self stopActivityIndicator];
if (imageLoader) { imageLoader = nil;
[MediaManager cancel:imageLoader];
imageLoader = nil;
}
if (loadingView) { if (loadingView) {
[loadingView removeFromSuperview]; [loadingView removeFromSuperview];
loadingView = nil; loadingView = nil;
@ -289,6 +289,8 @@
[super removeFromSuperview]; [super removeFromSuperview];
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMediaDownloadProgressNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:kMediaDownloadProgressNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMediaDownloadDidFinishNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMediaDownloadDidFailNotification object:nil];
if (useFullScreen) { if (useFullScreen) {
[UIApplication sharedApplication].statusBarHidden = NO; [UIApplication sharedApplication].statusBarHidden = NO;
@ -435,13 +437,13 @@
// it could be triggered after a screen rotation, new message ... // it could be triggered after a screen rotation, new message ...
return; return;
} }
// reinit parameters
imageLoader = nil;
downloadingImageURL = nil;
// Cancel media loader in progress (if any) // remove any pending observers
if (imageLoader) { [[NSNotificationCenter defaultCenter] removeObserver:self];
[MediaManager cancel:imageLoader];
imageLoader = nil;
downloadingImageURL = nil;
}
// preview image until the image is loaded // preview image until the image is loaded
self.image = previewImage; self.image = previewImage;
@ -459,21 +461,102 @@
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMediaDownloadProgress:) name:kMediaDownloadProgressNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMediaDownloadProgress:) name:kMediaDownloadProgressNotification object:nil];
imageLoader = [MediaManager loadPicture:downloadingImageURL id loader = [MediaManager mediaLoaderForURL:downloadingImageURL];
success:^(UIImage *anImage) {
downloadingImageURL = nil; // there is no pending request to this URL
[self stopActivityIndicator]; if (!loader) {
self.image = anImage; imageLoader = [MediaManager loadPicture:downloadingImageURL
loadedImageURL = anImageURL; success:^(UIImage *anImage) {
downloadingImageURL = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMediaDownloadProgressNotification object:nil]; [self stopActivityIndicator];
} self.image = anImage;
failure:^(NSError *error) { loadedImageURL = anImageURL;
[self stopActivityIndicator];
downloadingImageURL = nil; [[NSNotificationCenter defaultCenter] removeObserver:self name:kMediaDownloadProgressNotification object:nil];
NSLog(@"Failed to download image (%@): %@", anImageURL, error); }
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMediaDownloadProgressNotification object:nil]; failure:^(NSError *error) {
}]; [self stopActivityIndicator];
downloadingImageURL = nil;
NSLog(@"Failed to download image (%@): %@", anImageURL, error);
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMediaDownloadProgressNotification object:nil];
}];
} else {
// update the progress UI with the current info
[self updateProgressUI:[MediaManager downloadStatsDict:loader]];
// wait that the download is ended
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMediaDownloadEnd:) name:kMediaDownloadDidFinishNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMediaDownloadEnd:) name:kMediaDownloadDidFailNotification object:nil];
}
}
}
- (void)onMediaDownloadEnd:(NSNotification *)notif {
// sanity check
if ([notif.object isKindOfClass:[NSString class]]) {
NSString* url = notif.object;
if ([url isEqualToString:downloadingImageURL]) {
[self stopActivityIndicator];
// update the image
UIImage* image = [MediaManager loadCachePicture:downloadingImageURL];
if (image) {
self.image = image;
}
// updates the statuses
loadedImageURL = downloadingImageURL;
downloadingImageURL = nil;
// remove the observers
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMediaDownloadProgressNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMediaDownloadDidFinishNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMediaDownloadDidFailNotification object:nil];
}
}
}
- (void)updateProgressUI:(NSDictionary*)downloadStatsDict {
NSNumber* progressNumber = [downloadStatsDict valueForKey:kMediaManagerProgressRateKey];
if (progressNumber) {
pieChartView.progress = progressNumber.floatValue;
waitingDownloadSpinner.hidden = YES;
}
if (progressInfoLabel) {
NSString* downloadRate = [downloadStatsDict valueForKey:kMediaManagerProgressDownloadRateKey];
NSString* remaingTime = [downloadStatsDict valueForKey:kMediaManagerProgressRemaingTimeKey];
NSString* progressString = [downloadStatsDict valueForKey:kMediaManagerProgressStringKey];
NSMutableString* text = [[NSMutableString alloc] init];
[text appendString:progressString];
if (remaingTime) {
[text appendFormat:@" (%@)", remaingTime];
}
if (downloadRate) {
[text appendFormat:@"\n %@", downloadRate];
}
progressInfoLabel.text = text;
// on multilines, sizeToFit uses the current width
// so reset it
progressInfoLabel.frame = CGRectZero;
[progressInfoLabel sizeToFit];
//
CGRect progressInfoLabelFrame = progressInfoLabel.frame;
progressInfoLabelFrame.origin.x = self.center.x - (progressInfoLabelFrame.size.width / 2);
progressInfoLabelFrame.origin.y = 10 + loadingView.frame.origin.y + loadingView.frame.size.height;
progressInfoLabel.frame = progressInfoLabelFrame;
} }
} }
@ -483,44 +566,7 @@
NSString* url = notif.object; NSString* url = notif.object;
if ([url isEqualToString:downloadingImageURL]) { if ([url isEqualToString:downloadingImageURL]) {
NSNumber* progressNumber = [notif.userInfo valueForKey:kMediaManagerProgressRateKey]; [self updateProgressUI:notif.userInfo];
if (progressNumber) {
pieChartView.progress = progressNumber.floatValue;
waitingDownloadSpinner.hidden = YES;
}
if (progressInfoLabel) {
NSString* downloadRate = [notif.userInfo valueForKey:kMediaManagerProgressDownloadRateKey];
NSString* remaingTime = [notif.userInfo valueForKey:kMediaManagerProgressRemaingTimeKey];
NSString* progressString = [notif.userInfo valueForKey:kMediaManagerProgressStringKey];
NSMutableString* text = [[NSMutableString alloc] init];
[text appendString:progressString];
if (remaingTime) {
[text appendFormat:@" (%@)", remaingTime];
}
if (downloadRate) {
[text appendFormat:@"\n %@", downloadRate];
}
progressInfoLabel.text = text;
// on multilines, sizeToFit uses the current width
// so reset it
progressInfoLabel.frame = CGRectZero;
[progressInfoLabel sizeToFit];
//
CGRect progressInfoLabelFrame = progressInfoLabel.frame;
progressInfoLabelFrame.origin.x = self.center.x - (progressInfoLabelFrame.size.width / 2);
progressInfoLabelFrame.origin.y = 10 + loadingView.frame.origin.y + loadingView.frame.size.height;
progressInfoLabel.frame = progressInfoLabelFrame;
}
} }
} }
} }