NSURLSessionDataTask:NSOperationQueue中的应用程序崩溃

亚历克斯

我使用的是NSURLSessionDataTaskNSOperationQueue这导致我的应用程序崩溃。

不幸的是,在更改了许多与队列相关的参数并通读了文档之后,我仍然无法找到导致错误的原因。

我会很感激您的帮助和提示!

这是我的AppDelegate.m(Cocoa),在其中设置队列并启动后台操作。请注意,该操作具有完成处理程序:

@property (strong, nonatomic) NSOperationQueue *queue;

- (IBAction)startProcess:(id)sender {

    self.queue = [NSOperationQueue new];
    self.queue.maxConcurrentOperationCount = 1; // serial queue

    MyOperation *myOperation = [[MyOperation alloc]initWithSymbol:@"abc"
        withCompletion:^(NSError *error, NSString *result) {
        NSLog(@"Process completed: %@",result);
    }];
    [self.queue myOperation];
}

这是MyOperation.h

@interface MyOperation : NSOperation

MyOperation.m:

@interface MyOperation ()

typedef void(^completionBlock)(NSError *error, NSString *result);
@property (strong, nonatomic) completionBlock completionBlock;

@end

@implementation MyOperation

- (id)initWithSymbol:(NSString*)symbol withCompletion:
        (void(^)(NSError *error, Order *order))completionBlock
{
    self = [super init];
    if (self) {
        _symbol = symbol;
        _completionBlock = completionBlock;
    }
    return self;
}

