// // RAUploadManager.m // test_autolayout // // Created by Ray on 02/05/2017. // Copyright © 2017 USAI. All rights reserved. // #import #import "RAUploadManager.h" #import "NetworkUtils.h" #import "RAUtils.h" #import "UploadSettingController.h" @implementation RAUploadManager /*! * Called by Reachability whenever status changes. */ - (void) reachabilityChanged:(NSNotification *)note { [self handleReachability:self.reach]; } - (void)handleReachability:(Reachability *)reachability { NetworkStatus netStatus = [reachability currentReachabilityStatus]; if (self.onlyWiFi && netStatus != ReachableViaWiFi) { DebugLog(@"not wifi & stop task"); [self stopAllTasks]; } } - (instancetype)init { if (self = [super init]) { /* Observe the kNetworkReachabilityChangedNotification. When that notification is posted, the method reachabilityChanged will be called. */ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) name:kReachabilityChangedNotification object:nil]; NSString *remoteHostName = @"www.apple.com"; self.reach = [Reachability reachabilityWithHostName:remoteHostName]; [self.reach startNotifier]; [self handleReachability:self.reach]; self.queue_status = QueueStatusDefault; NSDictionary *param = [[NSUserDefaults standardUserDefaults] objectForKey:kUploadSetting]; if (param) { BOOL autoUpload = [[param objectForKey:@"auto_upload"] boolValue]; BOOL autoRmFinish = [[param objectForKey:@"auto_rm_finish"] boolValue]; BOOL autoRmErr = [[param objectForKey:@"auto_rm_error"] boolValue]; BOOL onlyWiFi = [[param objectForKey:@"only_wifi"] boolValue]; int retryCount = [[param objectForKey:@"retry_count"] intValue]; self.autoStart = autoUpload; // self.removeFinish = autoRmFinish; // self.removeError = autoRmErr; self.maxRetry = retryCount; self.onlyWiFi = onlyWiFi; } else { self.autoStart = YES; // self.removeFinish = YES; // self.removeError = NO; self.maxRetry = 5; self.onlyWiFi = NO; } self.newtaskStatus = TaskStatusWait; self.maxThread = 3; // self.autoStart = true; // self.removeError=true; // self.removeFinish = true; self.operation_queue = [NSOperationQueue new]; self.operation_queue.maxConcurrentOperationCount = self.maxThread; [self.operation_queue addObserver:self forKeyPath:@"operationCount" options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) context:@"queueFinished changed"]; //load task 要在监听arr_queue之前 [self loadTasks]; [self addObserver:self forKeyPath:@"arr_queue" options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) context:@"arr_queue changed"]; // self.arr_queue_lock = [NSLock new]; // [self.arr_queue_lock lock]; // [self.arr_queue_lock lock]; // [self.arr_queue_lock unlock]; // [self.arr_queue_lock unlock]; // self.backgroundColor = [UIColor clearColor]; } return self; } -(void) dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self name:kReachabilityChangedNotification object:nil]; [self.operation_queue removeObserver:self forKeyPath:@"operationCount"]; [self.operation_queue removeObserver:self forKeyPath:@"arr_queue"]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if([keyPath isEqualToString:@"operationCount"]) { if([[change objectForKey:NSKeyValueChangeNewKey] intValue]==0) { for(NSMutableDictionary* task in self.arr_queue) { if([task[@"status"] intValue] == TaskStatusError) { self.queue_status = QueueStatusFinishWithError; return; } } self.queue_status = QueueStatusFinish; } } if([keyPath isEqualToString:@"arr_queue"]) { NSArray* newqueue=[change objectForKey:NSKeyValueChangeNewKey]; NSArray* oldqueue=[change objectForKey:NSKeyValueChangeOldKey]; if([newqueue isKindOfClass:[NSNull class]]) newqueue=nil; if([oldqueue isKindOfClass:[NSNull class]]) oldqueue=nil; if(newqueue.count>oldqueue.count) { self.queue_status = QueueStatusAdd; return; } } } //-(void) upload:(NSString*) url //{ // while(self.activeThreadAtIndex // [ insertObjects:tasks atIndexes:indexSet]; } // if (self.delegate && [self.delegate respondsToSelector:@selector(uploadManager:didRemoveTasks:)]) { // [self.delegate uploadManager:self didRemoveTasks:tasks]; // } } -(void) removeTask:(NSMutableDictionary*) task { NSFileManager* fmanager = [NSFileManager new]; // [self.arr_queue addObject:task]; [self stopTask:task]; NSError* error = nil; bool bdel=[fmanager removeItemAtPath:[self filePath:task] error:&error]; if(!bdel) DebugLog(@"file delete failed path:%@",[self filePath:task]); // [self.arr_queue_lock lock]; // DebugLog(@"lock"); // [[self mutableArrayValueForKey:@"arr_queue"] removeObject:task]; // DebugLog(@"unlock"); // [self.arr_queue_lock unlock]; // [self.arr_queue_lock lock]; // [[self mutableArrayValueForKey:@"arr_queue"] removeObject:task]; // [self.arr_queue_lock unlock]; @synchronized(self) { [[self mutableArrayValueForKey:@"arr_queue"] removeObject:task]; } // if (self.delegate && [self.delegate respondsToSelector:@selector(uploadManager:didRemoveTasks:)]) { // [self.delegate uploadManager:self didRemoveTasks:@[task]]; // } } -(NSString*)filePath:(NSMutableDictionary*)task { NSString *path = [RAUtils appCacheDirectory]; path= [path stringByAppendingPathComponent:task[@"path"]]; path= [path stringByAppendingPathComponent:task[@"file"]]; return path; } -(void) saveTasks { NSUserDefaults *defaults =[NSUserDefaults standardUserDefaults]; [defaults setObject:self.arr_queue forKey:@"upload_queue"]; [defaults synchronize]; } -(void) loadTasks { [self stopAllTasks]; self.arr_queue = [NSMutableArray new]; NSMutableArray* arr = [[[NSUserDefaults standardUserDefaults] objectForKey:@"upload_queue"] mutableCopy]; // if(arr==nil) for(NSDictionary* task in arr) { NSMutableDictionary* newtask =[task mutableCopy]; [self.arr_queue addObject:newtask]; if(self.autoStart&&[task[@"status"] intValue]!=TaskStatusError&&[task[@"status"] intValue]!=TaskStatusFinish) [self startTask:newtask]; } // NSDictionary* ddd = arr[0] ; // NSMutableDictionary* eee = [ddd mutableCopy]; // // eee=[NSMutableDictionary dictionaryWithDictionary:ddd]; // if(arr!=nil) // self.arr_queue=arr; // else // self.arr_queue= [[NSMutableArray alloc] init]; // // for(__strong NSMutableDictionary* task in arr) // { // // task=[NSMutableDictionary dictionaryWithDictionary:task]; //// if([task[@"status"] intValue]==TaskStatusStart) //// task[@"status"]=[NSNumber numberWithInteger:TaskStatusWait]; // // NSMutableDictionary *new_task = [task mutableCopy]; // if(self.autoStart&&[task[@"status"] intValue]!=TaskStatusError&&[task[@"status"] intValue]!=TaskStatusFinish) // [self startTask:task]; // } } -(void) stopAllTasks { for(NSMutableDictionary* task in self.arr_queue) { [self stopTask:task]; } } -(void) stopTask:(NSMutableDictionary*) task { if([task[@"status"] intValue]!=TaskStatusStart&&[task[@"status"] intValue]!=TaskStatusWait) { task[@"operation"]=nil; return; // task 已停止,返回 } DebugLog(@"stop task"); RAUploadOperation* operation = task[@"operation"]; [operation cancel]; task[@"operation"]=nil; task[@"status"] = [NSNumber numberWithInt:TaskStatusStop] ; task[@"progress"] = [NSNumber numberWithDouble:0.0]; } -(void) startAllTasks { for(NSMutableDictionary* task in self.arr_queue) [self startTask:task]; } -(void) startTask:(NSMutableDictionary*) task { if (self.onlyWiFi && self.reach.currentReachabilityStatus != ReachableViaWiFi) { return; } /*__block*/ NSMutableDictionary* block_task = task; __weak typeof(self) weakSelf = self; if([task[@"status"] intValue]==TaskStatusStart||[task[@"status"] intValue]==TaskStatusWait) return; // task 已在执行队列,返回 RAUploadOperation* operation = [[RAUploadOperation alloc] initWithTaskinfo:task retry:self.maxRetry]; [operation setCompletionBlock:^{ switch ([block_task[@"status"] intValue]) { case TaskStatusFinish: { // if(weakSelf.removeFinish) // [self removeTask:block_task]; } break; case TaskStatusError: { // if(weakSelf.removeError) // [self removeTask:block_task]; } break; default: break; } }]; task[@"msg"] = nil; task[@"operation"] = operation; task[@"status"] = [NSNumber numberWithInt:self.newtaskStatus] ; [self.operation_queue addOperation:operation]; } //- (void) uploadTask:(NSMutableDictionary*) task url:(NSString*)url{ // //// __weak typeof(self) weakself = self; // // // // //} - (BOOL)canUpload { if (self.onlyWiFi && self.reach.currentReachabilityStatus != ReachableViaWiFi) { return NO; } return YES; } @end