我试图使用块创建一个简单的回调。 我有一个MainViewController addSubView另一个DatePickerViewController.view我创建了一个像这样的块
typedef void(^DateChangedBlock)(NSDate*);
我的DatePickerViewController上有一个名为
的方法setOnDateChangedCallback:(DateChangedBlock)callback
我将回调存储在DatePickerViewController的属性中。 DatePickerViewController的视图是一个UIDatePicker实例,我已将IBAction绑定到更改为执行此操作的方法的值。
- (IBAction)dateChanged:(id)sender {
if (dateChangedCallback != nil)
{
dateChangedCallback(nil);
}
}
以下是我在MainViewController
中注册块的方法DatePickerViewController *dateController = [[DatePickerViewController alloc] initWithNibName:@"DatePickerView" bundle:nil];
self.datePicker = dateController;
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 100, 200)];
[self.view addSubview:textView];
DateChangedBlock myBlock = ^(NSDate *newDate) {
textView.text = @"testing";
};
[self.datePicker setOnDateChanged: myBlock];
[self.datePicker dateChanged:self]; // force trigger (this works).
当我强制触发DatePickerViewController上的dateChanged方法时,它没有问题。但是当datepicker本身通过IBAction触发方法时,我得到一个EXC_BAD_ACCESS错误。此方法在“int retVal”行上发生错误。
#import <UIKit/UIKit.h>
int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil); // THREAD 1: program received EXC_BAD_ACCCESS.**
[pool release];
return retVal;
}
我做错了什么?
答案 0 :(得分:24)
您应该在将块传递给其他方法时复制块(例如您的情况下的属性设置器)。因此,在设置回调块时,请执行以下操作:
[self.datePicker setOnDateChanged:[[myBlock copy] autorelease]];
创建块时使用的EXC_BAD_ACCESS原因块变量不会被块本身保留。因此,当调用块时 - 变量不再存在。
答案 1 :(得分:4)
接受的答案是错误的。您无需在MainViewController
中复制它。相反,带有块参数的setOnDateChangedCallback:
方法负责复制它,如果它需要将它存储在一个实例变量中(我看到它正在做,在变量dateChangedCallback
中,稍后由另一种方法)。如果dateChangedCallback
是合成属性,则可以通过将属性声明为copy
而不是retain
来完成此操作。
答案 2 :(得分:-3)
您只能从UI线程更新UI。由于您的块在另一个线程上运行,因此在更新textView
的文本时会出现异常。您可以使用主队列(dispatch_get_main_queue()
)在块中运行UI线程上的代码。