0

我正在使用此代码在我的 iOS 应用程序的屏幕键盘上方添加一些按钮。请注意,我在手机和 iOS 9 之前的设备上使用较旧的 inputAccessoryView 方法,在 iOS 9 平板电脑上使用较新的 inputAssistantItem:

UITextView *textInputMultiline = [[UITextView alloc] initWithFrame:frame];
TextInputToolbar *textInputToolbar = [TextInputToolbar alloc]; // custom class
(void)[textInputToolbar initWithNibName:@"TextInputToolbar" bundle:nil];
textInputToolbar.textView = textInputMultiline;
if ((self.appDelegate.isTablet)&&([[[UIDevice currentDevice] systemVersion] compare:@"9.0"] != NSOrderedAscending)) {
    NSMutableArray *barButtonItems = [NSMutableArray array];
    [barButtonItems addObject:[[UIBarButtonItem alloc] initWithTitle:@"button 1" style:UIBarButtonItemStylePlain target:textInputToolbar action:@selector(button1)]];
    [barButtonItems addObject:[[UIBarButtonItem alloc] initWithTitle:@"button 2" style:UIBarButtonItemStylePlain target:textInputToolbar action:@selector(button2)]];
    [barButtonItems addObject:[[UIBarButtonItem alloc] initWithTitle:@"button 3" style:UIBarButtonItemStylePlain target:textInputToolbar action:@selector(button3)]];
    UIBarButtonItem *representativeItem = nil;
    UIBarButtonItemGroup *group = [[UIBarButtonItemGroup alloc] initWithBarButtonItems:barButtonItems representativeItem:representativeItem];
    textInputMultiline.inputAssistantItem.trailingBarButtonGroups = [NSArray arrayWithObject:group];
} else {
    textInputMultiline.inputAccessoryView = textInputToolbar.view;
}

我的自定义工具栏类如下所示:

@interface TextInputToolbar : UIViewController {
    UITextView *textView;

    IBOutlet UIButton *button1;
    IBOutlet UIButton *button2;
    IBOutlet UIButton *button3;
}

@property (nonatomic, strong) UITextView *textView;

- (void)insertText:(NSString *)text;

- (IBAction)button1;
- (IBAction)button2;
- (IBAction)button3;

@end

和...

#import "TextInputToolbar.h"

@implementation TextInputToolbar

@synthesize textView;

- (void)viewDidLoad {
    NSLog(@"viewDidLoad");
    [super viewDidLoad];
}

- (void)insertText:(NSString *)text {
    [self.textView insertText:text];
}

- (IBAction)button1 {
    NSLog(@"button1");
    [self insertText:@"1"];
}

- (IBAction)button2 {
    NSLog(@"button2");
    [self insertText:@"2"];
}

- (IBAction)button3 {
    NSLog(@"button3");
    [self insertText:@"3"];
}

@end

当我的应用程序未使用 ARC 时,这按预期工作。我最近更新到 ARC,只需要对上面的代码进行少量更改(UIBarButtonItems(void)之前initWithNibName在 在 iOS 8 上,我在点击其中一个按钮时崩溃([CALayer button1]: unrecognized selector sent to instance,我认为这表示内存指针无效),在 iOS 9 上,当我点击一个按钮时没有任何反应,并且不会调用按钮方法的日志记录。

在更新到 ARC 之前,我有我的项目的副本,当我返回并在我的 iOS 8 或 iOS 9 设备上运行它时,工具栏按钮再次起作用。因此,似乎 ARC 要么是问题的根源,要么是另一个问题的触发器。

如果我将 barButtonItem 指向自我,就像这样......

[barButtonItems addObject:[[UIBarButtonItem alloc] initWithTitle:@"button 3" style:UIBarButtonItemStylePlain target:self action:@selector(test)]];

...按预期接收方法调用。如果我将 barButtonItem 选择器更改为无效方法,像这样......

[barButtonItems addObject:[[UIBarButtonItem alloc] initWithTitle:@"button 3" style:UIBarButtonItemStylePlain target:textInputToolbar action:@selector(flkjfd)]];

...什么都没发生。这向我表明,在调用按钮选择器时 textInputToolbar 以某种方式变为 nil,因为如果它不是 nil,则会产生无法识别的选择器崩溃。

但我知道 TextInputToolbar 类及其视图正在加载,因为发生了 viewDidLoad 的登录,并且视图显示为手机和 iOS 8 平板电脑的 inputAccessoryView。

知道发生了什么,或者我还能做些什么来排除故障?

4

2 回答 2

1

调用这些代码时发生了什么:

UITextView *textInputMultiline = [[UITextView alloc] initWithFrame:frame];

//alloc textInputToolbar (textInputToolbar.retaincount = 1)
TextInputToolbar *textInputToolbar = [TextInputToolbar alloc];
textInputToolbar.textView = textInputMultiline;

if ((self.appDelegate.isTablet)&&([[[UIDevice currentDevice] systemVersion] compare:@"9.0"] != NSOrderedAscending)) {
    NSMutableArray *barButtonItems = [NSMutableArray array];
    //add button items....
    UIBarButtonItem *representativeItem = nil;

    //alloc UIBarButtonItemGroup (group.retaincount = 1)
    UIBarButtonItemGroup *group = [[UIBarButtonItemGroup alloc] initWithBarButtonItems:barButtonItems representativeItem:representativeItem];

    //strong reference group (group.retaincount = 2)
    textInputMultiline.inputAssistantItem.trailingBarButtonGroups = [NSArray arrayWithObject:group];
    //autorelease group 

} else {
    //strong reference textInputToolbar.view (textInputToolbar.view.retaincount = 2)
    textInputMultiline.inputAccessoryView = textInputToolbar.view;
}

//autorelease textInputToolbar (textInputToolbar.retaincount = 0, textInputToolbar.view.retaincount = 1)

在 iOS 8 中, textInputToolbar 将被 dealloc 但它的视图不会。这就是为什么你可以看到按钮但是当你点击它们时,观察者变成了一个野指针,运行时找不到函数所以它崩溃了。

在 iOS 9 中,textInputToolbar 也将被释放。由于您创建了按钮项并将观察(弱引用)目标设置在 InputToolbar 之外,当 textInputToolbar 释放时,观察变为 nil。因此不会调用该函数。

于 2016-07-15T08:20:25.180 回答
1

您的代码从来都不是正确的,只是因为泄漏而起作用。你基本上失去/不保留视图控制器。它过去只是继续存在和工作,但在 ARC 下它已被释放,因此没有什么可以响应按钮。ARC 已经解决了您的记忆问题,并让您意识到存在问题,尽管不是以一种理想的方式。

要解决此问题,请在使用视图时保留视图控制器。

另外,我不确定你在哪里学会的:

TextInputToolbar *textInputToolbar = [TextInputToolbar alloc]; // custom class
(void)[textInputToolbar initWithNibName:@"TextInputToolbar" bundle:nil];

但你不应该。在一条线上完成所有这些。不要忽略init调用返回的对象 - 它可能与您最初调用它的对象不同。

于 2016-07-12T16:52:45.197 回答