Objc-C:RACObserve快速更改值(RACSignal for AFHTTPRequestOperation)

问题描述:

我正在使用反应可可从服务器创建下载文件。我有一个DownloadMapFileOperation.m文件具有progress属性(progress value,currentBytes,totalBytes)。它非常迅速改变我的下一个RACSignal方法和漂浮的进展(这是unnecesarry,但Objc-C:RACObserve快速更改值(RACSignal for AFHTTPRequestOperation)

@property (nonatomic, strong, readwrite) NSMutableDictionary *progressDictionary; 
@property (nonatomic, assign, readwrite) float progress; 

RACSignal创建方法

- (RACSignal *)signalForDownloadMap:(Place *)place 
{ 
    return [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { 
     NSString *mapUrlString = [NSString stringWithFormat:@"http://myurl/%@", place.mapFileName]; 
     NSURL *url = [NSURL URLWithString:mapUrlString]; 
     NSURLRequest *request = [NSURLRequest requestWithURL:url]; 

     _downloadFileOperation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; 
     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 

     NSString *documentsDirectory = [paths objectAtIndex:0]; 

     NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:[url lastPathComponent]]; 

     [_downloadFileOperation setOutputStream:[NSOutputStream outputStreamToFileAtPath:fullPath append:NO]]; 

     [_downloadFileOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation , id response) 
     { 
      NSLog(@"Downloaded via compl block"); 
      [subscriber sendNext:nil]; 
      [subscriber sendCompleted]; 

     } failure:^(AFHTTPRequestOperation *operation, NSError *error) 
     { 
      [subscriber sendError:error]; 
     }]; 

     @weakify(self) 
     self.progressDictionary = [[NSMutableDictionary alloc] init]; 
     self.progressDictionary[@"progress"] = @(0); 
     self.progressDictionary[@"current"] = @(0); 
     self.progressDictionary[@"total"] = @(0); 
     self.progress = @(0); 

     [_downloadFileOperation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) 
     { 
      @strongify(self) 
      self.progressDictionary[@"current"] = @(totalBytesRead); 
      self.progressDictionary[@"total"] = @(totalBytesExpectedToRead); 
      self.progressDictionary[@"progress"] = @((float)totalBytesRead/(float)totalBytesExpectedToRead); 
      self.progress = @((float)totalBytesRead/(float)totalBytesExpectedToRead); 
      self.progress = @((float)totalBytesRead/(float)totalBytesExpectedToRead); 
     }]; 

     [_downloadFileOperation start]; 
     return nil; 
    }] filter:^BOOL(id value) { 
     return !(.mapFileName == nil); 
    }] 
     deliverOn:[RACScheduler mainThreadScheduler] 
    ]; 
} 

我只是想通过RACObserve在我的ViewController展现在我看来进展

[[[DownloadMapFileOperation sharedInstance] signalForDownloadMap:self.place] 
    subscribeNext:^(AFHTTPRequestOperation *operation) { 
     NSString *alertMessage = @"Download complete"; 
     [[[UIAlertView alloc] initWithTitle:@"Complete" message:alertMessage delegate:self cancelButtonTitle:@"Close" otherButtonTitles: nil] show]; 
     downloadMapView.progressLabel.text = @"Download Complete"; 
    }]; 

    [[[DownloadMapFileOperation sharedInstance] signalForDownloadMap:self.place] subscribeError:^(NSError *error) { 
     [[[UIAlertView alloc] initWithTitle:@"Error" message:[error localizedDescription] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil] show]; 
    }]; 

    RAC(downloadMapView, progressView.progress) = [RACObserve([DownloadMapFileOperation sharedInstance], progress) 
                map:^id(id value) { 
                 return value; 
                }]; 

    RAC(downloadMapView, progressLabel.text) = [RACObserve([DownloadMapFileOperation sharedInstance], progressDictionary) 
                map:^id(NSDictionary *value) { 
                 return [value[@"progress"] isEqual: @(1)] ? @"Download Complete" : [NSString stringWithFormat:@"Downloaded %@ of %@", value[@"current"], value[@"total"]]; 
                }]; 

但是我的进度视图有时会从60%跳到50%(或45-35等),NSLog(@"Downloaded via compl block");显示进度达到100%之前(有时达到并从约70%再次开始)。 如果我(在第二RACObserve等)使用progressDictionary - 这是行不通的(显示为0的进步和0下载0)

EDITED

我也试着在我DownloadMapFileOperation添加方法.m暂停,恢复,取消下载操作的文件。

- (RACSignal *)signalForPauseDownloadMap 
{ 
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { 
     [_downloadFileOperation pause]; 
     [subscriber sendNext:nil]; 
     [subscriber sendCompleted]; 
     return nil; 
    }]; 
} 

- (RACSignal *)signalForResumeDownloadMap 
{ 
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { 
     [_downloadFileOperation resume]; 
     [subscriber sendNext:nil]; 
     [subscriber sendCompleted]; 
     return nil; 
    }]; 
} 

