关闭模态视图时无法形成对 UIScrollView sub class (EXC_BAD_INSTRUCTION) 的弱引用
Cannot form weak reference to UIScrollView sub class (EXC_BAD_INSTRUCTION) when dismissing modal view
大家好,我调试这个问题已经有一段时间了,但到目前为止还没有成功。我在这里很迷路,不知道导致这次崩溃的原因以及如何解决它。如果有人能为此提供帮助,我将不胜感激,非常感谢!
我准备了一个示例项目来演示 GitHub here 中的问题。
场景如下:
有两个view controller,分别是root view和modal view,各自有一个自定义的scroll view(class即SubScorllView
)作为子view,modal视图有一个用于关闭模态视图的按钮。
滚动视图是 UIScrollView 的子class,每个都有相应的委托协议,它们的 class 层次结构如下:
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文件中加载的,滚动视图的委托也设置在里面,并且有一些关于启动和设置滚动视图子委托的方法的覆盖classes .
当我通过单击模态视图中的 "Close" 按钮关闭模态视图时出现问题,当单击该按钮时,会发生以下情况:
- (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]: Cannot form weak reference to instance (0x7fa803839000) of
class SubScrollView. It is possible that this object was
over-released, or is in the process of deallocation.
我不明白为什么应用程序会崩溃并给出上述错误消息,或者我应该如何解决它。我尝试使用错误消息进行搜索,但似乎该消息主要与文本视图等其他 classes 相关,而其他一些人通过在解除分配之前将滚动视图的委托设置为 nil 来解决它,但它不起作用就我而言。
==========
更新: 刚刚用模拟器测试了这种情况是否发生在 iOS 8 上,它根本不会像在 iOS 9 上那样崩溃。
当 SuperScrollView 被释放时,setDelegate 被隐式调用。在 iOS 9 中,你不能将委托设置为 self,因为 self 正在被释放(不知道为什么这在 iOS 8 中有效)。要解决此问题,您可以先检查传入的委托参数是否不为 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;
}
}
super.delegate = self
,super
这里是UIScrollView
,super.delegate
是UIScrollViewDelegate
类型,self
是[=12类型=],所以你把UIScrollView
的delegate设置成scroll view,这没有意义,通常controller应该是UIScrollView
的delegate。
当您关闭模态视图控制器时,它正处于释放过程中。 super.delegate = self;
,这里self
是一个滚动视图,它是self.view
的子视图,属于模态视图控制器。所以 self
也在解除分配。
我在Swift遇到了同样的问题,cncool的回答帮助了我。
以下(考虑在父 class 的实例中)解决了我的问题:
deinit {
self.scrollView.delegate = nil
}
大家好,我调试这个问题已经有一段时间了,但到目前为止还没有成功。我在这里很迷路,不知道导致这次崩溃的原因以及如何解决它。如果有人能为此提供帮助,我将不胜感激,非常感谢!
我准备了一个示例项目来演示 GitHub here 中的问题。
场景如下:
有两个view controller,分别是root view和modal view,各自有一个自定义的scroll view(class即
SubScorllView
)作为子view,modal视图有一个用于关闭模态视图的按钮。滚动视图是 UIScrollView 的子class,每个都有相应的委托协议,它们的 class 层次结构如下:
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文件中加载的,滚动视图的委托也设置在里面,并且有一些关于启动和设置滚动视图子委托的方法的覆盖classes .
当我通过单击模态视图中的 "Close" 按钮关闭模态视图时出现问题,当单击该按钮时,会发生以下情况:
- (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]: Cannot form weak reference to instance (0x7fa803839000) of class SubScrollView. It is possible that this object was over-released, or is in the process of deallocation.
我不明白为什么应用程序会崩溃并给出上述错误消息,或者我应该如何解决它。我尝试使用错误消息进行搜索,但似乎该消息主要与文本视图等其他 classes 相关,而其他一些人通过在解除分配之前将滚动视图的委托设置为 nil 来解决它,但它不起作用就我而言。
==========
更新: 刚刚用模拟器测试了这种情况是否发生在 iOS 8 上,它根本不会像在 iOS 9 上那样崩溃。
当 SuperScrollView 被释放时,setDelegate 被隐式调用。在 iOS 9 中,你不能将委托设置为 self,因为 self 正在被释放(不知道为什么这在 iOS 8 中有效)。要解决此问题,您可以先检查传入的委托参数是否不为 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;
}
}
super.delegate = self
,super
这里是UIScrollView
,super.delegate
是UIScrollViewDelegate
类型,self
是[=12类型=],所以你把UIScrollView
的delegate设置成scroll view,这没有意义,通常controller应该是UIScrollView
的delegate。
当您关闭模态视图控制器时,它正处于释放过程中。 super.delegate = self;
,这里self
是一个滚动视图,它是self.view
的子视图,属于模态视图控制器。所以 self
也在解除分配。
我在Swift遇到了同样的问题,cncool的回答帮助了我。 以下(考虑在父 class 的实例中)解决了我的问题:
deinit {
self.scrollView.delegate = nil
}