【问题标题】:inputAssistantItem and inputAccessoryView stopped working with ARCinputAssistantItem 和 inputAccessoryView 停止使用 ARC
【发布时间】:2016-11-12 02:46:20
【问题描述】:

我正在使用此代码在我的 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 上有自动释放,并且在 initWithNibName 之前没有 (void) 演员表),现在按钮仍然显示为预期,但不工作。在 iOS 8 上,我在点击其中一个按钮时崩溃([CALayer button1]: unrecognized selector sent to instance,我认为这表示内存指针无效),在 iOS 9 上,当我点击一个按钮时没有任何反应,并且按钮方法的日志记录是没有调用。

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

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

[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 中发生了登录,并且因为视图显示为 inputAccessoryView 手机和 iOS 8 平板电脑。

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

【问题讨论】:

    标签: ios automatic-ref-counting uitextinput


    【解决方案1】:

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

    要修复,请在使用视图时保留视图控制器。

    另外,我不确定你是从哪里学到的:

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

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

    【讨论】:

    • 你说得对,我应该在 textInputToolbar 上有一个自动释放功能,我刚刚确认它破坏了非 ARC 中的功能。你能告诉我在这种情况下如何正确保留和释放 textInputToolbar 吗?我是否需要使用父视图控制器的实例变量而不是局部变量,或者我可以在这段代码中以某种方式完成所有操作?
    • 你需要在包含的视图控制器上添加一个属性,一个实例变量,是的。
    【解决方案2】:

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

    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 将被释放,但它的视图不会。这就是为什么你可以看到按钮,但是当你点击它们时,观察者变成了一个野指针,运行时找不到函数所以它崩溃了。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-03
      • 2013-11-14
      • 1970-01-01
      • 2011-12-25
      • 2014-10-15
      • 2014-04-06
      • 2013-07-18
      • 2016-07-31
      相关资源
      最近更新 更多