- (RACSignal *)signalForCancelDownloadMap 
{ 
    return [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { 
     [_downloadFileOperation cancel]; 
     [subscriber sendNext:nil]; 
     [subscriber sendCompleted]; 
     return nil; 
    }] filter:^BOOL(id value) { 
     return (_downloadFileOperation); 
    }]; 
} 

但是:我的下载文件操作没有停止。当我在我的VC中使用

[[_downloadMapFileOperation signalForPauseDownloadMap] 
    subscribeNext:^(id x) { 
     [downloadMapView setTitleForStartDownloadButton:@"Resume download"]; 
     _currentDownloadState = kHTDownloadStatePaused; 
    }]; 

我的进度值工作正常(不会从值跳转到值)。请帮助我。谢谢。

对于您关于跳转下载进度的原始问题,问题是您要创建两个信号副本的订阅,这导致了两次下载。即,该位的代码:

[[[DownloadMapFileOperation sharedInstance] signalForDownloadMap:self.place] 
subscribeNext:^(AFHTTPRequestOperation *operation) { 
    NSString *alertMessage = @"Download complete"; 
    [[[UIAlertView alloc] initWithTitle:@"Complete" message:alertMessage delegate:self cancelButtonTitle:@"Close" otherButtonTitles: nil] show]; 
    downloadMapView.progressLabel.text = @"Download Complete"; 
}]; 

[[[DownloadMapFileOperation sharedInstance] signalForDownloadMap:self.place] subscribeError:^(NSError *error) { 
    [[[UIAlertView alloc] initWithTitle:@"Error" message:[error localizedDescription] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil] show]; 
}]; 

每个subscribeNext/subscribeError /等。会创建一个新的订阅,并开始下载。你想用于订阅如下:

[[[DownloadMapFileOperation sharedInstance] signalForDownloadMap:self.place] 
subscribeNext:^(AFHTTPRequestOperation *operation) { 
    NSString *alertMessage = @"Download complete"; 
    [[[UIAlertView alloc] initWithTitle:@"Complete" message:alertMessage delegate:self cancelButtonTitle:@"Close" otherButtonTitles: nil] show]; 
    downloadMapView.progressLabel.text = @"Download Complete"; 
} error:^(NSError *error) { 
    [[[UIAlertView alloc] initWithTitle:@"Error" message:[error localizedDescription] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil] show]; 
}]; 

对于暂停和恢复,我不认为创建更多的信号是有道理的。如果您确实可以访问下载文件操作,则直接在它上面调用暂停/恢复。原始订阅将继续有效,并应根据创建的信号内的行为暂停/恢复更新。

至于取消,你真正想做的是使用一次性。在拨打[RACSignal createSignal:]时,您不想返回nil。相反,请设置一次性用品,以便在丢弃一次性用品时取消下载。

编辑

理想情况下,你想通过信号发送的进度。在setDownloadProgressBlock你反而会:

NSMutableDictionary *progressDictionary = [[NSMutableDictionary alloc] init]; 
progressDictionary[@"current"] = @(totalBytesRead); 
progressDictionary[@"total"] = @(totalBytesExpectedToRead); 
progressDictionary[@"progress"] = @((float)totalBytesRead/(float)totalBytesExpectedToRead); 
[subscriber sendNext:[progressDictionary copy]]; 

然后,您将能够读取progressDictionary当您订阅,就像这样:

[[[DownloadMapFileOperation sharedInstance] signalForDownloadMap:self.place] 
subscribeNext:^(NSDictionary *progressDictionary) { 
    // Do stuff with dictionary here, like update UI with progress 
} error:^(NSError *error) { 
    // Error related stuff 
} completed:^{ 
    // Completed stuff 
}]; 

注意:你不应该不经过sendNext发送零好理由。完成逻辑只能在完成块中完成。

+0

谢谢你的回答。但是,你能解释一下如何处理信号。我已添加return [[RACDisposable disposableWithBlock:^ {_downloadFileOperation cancel]; }];'而不是'return nil'。现在我必须按钮:1订阅信号'[_signal订阅...',第二个应该取消,但是我不能使用'dispose'没有'subscribeNext/error'。第二个问题是:为什么我无法观察字典值(** progressDictionary **)。如果我观察'浮动'属性(进度) - 它的工作原理。如果我使用'progressDictionary [@“progress”]' - 它不起作用。 –

+0

如果你使用的是按钮,你可能想使用'RACCommand'进行研究。我不确定'progressDictionary'可能会出现什么问题,但理想情况下,您不想使用类似的东西。不要在'self'上存储属性,只需让你的信号发出进度信息即可。这更像是“RAC”做事的方式。 – Simon

+0

谢谢你帮助我。但我是RAC的新成员,所以我想学习一些很好的做法。你能否订阅我一些关于热点的内容来“发布进度信息”。如何从块'setDownloadProgressBlock:^(NSUInteger bytesRead,long long totalBytesRead,long long totalBytesExpectedToRead)'获得进度信息''。第二个:我使用按钮的委托模式(在视图中创建,查看委托给控制器的动作)。我如何在那里使用'RACCommand'。 –