Reputation: 1842
Even though it worked nicely on the simulator, my multiview app crashes on an iPhone 5 C (by ’nicely’, I mean no memory leaks, smooth animation as buttons move into place, etc.). The app is written in Objective C, The simulator runs under Xcode 8.3.3. The phone runs iOS 10.3.3.
The problem happens when I press a sync button that switches from SyncViewController
to PlayViewController
i.e. from VC3 to VC4 after switching successfully from VC1 to VC2 to VC3. Each ViewController
has a delegate method that responds to buttons pressed from within the previous ViewController.
The crash happens consistently in the following method that displays three things in PlayView
: a horizontally scrollable graphic score, a button with a time display that is overwritten every second and a stop button.
- (UIView *)showScoreClockAndExit:(CGRect)panel highlight:(int)currentState seconds:(NSUInteger)clockCount {
if (!self.seconds)
{
[self.seconds removeFromSuperview];
self.seconds = [[ClockButton alloc] loadClockButton:(NSUInteger)clockCount];
[self addSubview:_seconds];
}
ClockButton *seconds = [[ClockButton alloc] loadClockButton:(NSUInteger)clockCount];
[self addSubview:seconds];
EscButton *escape = [[EscButton alloc] loadEscButton:(NSString *)@"stop"];
[self addSubview:escape];
GraphicScore *score = [[GraphicScore alloc] createGraphicScore:(CGRect)panel highlight:(int)currentState];
[self addSubview:score];
return self;
}
What is weird is that the last UIView
previously loaded by SyncViewController
remains frozen on the device itself even though the PlayViewController
has already begun taking over from SyncViewController,
i.e PlayView
is loaded, a UITimer
is set up and the state of play for the selected player is enabled, as the debug log (below) clearly shows
2017-07-24 15:25:24.950097+1000 SatGam2[3052:1712261] PlayView loaded (selectedFamily:1 selectedPlayerID:1)
2017-07-24 15:25:24.950923+1000 SatGam2[3052:1712261] TIME: 00:00
2017-07-24 15:25:24.951905+1000 SatGam2[3052:1712261] ENABLED (player 1: state 0)
(lldb)
Following a helpful lead I found here, I typed : bt
and pressed: Enter to get the following log
SatGam2 was compiled with optimization - stepping may behave oddly; variables may not be available.
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0xe15d25d2)
frame #0: 0x1b300694 libobjc.A.dylib`objc_retain + 4
frame #1: 0x21291d0a UIKit`-[UIView(Hierarchy) addSubview:] + 18
* frame #2: 0x000c2696 SatGam2`-[PlayView showScoreClockAndExit:highlight:seconds:](self=0x15e9ed70, _cmd=<unavailable>, panel=<unavailable>, currentState=<unavailable>, clockCount=<unavailable>) at PlayView.m:215 [opt]
frame #3: 0x000c246c SatGam2`-[PlayView initWithFrame:state:family:player:cue:seconds:](self=<unavailable>, _cmd=<unavailable>, frame=<unavailable>, currentState=<unavailable>, selectedFamily=<unavailable>, selectedPlayerID=<unavailable>, entryString=@"", clockCount=<unavailable>) at PlayView.m:149 [opt]
frame #4: 0x000cd0da SatGam2`-[PlayViewController nextState](self=0x168aae00, _cmd=<unavailable>) at PlayViewController.m:244 [opt]
frame #5: 0x000ccc40 SatGam2`-[PlayViewController viewDidLoad](self=0x168aae00, _cmd=<unavailable>) at PlayViewController.m:152 [opt]
frame #6: 0x2128b27e UIKit`-[UIViewController loadViewIfRequired] + 966
frame #7: 0x2128aea0 UIKit`-[UIViewController view] + 22
frame #8: 0x000c1266 SatGam2`-[MultiviewViewController displayView:](self=0x15d85710, _cmd=<unavailable>, intNewView=4) at MultiviewViewController.m:45 [opt]
frame #9: 0x000c2fb6 SatGam2`-[SyncViewController fromSyncButton:](self=<unavailable>, _cmd=<unavailable>, button=<unavailable>) at SyncViewController.m:65 [opt]
frame #10: 0x212bf784 UIKit`-[UIApplication sendAction:to:from:forEvent:] + 76
frame #11: 0x212bf718 UIKit`-[UIControl sendAction:to:forEvent:] + 62
frame #12: 0x212a9d48 UIKit`-[UIControl _sendActionsForEvents:withEvent:] + 478
frame #13: 0x212bf054 UIKit`-[UIControl touchesEnded:withEvent:] + 604
frame #14: 0x212beb9e UIKit`-[UIWindow _sendTouchesForEvent:] + 2094
frame #15: 0x212b9ade UIKit`-[UIWindow sendEvent:] + 2798
frame #16: 0x2128b682 UIKit`-[UIApplication sendEvent:] + 308
frame #17: 0x21a1ede6 UIKit`__dispatchPreprocessedEventFromEventQueue + 2254
frame #18: 0x21a1978a UIKit`__handleEventQueue + 4186
frame #19: 0x21a19b6c UIKit`__handleHIDEventFetcherDrain + 144
frame #20: 0x1c01bfdc CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 12
frame #21: 0x1c01bb04 CoreFoundation`__CFRunLoopDoSources0 + 424
frame #22: 0x1c019f50 CoreFoundation`__CFRunLoopRun + 1160
frame #23: 0x1bf6d1ae CoreFoundation`CFRunLoopRunSpecific + 470
frame #24: 0x1bf6cfd0 CoreFoundation`CFRunLoopRunInMode + 104
frame #25: 0x1d717b40 GraphicsServices`GSEventRunModal + 80
frame #26: 0x212eee12 UIKit`UIApplicationMain + 150
frame #27: 0x1b75a4ea libdyld.dylib`start + 2
(lldb)
I cleared all apps previously tested on the phone. I also tried a version of the app backed up last month to eliminate any problems I may have introduced since I began working on deviceMotion
. But the problem remains the same.
Has anyone seen something like this ? Where would I begin ? e.g. like where would I put a breakpoint ?
Upvotes: 0
Views: 315
Reputation: 7588
This checking is incorrect.
if (!self.seconds)
{
[self.seconds removeFromSuperview];
self.seconds = [[ClockButton alloc] loadClockButton:(NSUInteger)clockCount];
[self addSubview:_seconds];
}
!self.seconds could be used if it is a boolean. In this case it seems self.seconds is some sort of a view. So what you should do is:
if (self.seconds!=nil) {
[self.seconds removeFromSuperView];
self.seconds = [[ClockButton alloc] loadClockButton:(NSUInteger)clockCount];
[self addSubview:_seconds];
}
Upvotes: 1