【问题标题】:UIViewController with inputAccessoryView is not deallocated带有 inputAccessoryView 的 UIViewController 未被释放
【发布时间】:2014-08-27 01:49:26
【问题描述】:

我有 UIViewController 的简单子类(代码如下)。 如果我附加 inputAccessoryView,我的视图控制器永远不会被释放。如果我没有在 viewDidLoad 中设置 inputAccessoryView,dealloc 会按预期调用。

我错过了什么吗?

@interface IMTestViewController : UIViewController

@property (nonatomic, strong) UIView *messageInputView;
@property(nonatomic, readwrite, strong) UIView *inputAccessoryView;

@end

@implementation IMTestViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)dealloc
{

}

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.inputAccessoryView = self.messageInputView;
}

- (BOOL)canBecomeFirstResponder
{
    return YES;
}

- (UIView *)messageInputView
{
    if (_messageInputView == nil)
    {
        _messageInputView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 45)];
        _messageInputView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    }
    return _messageInputView;
}
@end

我的想法已经用完了。 谢谢。

【问题讨论】:

  • 你想把这个 inputAccessoryView 添加到出现的键盘上吗?如果是这样,你做错了。 inputAccessoryView 是 UITextField 上的属性,而不是 UIViewController。我不确定,为什么这样做会导致您的控制器不会被释放,但是如果您将名称更改为 inputAccessoryView 以外的名称,它会被正确释放。因此,似乎错误地使用此属性名称会以某种方式混淆系统。
  • 请添加用于设置self.messageInputView的代码和用于呈现IMTestViewController的代码
  • @rdelmar,inputAccessoryView 是 UIResponder 的一个属性,它是 UIViewController 的超类。
  • @Rafeek,这就是我拥有的所有代码。我为此创建了一个示例项目。 appDelegate 中的代码: UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[UIViewController new]]; [导航 pushViewController:[IMChatIAVViewController new] 动画:NO]; self.window.rootViewController = 导航;
  • 我和你的情况相同。如果您找到了解决方案,请告诉我。

标签: ios objective-c ios7 uiviewcontroller uiresponder


【解决方案1】:

不幸的是,@rdelmar 的回答没有奏效。经过一段时间尝试解决后,我找到了这篇文章:http://derpturkey.com/uitextfield-docked-like-ios-messenger/

我的目标是让输入附件视图可见,即使键盘不可见,就像在所有 IM 应用程序中一样。我之前将我的UIViewController 自定义类子类化以使其成为第一响应者并将我的自定义子视图返回为inputAccessoryView。这阻止了视图控制器被释放。现在我将控制器的视图子类化以实现与上面链接中推荐的相同的事情,一切似乎都工作正常。

编辑:经过更多测试后,我可以确认自定义 UIView 已正常释放。

编辑 2:唯一的缺点是您不能让键盘出现在 viewWillAppear 中,inputAccessoryView 尚未添加到视图层次结构中并且不能成为第一响应者。

【讨论】:

  • 哇,让视图成为响应者而不是视图控制器本身的好主意。它解决了释放问题。谢谢!
  • 这是一个很棒的发现,我一直在寻找解决方案。
  • 在 iOS > 7 上 UIViewController 子类工作正常,但是文章中提到的 inputAccessoryView 的内存泄漏仍然发生:(
  • 是的,如果我的回答不是很清楚,很抱歉。我使用返回视图控制器,但我现在将其视图子类化以允许它成为第一响应者
【解决方案2】:

这个问题相当老了,但我在 2019 年尝试在 iOS 12 中使用 inputAccessoryView 时遇到了它。

今天仍然存在释放问题,dvkch's answer 中提到的文章中提出的第一个解决方案也不起作用。文章中的第二个解决方案(涉及动画)只是工作量太大,当用户通过带有scrollView.keyboardDismissMode = .interactive 的 UIScrollView 以交互方式关闭键盘时效果不佳。

我能想到的最佳方法是在viewDidDisappear 上将第一响应者UITextFieldUITextView inputAccessoryView 设置为nil。这完全消除了内存泄漏,并且似乎没有任何副作用或缺点。

这是一个完整的 Swift 4.2 示例:

class MyViewController: UIViewController {
    /// You could also add your text field or text view programmatically, 
    /// but let's say it's coming from a .xib for now...
    @IBOutlet private weak var myTextField: UITextField!

    /// This is required for the inputAccessoryView to work.
    override internal var canBecomeFirstResponder: Bool {
        return true
    }

    /// Here's a nice empty red view that will be used as an
    /// input accessory.
    private lazy var accessoryView: UIView = {
        let accessoryView = UIView()
        accessoryView.backgroundColor = UIColor.red
        accessoryView.frame.size = CGSize(
            width: view.frame.size.width,
            height: 45
        )

        return accessoryView
    } ()

    override var inputAccessoryView: UIView? {
        return accessoryView
    }

    /// This is required to avoid leaking the `inputAccessoryView`
    /// when the keyboard is open and the `UIViewController`
    /// is deallocated.
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        myTextField.inputAccessoryView = nil
    }
}

【讨论】:

  • 我认为这将是最简单的,但可能在确实消失的情况下这样做,因为使用 UINavigationController 的交互式 Pop 手势时可以调用 willDisappear,可以取消。当呈现另一个视图控制器时,视图控制器也可能会消失,因此可以检查presentedViewController == nil
  • @dkvch 哎呀!!你是绝对正确的关于确实消失了!我以为这就是我输入的内容:) 我现在会修复它。谢谢!关于控制器消失,我认为这并不重要,因为inputAccessoryView 将再次被调用。你只需要确保视图在此期间没有被释放(在这个例子中它不是 - 因为在私有惰性 var 中有对它的强引用)。
猜你喜欢
  • 2012-07-23
  • 1970-01-01
  • 1970-01-01
  • 2018-08-27
  • 1970-01-01
  • 1970-01-01
  • 2016-05-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多