【问题标题】:Cannot form weak reference to UIScrollView sub class (EXC_BAD_INSTRUCTION) when dismissing modal view关闭模式视图时无法形成对 UIScrollView 子类 (EXC_BAD_INSTRUCTION) 的弱引用
【发布时间】:2016-03-15 03:35:11
【问题描述】:

大家好,我已经调试这个问题很长一段时间了,但到目前为止还没有运气。我在这里很迷茫,不知道导致此崩溃的原因以及如何修复它。如果有人能在这方面给我一些帮助,我将非常感激,非常感谢!

我在GitHub here 准备了一个示例项目来演示该问题。

场景如下:

  1. 有两个视图控制器,分别是根视图和模态视图,每个都有一个自定义滚动视图(类即SubScorllView)作为子视图,模态视图有一个关闭模态视图的按钮。

  2. 滚动视图是UIScrollView的子类,每个子类都有对应的委托协议,类层次如下:

UIScrollView
∟ SuperScrollView
.....∟ SubScrollView

应用以非常简单的方式启动和运行,在 AppDelegate 的 didFinishLaunchingWithOptions 中:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.backgroundColor = [UIColor blackColor];

    RootViewController * rootVC = [[RootViewController alloc] init];
    self.navVC = [[UINavigationController alloc] initWithRootViewController:rootVC];
    self.navVC.navigationBarHidden = TRUE;

    self.window.rootViewController = self.navVC;
    [self.window makeKeyAndVisible];

    ModalViewController *modalVC = [[ModalViewController alloc] init];
    [self.navVC presentViewController:modalVC animated:YES completion:nil];

    return YES;
}

并且视图是从 xib 文件中加载的,滚动视图的委托也在其中设置,并且对于滚动视图子类的启动和设置委托的方法有一些覆盖。

当我通过单击模态视图中的“关闭”按钮关闭模态视图时出现问题,当单击该按钮时,会发生以下情况:

- (IBAction)didPressedCloseButton:(id)sender {

    self.subScrollView.delegate = nil;
    [self dismissViewControllerAnimated:YES completion:nil];

}

应用程序在SuperScrollView 中的以下部分崩溃:

- (void)setDelegate:(id<SuperScrollViewDelegate>)delegate {

    _superScrollViewDelegate = delegate;

    // trigger UIScrollView to re-examine delegate for selectors it responds
    super.delegate = nil;
    super.delegate = self;  // app crashes at this line
}

在控制台中出现以下错误消息:

objc[6745]: 无法形成对实例 (0x7fa803839000) 的弱引用 类子滚动视图。这个物体可能是 过度释放,或正在释放。

我不明白为什么应用程序会崩溃并给出上述错误消息,或者我应该如何修复它。我尝试使用错误消息进行搜索,但似乎该消息主要与文本视图等其他类有关,而其他一些则通过在解除分配之前将滚动视图的委托设置为 nil 来解决它,但它在我的情况下不起作用。

===========

更新:刚刚测试了这是否发生在带有模拟器的 iOS 8 上,它根本不会像在 iOS 9 上那样崩溃。

【问题讨论】:

标签: ios objective-c uiscrollview uiscrollviewdelegate


【解决方案1】:

当 SuperScrollView 被释放时,setDelegate 被隐式调用。在 iOS 9 中,您不能将委托设置为 self,因为 self 正在被释放(不知道为什么这在 iOS 8 中有效)。要解决这个问题,可以先检查传入的delegate参数是否不为nil,然后才将super.delegate设置为self:

- (void)setDelegate:(id<SuperScrollViewDelegate>)delegate {

    _superScrollViewDelegate = delegate;

    // trigger UIScrollView to re-examine delegate for selectors it responds
    super.delegate = nil;

    if(delegate)
    {
        super.delegate = self;
    }
}

如果出于某种原因您需要支持对 UIScrollView 委托方法的自我响应,即使 _superScrollViewDelegate 为 nil,您也可以创建一个参数

@interface SuperScrollView ()

@property (nonatomic, weak) SuperScrollView * weakSelf;

@end

在文件顶部,并在设置中设置

- (void)setup {

    super.delegate = self;
    self.weakSelf = self;
}

然后,在 setDelegate 中,只需检查weakSelf 是否为nil。如果weakSelf 为nil,则self 正在解除分配过程中,您不应将其设置为super.delegate:

- (void)setDelegate:(id<SuperScrollViewDelegate>)delegate {

    _superScrollViewDelegate = delegate;

    // trigger UIScrollView to re-examine delegate for selectors it responds
    super.delegate = nil;

    if(self.weakSelf)
    {
        super.delegate = self;
    }
} 

【讨论】:

  • 非常感谢!很长一段时间以来,我一直在尝试调试和解决这个问题。按照您的建议进行了一些更改,并且运行良好。
  • 关于它为什么在 iOS 8 上运行,我不确定这是否是原因,但在我寻找解决方案的过程中,我发现这个主题表明 Apple 对 UIScrollView 的委托进行了一些更改,但是他的解决方案似乎没有解决我的问题。这是链接:forums.developer.apple.com/thread/19027
  • 非常感谢!我花了两个小时来处理一个神秘的 iOS 9 崩溃,直到我看到这个。
【解决方案2】:

super.delegate = self ,super 这里是 UIScrollViewsuper.delegateUIScrollViewDelegate 类型,selfUIScrollView 类型,所以您将 UIScrollView 的委托设置为滚动视图,没有意义,通常控制器应该是UIScrollView的代表。

当您关闭模态视图控制器时,它处于释放过程中。 super.delegate = self;,这里self 是一个滚动视图,它是self.view 的子视图,属于模态视图控制器。所以self 也在解除分配。

【讨论】:

    【解决方案3】:

    我在 Swift 中遇到了同样的问题,cncool 的回答帮助了我。 以下(考虑在父类的实例中)解决了我的问题:

    deinit {
        self.scrollView.delegate = nil
    }
    

    【讨论】:

      猜你喜欢
      • 2017-12-17
      • 2014-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-31
      • 2020-08-01
      • 2013-10-26
      相关资源
      最近更新 更多