2014-07-26 46 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