objective-c - block 执行时的 EXC_BAD_ACCESS

标签 objective-c objective-c-blocks urlconnection

我有一个只有一个方法的类,它使用 URLConnection 将序列化的 NSDictionary 发送到某个 URL 处的脚本,然后调用完成 block 。这是该方法的代码:

- (void)sendDictionary:(NSDictionary *)dictionary toScript:(NSString *)scriptName completion:(void (^) (id response))completionBlock
{

    ...Serialize data and add it to an NSURLRequest request...

    H2URLConnection *connection = [[H2URLConnection alloc]initWithRequest:request];

    //Define a semaphore to block execution of later statements until the signal is received.
    dispatch_semaphore_t sem = dispatch_semaphore_create(0);

    [connection setCompletionBlock:[^(id obj, NSError *err)
     {
         if (!err) {
            //Catch the server response
             NSString *receivedString = [[NSString alloc] initWithData:obj encoding:NSUTF8StringEncoding];
             NSLog( @"ChecklistAppNetworkManager received string: %@", receivedString);

             //Convert the JSON response into an NSDictionary
             NSError *otherError;
             id deserializedJSON = [NSJSONSerialization JSONObjectWithData:obj options:kNilOptions error:&otherError];

             if (otherError) {
                 NSLog(@"ChecklistAppNetworkManager JSON Error: %@", otherError.description);
             }

             [completionBlock invoke];

             NSLog(@"ChecklistAppNetworkManager JSON Response: %@", deserializedJSON);

             //Dispatch the semaphore signal so that the main thread continues.
             dispatch_semaphore_signal(sem);

         } else {
             NSLog(@"ChecklistAppNetworkManager encountered an error connecting to the server: %@", [err description]);
         }

     }copy]];
    //Finalize and initate the connection.
    [connection start];

    //Since block is dispatched to main queue, stall with a loop until the semaphore signal arrives.
    while (dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW)) {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]];
    }
}

我正在尝试从定义了完成 block 的另一个类中的此类实例调用此方法。这是我获得 EXC_BAD_ACCESS 的代码:

- (void)doSomeServerTask
{
    H2ChecklistAppNetworkManager *currentNetworkManager = ((H2AppDelegate *)[[UIApplication sharedApplication]delegate]).networkManager; //Instantiate class where that method is defined

    NSMutableDictionary *dictonary = [NSMutableDictionary dictionary];

    ...populate dictionary...

    [currentNetworkManager sendDictionary:dictionary toScript:@"script.php" completion:[^(id response)
     { //THIS iS THE LINE WHERE THE BAD ACCESS OCCURS

         NSLog(@"LoginViewController received response: %@", response);

     } copy]];
}

如有任何帮助,我们将不胜感激!

最佳答案

该方法的 completionBlock 接受一个参数,但您使用 invoke 方法调用该 block 。崩溃更有可能是因为运行时试图保留内存中应该是该参数的任何垃圾。


但是,您确实需要完全重构这段代码。阻塞主事件循环是不好的。在 MEL 上运行子运行循环甚至更糟;它改变了调度队列处理语义的工作方式,并可能导致病态的不良性能或行为。

您应该转向真正的异步模型。如果在完成这些查询之前应用程序无法继续,则放置一个模式指示器来阻止进度。

为此,您将代码松散地构造为:

• 将用户界面置于“正在加载...”或其他一些模态状态

• 使用完成处理程序执行异步数据请求

• 在完成处理程序中,将“更新 UI”请求分派(dispatch)到主队列

• 在“更新用户界面”时,拆除您的模态“正在加载...”用户界面并为用户更新显示

无需阻塞主事件循环即可执行任何操作。

关于objective-c - block 执行时的 EXC_BAD_ACCESS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34373946/

相关文章:

ios - SWRevealViewController 使侧边栏按钮静态并使 rearView 出现在 frontView 的顶部

ios - 在执行使用对 self 的强引用的 block 时更改 self 的 @property 值

java - 无法使用 Java 的 URLConnection 获取响应 header 位置

java - Google 天气 api,读取 xml 时出现问题

iOS 更改按钮图像以填满 iphone 3.5 英寸和 iphone 4 英寸的屏幕

objective-c - 我可以在 int 和 NSNumber 之间实现多重调度吗?

ios - __weak 貌似保留了对象

ios - UITableViewCell 部分重复

ios - 关闭键盘不工作

java - URLConnection 的 getInputStream() 是否每次都返回相同的 InputStream?