ala*_*nlo 0 objective-c uiscrollview uiscrollviewdelegate ios
大家好,我已经调试了这个问题很长一段时间但到目前为止没有运气.我在这里迷失了,并且不知道造成这次崩溃的原因以及如何解决它.如果有人能为我提供一些帮助,我将非常感激,非常感谢!
我准备了一个示例项目来在GitHub上演示这个问题.
方案如下:
有两个视图控制器,即根视图和模态视图,每个视图控制器都有一个自定义滚动视图(即类SubScorllView)作为子视图,模态视图有一个用于关闭模态视图的按钮.
滚动视图是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;
}
Run Code Online (Sandbox Code Playgroud)
并且视图是从xib文件加载的,滚动视图的委托也在其中设置,并且有一些关于启动和设置滚动视图子类的委托的方法的覆盖.
当我通过单击模态视图中的"关闭"按钮关闭模态视图时出现问题,单击该按钮时,会发生以下情况:
- (IBAction)didPressedCloseButton:(id)sender {
self.subScrollView.delegate = nil;
[self dismissViewControllerAnimated:YES completion:nil];
}
Run Code Online (Sandbox Code Playgroud)
该应用程序崩溃在以下部分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
}
Run Code Online (Sandbox Code Playgroud)
控制台中出现以下错误消息:
objc [6745]:无法形成类SubScrollView的实例(0x7fa803839000)的弱引用.该对象可能被过度释放,或者正在解除分配.
我不明白为什么应用程序会崩溃并给出上述错误消息,或者我应该如何解决它.我尝试使用错误消息进行搜索,但似乎该消息主要与其他类(如文本视图)相关,而其他一些消息则通过在解除分配之前将滚动视图的委托设置为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;
}
}
Run Code Online (Sandbox Code Playgroud)
如果由于某种原因你需要支持自我响应UIScrollView委托方法,即使_superScrollViewDelegate为nil,你也可以创建一个参数
@interface SuperScrollView ()
@property (nonatomic, weak) SuperScrollView * weakSelf;
@end
Run Code Online (Sandbox Code Playgroud)
在文件的顶部,并将其设置为安装程序
- (void)setup {
super.delegate = self;
self.weakSelf = self;
}
Run Code Online (Sandbox Code Playgroud)
然后,在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;
}
}
Run Code Online (Sandbox Code Playgroud)