我正在将 NSOperation 子类化为后台线程中的 http 帖子。
那些特定的 http 帖子不需要返回任何值。
我想要做的是当我遇到错误或超时时,我希望它在增加延迟(斐波那契)后发送。
到目前为止,我已经这样做了:
NSInternetOperation.h:
#import <Foundation/Foundation.h>
@interface NSInternetOperation : NSOperation
@property (nonatomic) BOOL executing;
@property (nonatomic) BOOL finished;
@property (nonatomic) BOOL completed;
@property (nonatomic) BOOL cancelled;
- (id)initWebServiceName:(NSString*)webServiceName andPerameters:(NSString*)parameters;
- (void)start;
@end
#import "NSInternetOperation.h"
static NSString * const kFinishedKey = @"isFinished";
static NSString * const kExecutingKey = @"isExecuting";
@interface NSInternetOperation ()
@property (strong, nonatomic) NSString *serviceName;
@property (strong, nonatomic) NSString *params;
- (void)completeOperation;
@end
@implementation NSInternetOperation
- (id)initWebServiceName:(NSString*)webServiceName andPerameters:(NSString*)parameters
{
self = [super init];
if (self) {
_serviceName = webServiceName;
_params = parameters;
_executing = NO;
_finished = NO;
_completed = NO;
}
return self;
}
- (BOOL)isExecuting { return self.executing; }
- (BOOL)isFinished { return self.finished; }
- (BOOL)isCompleted { return self.completed; }
- (BOOL)isCancelled { return self.cancelled; }
- (BOOL)isConcurrent { return YES; }
- (void)start
{
if ([self isCancelled]) {
[self willChangeValueForKey:kFinishedKey];
self.finished = YES;
[self didChangeValueForKey:kFinishedKey];
return;
}
// If the operation is not cancelled, begin executing the task
[self willChangeValueForKey:kExecutingKey];
self.executing = YES;
[self didChangeValueForKey:kExecutingKey];
[self main];
}
- (void)main
{
@try {
//
// Here we add our asynchronized code
//
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *completeURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@/%@", kWEB_SERVICE_URL, self.serviceName]];
NSData *body = [self.params dataUsingEncoding:NSUTF8StringEncoding];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:completeURL];
[request setHTTPMethod:@"POST"];
[request setValue:kAPP_PASSWORD_VALUE forHTTPHeaderField:kAPP_PASSWORD_HEADER];
[request setHTTPBody:body];
[request setValue:[NSString stringWithFormat:@"%lu", (unsigned long)body.length] forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
if (__iOS_7_AND_HIGHER)
{
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:[Netroads sharedInstance] delegateQueue:[NSOperationQueue new]];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error)
{
NSLog(@"%@ Error: %@", self.serviceName, error.localizedDescription);
}
else
{
//NSString *responseXML = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//NSLog(@"\n\nResponseXML(%@):\n%@", webServiceName, responseXML);
}
}];
[dataTask resume];
}
else
{
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue new] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (connectionError)
{
NSLog(@"%@ Error: %@", self.serviceName, connectionError.localizedDescription);
}
else
{
//NSString *responseXML = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//NSLog(@"\n\nResponseXML(%@):\n%@", webServiceName, responseXML);
}
}];
}
});
[self completeOperation];
}
@catch (NSException *exception) {
NSLog(@"%s exception.reason: %@", __PRETTY_FUNCTION__, exception.reason);
[self completeOperation];
}
}
- (void)completeOperation
{
[self willChangeValueForKey:kFinishedKey];
[self willChangeValueForKey:kExecutingKey];
self.executing = NO;
self.finished = YES;
[self didChangeValueForKey:kExecutingKey];
[self didChangeValueForKey:kFinishedKey];
}
@end
最佳答案
几个 react :
[self completeOperation]到 NSURLSessionDataTask 的完成块内或 sendAsynchronousRequest .您当前的操作类过早完成(因此不会满足依赖项和您的网络操作队列的预期 maxConcurrentOperationCount )。 - (void)main
{
NSURLRequest *request = [self createRequest]; // maybe move the request creation stuff into its own method
[self tryRequest:request currentDelay:1.0];
}
- (void)tryRequest:(NSURLRequest *)request currentDelay:(NSTimeInterval)delay
{
[NSURLConnection sendAsynchronousRequest:request queue:[self networkOperationCompletionQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
BOOL success = NO;
if (connectionError) {
NSLog(@"%@ Error: %@", self.serviceName, connectionError.localizedDescription);
} else {
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
if (statusCode == 200) {
// parse XML response here; if successful, set `success` to `YES`
}
}
}
if (success) {
[self completeOperation];
} else {
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
NSTimeInterval nextDelay = [self nextDelayFromCurrentDelay:delay];
[self tryRequest:request currentDelay:nextDelay];
});
}
}];
}
dispatch_async在 main 中发出请求到后台队列,因为您已经在使用异步方法(即使您没有使用,您也可能已将此操作添加到后台队列中,无论如何)。 try/catch逻辑,因为与其他语言/平台不同,异常处理不是处理运行时错误的首选方法。通常 Cocoa 中的运行时错误是通过 NSError 处理的.在 Cocoa 中,异常通常仅用于处理程序员错误,而不是处理用户可能遇到的运行时错误。见苹果的讨论Dealing with Errors在使用 Objective-C 编程指南中。 isExecuting和 isFinished getter 方法,如果您只是在它们各自的声明期间为您的属性定义适当的 getter 方法:@property (nonatomic, readwrite, getter=isExecuting) BOOL executing;
@property (nonatomic, readwrite, getter=isFinished) BOOL finished;
setExecuting和 setFinished setter 方法,如果需要,可以为您发送通知,例如:@synthesize finished = _finished;
@synthesize executing = _executing;
- (void)setExecuting:(BOOL)executing
{
[self willChangeValueForKey:kExecutingKey];
_executing = executing;
[self didChangeValueForKey:kExecutingKey];
}
- (void)setFinished:(BOOL)finished
{
[self willChangeValueForKey:kFinishedKey];
_finished = finished;
[self didChangeValueForKey:kFinishedKey];
}
willChangeValueForKey和 didChangeValueForKey你已经分散了你的代码。 isCancelled方法(因为已经为您实现了)。但你真的应该覆盖 cancel调用其 super 的方法执行,但也会取消您的网络请求并完成您的操作。或者,而不是实现 cancel方法,您可以移至 delegate基于网络请求的再现,但一定要检查 [self isCancelled]内didReceiveData方法。isCompleted用 isFinished 让我觉得多余.看来你可以完全消除completed属性(property)和isCompleted方法。 NSURLSession,您可能会不必要地重复网络代码量。和 NSURLConnection .如果您真的愿意,您可以这样做,但他们向我们保证 NSURLConnection仍然支持,所以我觉得它没有必要(除非你想享受一些适用于 iOS 7+ 设备的 NSURLSession 特定功能,而你目前没有这样做)。随心所欲,但就我个人而言,我正在使用 NSURLConnection我需要支持较早的 iOS 版本,以及 NSURLSession在我不这样做的地方,但除非有一些令人信服的业务要求,否则我不会倾向于同时实现两者。 关于ios - 通过重试将 NSOperation 子类化为 Internet 操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22127427/
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub
我正在使用puppet为ruby程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这
我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是
我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search
我在理解Enumerator.new方法的工作原理时遇到了一些困难。假设文档中的示例:fib=Enumerator.newdo|y|a=b=1loopdoy[1,1,2,3,5,8,13,21,34,55]循环中断条件在哪里,它如何知道循环应该迭代多少次(因为它没有任何明确的中断条件并且看起来像无限循环)? 最佳答案 Enumerator使用Fibers在内部。您的示例等效于:require'fiber'fiber=Fiber.newdoa=b=1loopdoFiber.yieldaa,b=b,a+bendend10.times.m
这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下
下面例子中的Nested和Child有什么区别?是否只是同一事物的不同语法?classParentclassNested...endendclassChild 最佳答案 不,它们是不同的。嵌套:Computer之外的“Processor”类只能作为Computer::Processor访问。嵌套为内部类(namespace)提供上下文。对于ruby解释器Computer和Computer::Processor只是两个独立的类。classComputerclassProcessor#Tocreateanobjectforthisc
这个问题在这里已经有了答案:Railsformattingdate(4个答案)关闭4年前。我想格式化Time.Now函数以显示YYYY-MM-DDHH:MM:SS而不是:“2018-03-0909:47:19+0000”该函数需要放在时间中.现在功能。require‘roo’require‘roo-xls’require‘byebug’file_name=ARGV.first||“Template.xlsx”excel_file=Roo::Spreadsheet.open(“./#{file_name}“,extension::xlsx)xml=Nokogiri::XML::Build
几个月前,我读了一篇关于rubygem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题: