2014-07-26 111 views
1

我试图能够从另一个completionHandler块(在异步URL请求之后调用)内调用'completionHandler'块。然而,这将导致应用程序与下面的消息崩溃(我使用僵尸对象):
*** -[CFRunLoopTimer hash]: message sent to deallocated instance在iOS中嵌套块

使用仪器我能找出这个问题是由于被释放的块,但我不能弄清楚如何保持足够长的时间。是因为我从另一个异步块调用该块吗?我的代码如下(MyCompletionHandler返回void,并采取void):

-(void)requestWithRequest:(NSURLRequest*)request withCompletionHandler:(MyCompletionHandler)serverCompletionHandler{ 

    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { 
     // do stuff… 


      if (serverCompletionHandler) { 
       dispatch_async(dispatch_get_main_queue(), ^{ 
      serverCompletionHandler(); 
     }); 
    }]; 
} 

但是这个代码通过它提供的serverCompletionHandler参数的另一种方法称为(难道这是问题吗?)。

因此,例如,上述的方法将通过该方法称为:

-(void)createAndSendRequestWithCompletionHandler:(MyCompletionHandler)serverCompletionHandler{ 

    NSMutableURLRequest* request = //.. 
    [self requestWithRequest:request withCompletionHandler:serverCompletionHandler]; 
} 

仪器示出了块被释放或删除(I假设我打电话的块),这将解释解除分配的对象被称为。

任何帮助,将不胜感激。

编辑
定时器(这似乎被释放)的代码是:

if ([timer isValid]) { 
    [timer invalidate]; 
} 
timer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(createAndSendRequestWithCompletionHandler:) userInfo:nil repeats:YES]; 

的令人困惑的事情是代码工作得很好,直到我说的completionHandler秒。

回答

2

没有那不是一个问题,你可以接取另一block.I内的块认为问题是,你已经在mainQueue([NSOperationQueue mainQueue]),并再次尝试getMainQueue上mainQueue.As sendAsynchronousRequest队列使用NSRunloop它被释放时,您再次询问主队列,因为您已经在主队列中。您可以检查您是否已经在主队列中,只需拨打serverCompletionHandler其他dispatch on mainqueue。您可以跳过此检查,因为您确定您的号码是main queue,可以拨打serverCompletionHandler()

[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { 
    // do stuff… 


if([[NSOperationQueue currentQueue] isEqual:[NSOperationQueue mainQueue]]){ //check for main queue 
    if (serverCompletionHandler) { 
      serverCompletionHandler(); 
     } 
} 
else{ 
    if (serverCompletionHandler) { if not than dispatch on main queue 
      dispatch_async(dispatch_get_main_queue(), ^{ //No need to do that 
     serverCompletionHandler(); 
    }); 
} 

}]; 

编辑:编辑code.As的感谢您使用

timer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(createAndSendRequestWithCompletionHandler:) userInfo:nil repeats:YES]; 

现在,当你不及格completionhandler所以做这个createAndSendRequestWithCompletionHandler:定时器本身传递给你的serverCompletionHandler。 所以serverCompletionHandler本身含有timer对象没有任何block object.If尝试NSLogserverCompletionHandlerrequestWithRequest,你会发现它是定时器object.Now dispatch_async尝试当调用serverCompletionHandler因为它不是阻止它会崩溃。

createAndSendRequestWithCompletionHandler

NSLog(@"serverCompletionHandler obnj %@",serverCompletionHandler); 
NSLog(@"class %@",NSStringFromClass([serverCompletionHandler class])); 

EDIT 2

这两条线,如果你真的想通过完成处理器比定时器object.Use的userInfo通过下面的代码

#import "YourViewController.h" 
typedef void (^MyCompletionHandler)(void); 

@interface YourViewController() 
{ 
    NSTimer *timer; 
} 
@end 

@implementation YourViewController 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 

    if ([timer isValid]) { 
     [timer invalidate]; 
    } 

    MyCompletionHandler com = ^{ 
     NSLog(@"Hi this is completion handler"); 
    }; 

    timer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(createAndSendRequestWithCompletionHandler:) userInfo:@{@"serverCompletionHandler":com} repeats:YES]; 

} 

- (void)didReceiveMemoryWarning 
{ 
    [super didReceiveMemoryWarning]; 
    // Dispose of any resources that can be recreated. 
} 

-(void)requestWithRequest:(NSURLRequest*)request withCompletionHandler:(MyCompletionHandler)serverCompletionHandler{ 

    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { 
     // do stuff… 


     if (serverCompletionHandler) { 
      dispatch_async(dispatch_get_main_queue(), ^{ 
       serverCompletionHandler(); 
      }); 
     } 

    }]; 
} 


-(void)createAndSendRequestWithCompletionHandler:(NSTimer *)timerObj{ 

// NSLog(@"serverCompletionHandler obnj %@",serverCompletionHandler); 
// NSLog(@"class %@",NSStringFromClass([serverCompletionHandler class])); 


    //get completion handler from `userInfo` 
    NSMutableURLRequest* request = [[NSMutableURLRequest alloc] init]; 
    [self requestWithRequest:request withCompletionHandler:timerObj.userInfo[@"serverCompletionHandler"]]; 
} 


@end 
+0

同意,但为什么当你知道你在上面时,你会检查你是否在主队列? sendAsynch的第一个参数指定完成处理程序将被调用的队列。 – danh

+0

如果你在另一个线程上并在其他队列上操作'sendAsynchronousRequest',因为在主队列上操作此方法并不常见。在这种情况下,我们可以跳过此检查 – codester

+0

好的。 OP正在使用主队列,硬编码。 – danh