iOS - 删除所有子视图后重新添加子视图
我正在制作一个球程序,您可以在长按手势上将球UIView子视图添加到超级视图。点击视图将其从超级视图中移除。iOS - 删除所有子视图后重新添加子视图
添加所有视图的效果很好,重新添加视图可以正常工作,因为至少有一个视图留在超级视图中。但是,一旦所有子视图都被删除,长按就应该重新添加第一个子视图,但是程序会关闭。
我只在其中一个线程中得到释放消息,导致我相信这是一个alloc/dealloc问题,但ARC禁止我明确释放视图,并且我认为[removeFromSuperview]
无论如何都会这样做。
我不确定我错过了什么。点击后感兴趣的特定方法是tapped:
和createBall
:已在所有子视图上使用。
ViewController.m
#import "ViewController.h"
#import <QuartzCore/QuartzCore.h>
@interface ViewController()
@property (nonatomic, strong) UILongPressGestureRecognizer *longPressRecog;
@property (nonatomic, strong) UIPanGestureRecognizer *panRecog;
@property (nonatomic, strong) UITapGestureRecognizer *tapRecog;
@property (nonatomic, strong) UIDynamicAnimator *anim;
@property (nonatomic, strong) NSTimer* timer;
@property (nonatomic, strong) UIView *orangeBall, *blueBall;
@property (nonatomic) CGPoint ballCenter;
@property (nonatomic, strong) NSMutableArray* ballsArray;
@property (nonatomic, assign) CGRect originalBounds;
@property (nonatomic) UIAttachmentBehavior *attachmentBehavior;
@property (nonatomic) UIPushBehavior *pushBehavior;
@property (nonatomic) UIDynamicItemBehavior *ballPhysics;
@property (nonatomic) UICollisionBehavior *collisionBehavior;
-(void)physics;
-(void)createBall;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Prepare to handle Long Press to create ball object
self.longPressRecog = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
self.longPressRecog.minimumPressDuration = 0.8f;
[self.longPressRecog setDelegate:self];
[self.view addGestureRecognizer:self.longPressRecog];
}
// Handles Long Presses and creates a ball within the view
- (void)longPress:(UILongPressGestureRecognizer *)sender {
if ([sender isEqual:self.longPressRecog]) {
if (sender.state == UIGestureRecognizerStateEnded) {
[self createBall];
}
}
}
// Set Ball Attributes
- (void)setOrangeBall {
if (self.viewLoaded) {
// Load ball view to screen
self.orangeBall = [[UIView alloc] initWithFrame:CGRectMake(100.0, 100.0, 50.0, 50.0)];
self.orangeBall.layer.cornerRadius = 25.0;
self.orangeBall.backgroundColor = [UIColor orangeColor];
self.orangeBall.layer.borderColor = [UIColor orangeColor].CGColor;
self.orangeBall.layer.borderWidth = 0.0;
[self.view addSubview:self.orangeBall];
} else {
}
}
- (void)setBlueBall {
// Load ball view to screen
self.blueBall = [[UIView alloc] initWithFrame:CGRectMake(160.0, 160.0, 50.0, 50.0)];
self.blueBall.layer.cornerRadius = 25.0;
self.blueBall.backgroundColor = [UIColor blueColor];
self.blueBall.layer.borderColor = [UIColor blueColor].CGColor;
self.blueBall.layer.borderWidth = 0.0;
[self.view addSubview:self.blueBall];
}
// Create Balls
- (void)createBall {
if (![_orangeBall superview] && ![_blueBall superview]) {
[self setOrangeBall];
} else if ([_orangeBall superview] && ![_blueBall superview]) {
[self setBlueBall];
} else {
// NOTHING
}
// Begin animations
self.anim = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
// Init Physics
[self physics];
}
// Gravity
- (void)physics {
//Add ball objects to NSMutableArray. Needed in order to add behaviors to all ball objects.
self.ballsArray = [NSMutableArray arrayWithObjects:self.orangeBall, self.blueBall, nil];
//Tapping Behavior
_tapRecog.delegate = self;
for (UIView *ball in _ballsArray) {
ball.userInteractionEnabled = YES;
_tapRecog = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
[_tapRecog setNumberOfTapsRequired:2];
[ball addGestureRecognizer:_tapRecog];
}
}
- (void)tapped:(UITapGestureRecognizer *)recognizer {
//Delete tapped ball
[recognizer.view willRemoveSubview:recognizer.view];
[recognizer.view removeFromSuperview];
}
@end
这里的一切我真的可以从线程错误发现:
UIKit`UIApplicationMain:
0x10acd4bc9 <+0>: pushq %rbp
0x10acd4bca <+1>: movq %rsp, %rbp
0x10acd4bcd <+4>: pushq %r15
0x10acd4bcf <+6>: pushq %r14
0x10acd4bd1 <+8>: pushq %r13
0x10acd4bd3 <+10>: pushq %r12
0x10acd4bd5 <+12>: pushq %rbx
0x10acd4bd6 <+13>: pushq %rax
0x10acd4bd7 <+14>: movq %rcx, %rbx
0x10acd4bda <+17>: movq %rsi, -0x30(%rbp)
0x10acd4bde <+21>: movl %edi, %r12d
0x10acd4be1 <+24>: movq 0xe7f7b8(%rip), %r13 ; (void *)0x0000000109c12cb0: objc_retain
0x10acd4be8 <+31>: movq %rdx, %rdi
0x10acd4beb <+34>: callq *%r13
0x10acd4bee <+37>: movq %rax, %r14
0x10acd4bf1 <+40>: movq %rbx, %rdi
0x10acd4bf4 <+43>: callq *%r13
0x10acd4bf7 <+46>: movq %rax, %r15
0x10acd4bfa <+49>: leaq 0x11dab6b(%rip), %r13 ; _UIApplicationLinkedOnVersion
0x10acd4c01 <+56>: movl (%r13), %eax
0x10acd4c05 <+60>: testl %eax, %eax
0x10acd4c07 <+62>: jne 0x10acd4c17 ; <+78>
0x10acd4c09 <+64>: cmpq $-0x1, 0x11d4ab7(%rip) ; WebKitSetIsClassic + 7
0x10acd4c11 <+72>: jne 0x10acd4c8a ; <+193>
0x10acd4c13 <+74>: movl (%r13), %eax
0x10acd4c17 <+78>: cmpl $0x20100, %eax ; imm = 0x20100
0x10acd4c1c <+83>: jb 0x10acd4c42 ; <+121>
0x10acd4c1e <+85>: callq 0x10b8f8a8a ; symbol stub for: objc_autoreleasePoolPush
0x10acd4c23 <+90>: movq %rax, %r13
0x10acd4c26 <+93>: movl %r12d, %edi
0x10acd4c29 <+96>: movq -0x30(%rbp), %rsi
0x10acd4c2d <+100>: movq %r14, %rdx
0x10acd4c30 <+103>: movq %r15, %rcx
0x10acd4c33 <+106>: callq 0x10acd4ca2 ; _UIApplicationMainPreparations
0x10acd4c38 <+111>: movq %r13, %rdi
0x10acd4c3b <+114>: callq 0x10b8f8a84 ; symbol stub for: objc_autoreleasePoolPop
0x10acd4c40 <+119>: jmp 0x10acd4c54 ; <+139>
0x10acd4c42 <+121>: movl %r12d, %edi
0x10acd4c45 <+124>: movq -0x30(%rbp), %rsi
0x10acd4c49 <+128>: movq %r14, %rdx
0x10acd4c4c <+131>: movq %r15, %rcx
0x10acd4c4f <+134>: callq 0x10acd4ca2 ; _UIApplicationMainPreparations
0x10acd4c54 <+139>: movq 0x11daa55(%rip), %rdi ; UIApp
0x10acd4c5b <+146>: movq 0x11489d6(%rip), %rsi ; "_run"
0x10acd4c62 <+153>: callq *0xe7f728(%rip) ; (void *)0x0000000109c15ac0: objc_msgSend
0x10acd4c68 <+159>: movq 0xe7f729(%rip), %rbx ; (void *)0x0000000109c12d20: objc_release
0x10acd4c6f <+166>: movq %r15, %rdi
0x10acd4c72 <+169>: callq *%rbx
0x10acd4c74 <+171>: movq %r14, %rdi
0x10acd4c77 <+174>: callq *%rbx
0x10acd4c79 <+176>: xorl %eax, %eax
0x10acd4c7b <+178>: addq $0x8, %rsp
0x10acd4c7f <+182>: popq %rbx
0x10acd4c80 <+183>: popq %r12
0x10acd4c82 <+185>: popq %r13
0x10acd4c84 <+187>: popq %r14
0x10acd4c86 <+189>: popq %r15
0x10acd4c88 <+191>: popq %rbp
0x10acd4c89 <+192>: retq
0x10acd4c8a <+193>: leaq 0x11d4a37(%rip), %rdi ; _UIApplicationLinkedOnVersionOnce
0x10acd4c91 <+200>: leaq 0xe82d08(%rip), %rsi ; __block_literal_global.1554
0x10acd4c98 <+207>: callq 0x10b8f92d6 ; symbol stub for: dispatch_once
0x10acd4c9d <+212>: jmp 0x10acd4c13 ; <+74>
当你双击一个“球”,你从删除其观点superview:
- (void)tapped:(UITapGestureRecognizer *)recognizer {
//Delete tapped ball
[recognizer.view willRemoveSubview:recognizer.view];
[recognizer.view removeFromSuperview];
}
但是,那个“球”仍然存在TS。在下一个长按,你的代码跳过创建球(因为它们都存在),但在球创建方法是你将它们添加到主视图。当您的代码落入物理方法时,您尝试将冲突行为添加到不在层次结构中的视图。
你应该删除你的“球”(将它们设置为零),当你从他们的superViews中删除它们,或者在下一次重新添加它们作为子视图时。
这是一个办法,虽然不是最好的...
- (void)tapped:(UITapGestureRecognizer *)recognizer {
//Delete tapped ball
[recognizer.view willRemoveSubview:recognizer.view];
[recognizer.view removeFromSuperview];
if (recognizer.view == _blueBall) {
_blueBall = nil;
} else if (recognizer.view == _orangeBall) {
_orangeBall = nil;
}
}
谢谢。我实际上尝试使用'_orangeBall = nil',但没有if条件,它没有帮助,但是这很好。我的代码需要很多重构,但我的主要目标是现在的功能。 Objective-C仍然是新的。谢谢您的帮助! –
如果你想要别人了解你的问题,请不要发布无关的代码(例如'updateView','didReceiveMemoryWarning')。找出问题发生的最小代码量也可能帮助您深入了解根本原因。如果删除'physics'方法或'ballDragged'方法(或其中的一部分),问题是否仍然存在?如果不是,请不要包含它们。 –
改进,但设置球颜色等影响行为?如果不是,请删除这些方法。删除与手头问题无关的任何属性。继续下去,直到你有最低限度的代码显示问题。您可能会发现自己创建一个新的临时项目用于调查此问题很有用。 –