- (void)main {
  MyObject *myObject = [[MyObject alloc]init];
  [myObject downloadData:self.symbol withCompletion:
         ^(NSDictionary *results, NSError *error) {

      //... }];

这是MyObject.m,其中应用程序在方法中崩溃-downloadData

- (void)downloadData:self:(NSString*)symbol 
      withCompletion:(void(^)(NSDictionary* results, NSError *error))completionBlock
   // ...
  NSMutableURLRequest *request = [NSMutableURLRequest 
      requestWithURL:[NSURL URLWithString:[self.baseUrl 
      stringByAppendingString:path]]];

  NSURLSessionConfiguration *sessionConfig = 
      [NSURLSessionConfiguration defaultSessionConfiguration];

  NSURLSession *session = [NSURLSession 
     sessionWithConfiguration:sessionConfig delegate:self 
     delegateQueue:[NSOperationQueue currentQueue]];

   NSURLSessionDataTask *dataTask = 
      [session dataTaskWithRequest:request 
      completionHandler:^(NSData *data, NSURLResponse *response, 
      NSError *error) {
    // **** THE APP CRASHES HERE RIGHT AFTER THE DATATASK STARTS. ****
    // The completion block never gets called.
    completionBlock(results, nil);
}];
[dataTask resume];
}

这是崩溃日志(Thread 2, 0__cxa_throw):

    libc++abi.dylib`__cxa_throw:
0x7fff8f6e1bdf:  pushq  %rbp
0x7fff8f6e1be0:  movq   %rsp, %rbp
0x7fff8f6e1be3:  pushq  %r15
0x7fff8f6e1be5:  pushq  %r14
0x7fff8f6e1be7:  pushq  %r13
0x7fff8f6e1be9:  pushq  %r12
0x7fff8f6e1beb:  pushq  %rbx
0x7fff8f6e1bec:  pushq  %rax
0x7fff8f6e1bed:  movq   %rdx, %r14
0x7fff8f6e1bf0:  movq   %rsi, %r15
0x7fff8f6e1bf3:  movq   %rdi, %rbx
0x7fff8f6e1bf6:  callq  0x7fff8f6e17f4            ; __cxa_get_globals
0x7fff8f6e1bfb:  movq   %rax, %r12
0x7fff8f6e1bfe:  callq  0x7fff8f6e2180            ; std::get_unexpected()
0x7fff8f6e1c03:  movq   %rax, -0x60(%rbx)
0x7fff8f6e1c07:  callq  0x7fff8f6e21ba            ; std::get_terminate()
0x7fff8f6e1c0c:  leaq   -0x20(%rbx), %r13
0x7fff8f6e1c10:  leaq   0x44(%rip), %rcx          ; __cxxabiv1::exception_cleanup_func(_Unwind_Reason_Code, _Unwind_Exception*)
0x7fff8f6e1c17:  movabsq $0x434c4e47432b2b00, %rdx
0x7fff8f6e1c21:  movq   %rax, -0x58(%rbx)
0x7fff8f6e1c25:  movq   %r15, -0x70(%rbx)
0x7fff8f6e1c29:  movq   %r14, -0x68(%rbx)
0x7fff8f6e1c2d:  movq   %rdx, -0x20(%rbx)
0x7fff8f6e1c31:  movq   $0x1, -0x78(%rbx)
0x7fff8f6e1c39:  incl   0x8(%r12)
0x7fff8f6e1c3e:  movq   %rcx, -0x18(%rbx)
0x7fff8f6e1c42:  movq   %r13, %rdi
0x7fff8f6e1c45:  callq  0x7fff8f6e49cc            ; symbol stub for: _Unwind_RaiseException
0x7fff8f6e1c4a:  movq   %r13, %rdi
0x7fff8f6e1c4d:  callq  0x7fff8f6e1c7f            ; __cxa_begin_catch
0x7fff8f6e1c52:  movq   -0x58(%rbx), %rdi
0x7fff8f6e1c56:  callq  0x7fff8f6e21c9            ; std::__terminate(void (*)())

MyObject充当Web服务的API,并具有从中获取数据的方法。

MyOperation包含业务逻辑并控制正在发送到API的请求。

想象一下MyObject是股票经纪人的API,方法是:getSharePrice,placeOrder和cancelOrder。

MyOperation定义逻辑,例如sharePrice = getSharePrice(symbol:"AAPL"); while (sharePrice < 300) placeOrder("AAPL", 50) until allSharesBought = 1000.

谢谢您的帮助!!

如果您无法使操作成为“并发”操作(例如,返回异步isConcurrentisFinished仅在异步处理完成后才发布的操作),则可能会发生崩溃MyOperation否则,您的对象可能会过早地被释放,因为在请求的发起完成时,操作已“完成”,而不是等待响应。有关并行操作的讨论,请参阅配置Operations并发执行的部分操作队列中的一章并发编程指南。

此外,您可能还想确保对保持强烈的引用myObject

因此:

@interface MyOperation ()

typedef void(^MyOperationCompletionBlock)(NSError *error, NSString *result);

@property (copy, nonatomic) MyOperationCompletionBlock myOperationCompletionBlock;
@property (strong, nonatomic) MyObject *myObject;

@property (nonatomic, readwrite, getter = isFinished)  BOOL finished;
@property (nonatomic, readwrite, getter = isExecuting) BOOL executing;

@end

@implementation MyOperation

@synthesize finished  = _finished;
@synthesize executing = _executing;

- (id)initWithSymbol:(NSString*)symbol withCompletion:(MyOperationCompletionBlock)completionBlock
{
    self = [super init];
    if (self) {
        _symbol = symbol;
        _myOperationCompletionBlock = completionBlock;
    }
    return self;
}

- (void)start
{
    if ([self isCancelled]) {
        self.finished = YES;
        return;
    }

    self.executing = YES;

    self.myObject = [[MyObject alloc]init];
    [self.myObject downloadData:self.symbol withCompletion:^(NSDictionary *results, NSError *error) {

        NSString *result = ... // presumably you're extracting this from `results` dictionary

        if (self.myOperationCompletionBlock)
            self.myOperationCompletionBlock(error, result);

        [self completeOperation];  // this is the key; post the `isFinished` notification when done
    }];
}

- (void)completeOperation
{
    self.executing = NO;
    self.finished  = YES;
}

#pragma mark - NSOperation methods

- (BOOL)isConcurrent
{
    return YES;
}

- (void)setExecuting:(BOOL)executing
{
    [self willChangeValueForKey:@"isExecuting"];
    _executing = executing;
    [self didChangeValueForKey:@"isExecuting"];
}

- (void)setFinished:(BOOL)finished
{
    [self willChangeValueForKey:@"isFinished"];
    _finished = finished;
    [self didChangeValueForKey:@"isFinished"];
}

@end

另外,在进行会话时,如果您不编写委托方法(这是您使用的完成块格式表示的dataTaskWithRequest),则应使用[NSURLSession sharedSession][NSURLSession sessionWithConfiguration:configuration](但未指定委托)。指定delegateofnil可能会导致问题。因此:

- (void)downloadData:self:(NSString*)symbol withCompletion:(void(^)(NSDictionary* results, NSError *error))completionBlock
{
    // ...
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[self.baseUrl stringByAppendingString:path]]];

    NSURLSession *session = [NSURLSession sharedSession];

    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {

        // **** THE APP CRASHES HERE RIGHT AFTER THE DATATASK STARTS. ****
        // The completion block never gets called.
        completionBlock(results, nil);
    }];
    [dataTask resume];
}

无关的,我还建议:

  1. 不要调用您的block属性completionBlockNSOperation已经具有一个completionBlock属性(具有不同的签名)。在上面的示例中,我将其重命名为myOperationCompletionBlock

  2. Apple建议您使用copy内存语义声明块属性如果使用ARC,无论如何,它就是这样做的,因此,他们建议使用最能反映正在发生的事情的内存语义声明您的属性。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

NSOperation中的NSOperationQueue导致应用程序因waitUntilFinished而冻结:是

来自分类Dev

NSOperation中的NSOperationQueue导致应用程序因waitUntilFinished而冻结:是

来自分类Dev

Android应用程序在简单应用程序中崩溃

来自分类Dev

iOS 7中的应用程序崩溃

来自分类Dev

Slidingtablayout中的SwipableRefreshLayout使应用程序崩溃

来自分类Dev

getExtra使服务中的应用程序崩溃

来自分类Dev

@IBAction使Swift中的应用程序崩溃

来自分类Dev

Slidingtablayout中的SwipableRefreshLayout使应用程序崩溃

来自分类Dev

我的应用程序在MainActivity中崩溃

来自分类Dev

PreferenceFragment中的AlertDialog使应用程序崩溃

来自分类Dev

在开始的Android应用程序中崩溃

来自分类Dev

应用程序在 android studio 中的 managedQuery 行中崩溃

来自分类Dev

MySQLIntegrityConstraintViolationException使应用程序崩溃

来自分类Dev

setImageResource崩溃的应用程序

来自分类Dev

OpenGL使应用程序崩溃

来自分类Dev

NSAutoLayoutConstraints崩溃的应用程序

来自分类Dev

Searchview崩溃的应用程序

来自分类Dev

selectableItemBackground崩溃的应用程序

来自分类Dev

ImageView使应用程序崩溃

来自分类Dev

setText使应用程序崩溃

来自分类Dev

setAdapter()使应用程序崩溃

来自分类Dev

SoundPool崩溃的应用程序

来自分类Dev

setImageResource崩溃的应用程序

来自分类Dev

selectableItemBackground崩溃的应用程序

来自分类Dev

应用程序在ABMultiValueRef崩溃

来自分类Dev

MySQLIntegrityConstraintViolationException使应用程序崩溃

来自分类Dev

VC ++-应用程序崩溃

来自分类Dev

stringForKey崩溃应用程序

来自分类Dev

应用程序崩溃。...NullPointerException

Related 相关文章

热门标签

归档