2017-02-21 99 views
0

我正在制作一个球程序,您可以在长按手势上将球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> 
+0

如果你想要别人了解你的问题,请不要发布无关的代码(例如'updateView','didReceiveMemoryWarning')。找出问题发生的最小代码量也可能帮助您深入了解根本原因。如果删除'physics'方法或'ballDragged'方法(或其中的一部分),问题是否仍然存在?如果不是,请不要包含它们。 –

+0

改进,但设置球颜色等影响行为?如果不是,请删除这些方法。删除与手头问题无关的任何属性。继续下去,直到你有最低限度的代码显示问题。您可能会发现自己创建一个新的临时项目用于调查此问题很有用。 –

回答

1

当你双击一个“球”,你从删除其观点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; 
    } 
} 
+0

谢谢。我实际上尝试使用'_orangeBall = nil',但没有if条件,它没有帮助,但是这很好。我的代码需要很多重构,但我的主要目标是现在的功能。 Objective-C仍然是新的。谢谢您的帮助! –