大家好我已经调试了这个问题很长一段时间但到目前为止没有运气。我在这里迷失了,并且不知道造成这次崩溃的原因以及如何解决它。如果有人能为我提供一些帮助,我将非常感激,非常感谢!
我准备了一个示例项目来展示GitHub here处的问题。
方案如下:
有两个视图控制器,即根视图和模态视图,每个都有一个自定义滚动视图(类SubScorllView
)作为子视图,模态视图有一个用于解除模态的按钮图。
滚动视图是UIScrollView的子类,每个子类都有相应的委托协议,其类层次结构如下:
的UIScrollView
∟SuperScrollView
.....∟SubScrollView
App在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)的弱引用 class SubScrollView。这个对象可能是 过度释放,或正在解除分配。
我不明白为什么应用会崩溃并提供上述错误消息,或者我应该如何解决它。我尝试使用错误消息进行搜索,但似乎该消息主要与其他类(如文本视图)相关,而其他一些消息则通过在解除分配之前将滚动视图的委托设置为nil来解决它,但在我的情况下它不起作用。 / p>
==========
更新:刚刚测试过iOS 8上是否有模拟器,它就不会像在iOS 9上那样崩溃。
答案 0 :(得分:5)
取消分配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;
}
}
答案 1 :(得分:0)
super.delegate = self
,super
此处为UIScrollView
,super.delegate
的类型为UIScrollViewDelegate
,self
的类型为UIScrollView
,所以你将UIScrollView
的委托设置为滚动视图,这没有意义,通常控制器应该是UIScrollView
的委托。
当你关闭模态视图控制器时,它正处于释放过程中。 super.delegate = self;
,此处self
是滚动视图,它是self.view
的子视图,属于模态视图控制器。所以self
也在解除分配。
答案 2 :(得分:0)
我在 Swift 中遇到了同样的问题,cncool的回答帮助了我。 以下内容(考虑在父类的实例中)解决了我的问题:
deinit {
self.scrollView.delegate = nil
}