为什么当我在 .m 文件中设置 ^block 变量时,我收到一条错误消息说 Thread_1 EXC_BAD_ACCESS

Why when I set a ^block variable in .m file, I receive an error message saying Thread_1 EXC_BAD_ACCESS

我正在尝试实现发布在 Whosebug 上的这个答案

use block to pass data from modal view to parent view

当我尝试在我的 SecondViewController(模态视图)实现中将 vale 设置为阻塞时。我收到错误的内存访问错误。

我仍在学习 Objective C 并使用协议我可以做到这一点,但阻止似乎更有效。 谁能告诉我我在哪里犯了错误。这是我的 StoryBoard 的代码和图像。

FirstViewController.h

#import <UIKit/UIKit.h>
#import "SecondViewController.h"

@interface FirstViewController : UIViewController

@end

FirstViewController.m

#import "FirstViewController.h"
#import "SecondViewController.h"

@interface FirstViewController ()

@end

@implementation FirstViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    SecondViewController *second = [[SecondViewController alloc]init];
    second.somethingHappenedInModalVC = ^(NSString *response) {
        NSLog(@"Something was selected in the modalVC, and this is what it was:%@", response);
    };

}

@end

SecondViewController.h //模态视图

#import <UIKit/UIKit.h>
#import "FirstViewController.h"

@interface SecondViewController : UIViewController
@property (nonatomic, copy) void (^somethingHappenedInModalVC)(NSString *response);

@end

SecondViewController.m

 #import "SecondViewController.h"


@interface SecondViewController ()
@property (strong, nonatomic) IBOutlet UITextField *textField;

@end

@implementation SecondViewController

- (IBAction)closeView:(id)sender {
    self.somethingHappenedInModalVC(@"Sending the message"); //here memory warning display.
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

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

您有一个执行以下操作的 viewDidLoad

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    SecondViewController *second = [[SecondViewController alloc]init];
    second.somethingHappenedInModalVC = ^(NSString *response) {
        NSLog(@"Something was selected in the modalVC, and this is what it was:%@", response);
    };
}

创建一个 SecondViewController,设置 somethingHappenedInModalVC 属性,但随后让第二个视图控制器实例超出范围,因此将被释放(从而丢弃该块属性 还有)。

因此,当您最终转换到 SecondViewController(此时此视图控制器的另一个实例被实例化)时,此新实例的 somethingHappenedInModalVCnil,因此尝试调用该块将会崩溃。

您通常在 prepareForSegue 中在此目标控制器中设置属性(或者如果您手动实例化 SecondViewController,请在此处手动设置)。您还没有向我们展示您是如何过渡到第二个视图控制器的,因此我们无法告诉您示例中哪种方式是正确的。

例如,您的第一个视图控制器中可能有一个 prepareForSegue,当您对 SecondViewController:

执行 segue 时会自动调用它
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([[segue identifier] isEqualToString:@"IdForSegue"]) {
        SecondViewController *destination = segue.destinationViewController;
        destination.somethingHappenedInModalVC = ^(NSString *response) {
            NSLog(@"Something was selected in the modalVC, and this is what it was:%@", response);
        };
    }
}

请注意,这假设您已经向执行到第二个视图控制器的转换的 segue 提供了故事板 ID。确保代码片段中的标识符与您为故事板中的 segue 提供的故事板 ID 匹配。

问题是,您正在创建 SecondViewController 的新实例并将块设置为新创建的实例,而不是当前(将要)显示的实际实例。因此,在您的实际 SecondViewController 对象中,该块将仍然是 nil,这就是它崩溃的原因。

在处理块时,你应该总是在调用它之前进行 nil 检查:

if (somethingHappenedInModalVC)
{
   somethingHappenedInModalVC(@"Sending the message");
}

并且为了解决逻辑问题,您应该使用 SecondViewController 的实际实例,而不是在 viewDidLoad.

中创建一个新实例