【问题标题】:iOS: sendSynchronousRequest with performSelectorInBackgroundiOS:带有 performSelectorInBackground 的 sendSynchronousRequest
【发布时间】:2012-02-13 17:07:17
【问题描述】:

我需要对某个 url 进行几次 https 调用。因此我做这样的事情

//ViewController Source
-(IBAction) updateButton_tapped {
    [self performSelectorInBackground:@selector(updateStuff) withObject:nil];
}


-(void) updateStuff {
    // do other stuff here...
    NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:self.url]];
    [request setHTTPMethod:@"POST"];

    NSData *postData = [[Base64 encodeBase64WithData:payload] dataUsingEncoding:NSASCIIStringEncoding];
    [request setHTTPBody:postData];

    NSURLResponse* response = [[NSURLResponse alloc] init];
    NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];

    //Process the recieved data...

    //Setup another synchronous request
    data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];

    //Process data

    //do this another 4 times (note for loop cannot be use in my case ;) )

    //Finally update some view controllers
    [[NSNotificationCenter defaultCenter] postNotificationName:@"NotificationIdentifier" object:self];
}

因此,此代码的问题在于它随机崩溃(并非总是如此,而是经常崩溃)。我在日志上没有调试输出。有时我的整个应用程序冻结或它只是使整个程序崩溃。但如果我在主线程上运行它,它永远不会崩溃。因此我认为代码是正确的,我想现在它与 iphone 上的线程有关。

以这种方式运行代码会出现什么问题,什么可能导致随机崩溃?

【问题讨论】:

    标签: ios multithreading httprequest


    【解决方案1】:

    内存管理,你不会在分配后释放你的请求或响应对象。

    【讨论】:

      【解决方案2】:

      请重新检查您的代码,以免在后台线程中更新任何 GUI。此外,使用异步处理应该会好得多。

      【讨论】:

        【解决方案3】:

        控制器或其他任何东西可能假设他们正在主线程上接收通知,在你的情况下他们不是(而且这绝不是一个安全的假设)。在对数据进行任何操作/更新 UIKit 内容等之前,让控制器在其通知回调中分派回主线程。

        您还应该在-updateStuff 的整个实现周围放置一个@autorelease 块。

        以下是您可能在其中一个控制器中收到的回调通知示例:

        - (void)updateStuffNotificaiton:(NSNotification*)note
        {
          // Can't assume we're on the main thread and no need to
          // test since this is made async by performSelectorInBacground anyway
          dispatch_async(dispatch_get_main_queue(), ^{
            // relocate all your original method implementation here
          });
        }
        

        还请注意,如果您的-updateStuff 实现正在创建和操作您的通知回调方法随后访问的数据结构,那么正确保护这些访问器非常重要。将数据批发回传回通知的userInfo 字典中的回调通常会更好。

        将自动释放符号添加到您的 -updateStuff 方法的示例:

        -(void) updateStuff
        {
         @autoreleasepool {
            // do other stuff here...
            NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:self.url]];
            [request setHTTPMethod:@"POST"];
        
            // rest of method snipped for brevity
        
            //Finally update some view controllers
            [[NSNotificationCenter defaultCenter] postNotificationName:@"NotificationIdentifier" object:self];
         }
        }
        

        【讨论】:

        • 感谢您的回答。但是在我的情况下,我该如何使用 autorelease 块。我不知道自动释放注释。
        • @toom 在后台线程上执行时,您需要一个自动释放池。您的选择是将调度切换到为您管理此池的 Grand Central Dispatch,或者简单地将方法的主体包含在 @autoreleasepool 块中。我在回答中为您添加了后者的示例。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多