I have the following code in class A:
UIViewController *vc = [self viewControllerForItem:item];
where the viewControllerForItem method in my app delegate returns a UIViewController based on my item i.e.
vc = [[[MyCustomViewController alloc] init] autorelease];
return vc;
I then push the view controller:
[self.navigationController pushViewController:vc animated:YES];
This VC i'm trying to push is a MKMapView and I inserted a log statement in the dealloc method to see if it's being called. In my memory usage, the growth is increasing pretty rapidly.
However, when I add the following code after pushing the VC:
[vc release];
my MKMapView class calls the dealloc method.
Of course this would be a simple solution if the MKMapView class was the only class returned by my app delegate (or I could just check if the VC's class is my MKMapView class). However, I would like to solve the root problem of this.
Why is the dealloc not being called if I set autorelease on my view controller?
How is it possible that I can add [vc release] to the view controller even though autorelease is used on that vc?
Thanks
Edit:
Here's some additional info. I have the viewControllerForItem class in my app delegate. I'm returning the auto released object into my other manager class where I then push the view controller. Is the retain count being messed up when I return an autoreleased object, and then push it in some other class?
This is the backtrace / callstack right when I push the VC and when the mkmapview's didDissappear is called:
pushVC: (
0 NewHampshire 0x00254cdf -[CustomViewController navigateToRowId:withLinkBehavior:animated:] + 2111
1 NewHampshire 0x002534c9 -[CustomViewController webView:shouldStartLoadWithRequest:navigationType:] + 841
2 UIKit 0x02caf288 -[UIWebView webView:decidePolicyForNavigationAction:request:frame:decisionListener:] + 318
3 UIKit 0x02cb1854 -[UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:] + 77
4 CoreFoundation 0x05d0bd1d __invoking___ + 29
5 CoreFoundation 0x05d0bc2a -[NSInvocation invoke] + 362
6 CoreFoundation 0x05d0bdaa -[NSInvocation invokeWithTarget:] + 74
7 WebKit 0x0a4d811d -[_WebSafeForwarder forwardInvocation:] + 157
8 CoreFoundation 0x05d076da ___forwarding___ + 458
9 CoreFoundation 0x05d074ee _CF_forwarding_prep_0 + 14
10 CoreFoundation 0x05d0bd1d __invoking___ + 29
11 CoreFoundation 0x05d0bc2a -[NSInvocation invoke] + 362
12 WebCore 0x09533b29 _ZL20HandleDelegateSourcePv + 121
13 CoreFoundation 0x05ca083f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
14 CoreFoundation 0x05ca01cb __CFRunLoopDoSources0 + 235
15 CoreFoundation 0x05cbd29e __CFRunLoopRun + 910
16 CoreFoundation 0x05cbcac3 CFRunLoopRunSpecific + 467
17 CoreFoundation 0x05cbc8db CFRunLoopRunInMode + 123
18 GraphicsServices 0x059749e2 GSEventRunModal + 192
19 GraphicsServices 0x05974809 GSEventRun + 104
20 UIKit 0x02a6ed3b UIApplicationMain + 1225
21 NewHampshire 0x000150dd main + 125
22 libdyld.dylib 0x04fab70d start + 1
)
disappear: (
0 NewHampshire 0x0014631d -[CustomAdvancedGPSMapViewController viewDidDisappear:] + 173
1 UIKit 0x02b85bac -[UIViewController _setViewAppearState:isAnimating:] + 341
2 UIKit 0x02b86328 -[UIViewController __viewDidDisappear:] + 150
3 UIKit 0x02b86461 -[UIViewController _endAppearanceTransition:] + 306
4 UIKit 0x02ba549a -[UINavigationController navigationTransitionView:didEndTransition:fromView:toView:] + 738
5 UIKit 0x02b9d403 __49-[UINavigationController _startCustomTransition:]_block_invoke + 206
6 UIKit 0x03176740 -[_UIViewControllerTransitionContext completeTransition:] + 99
7 UIKit 0x02a63454 __53-[_UINavigationParallaxTransition animateTransition:]_block_invoke105 + 680
8 UIKit 0x02ad1005 -[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 306
9 UIKit 0x02abac6c -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 267
10 UIKit 0x02abaf58 -[UIViewAnimationState animationDidStop:finished:] + 80
11 QuartzCore 0x028b2a44 _ZN2CA5Layer23run_animation_callbacksEPv + 304
12 libdispatch.dylib 0x04d194b0 _dispatch_client_callout + 14
13 libdispatch.dylib 0x04d0775e _dispatch_main_queue_callback_4CF + 340
14 CoreFoundation 0x05d7ca5e __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 14
15 CoreFoundation 0x05cbd6bb __CFRunLoopRun + 1963
16 CoreFoundation 0x05cbcac3 CFRunLoopRunSpecific + 467
17 CoreFoundation 0x05cbc8db CFRunLoopRunInMode + 123
18 GraphicsServices 0x059749e2 GSEventRunModal + 192
19 GraphicsServices 0x05974809 GSEventRun + 104
20 UIKit 0x02a6ed3b UIApplicationMain + 1225
21 NewHampshire 0x0001507d main + 125
22 libdyld.dylib 0x04fab70d start + 1
)
Solution: Although the responses in this post didn't provide the exact solution to my problem, Darren definitely steered me into the correct direction using the instruments tool. I found the culprit to be a CABasicAnimation object that was not being properly released.
in the viewWillDisappear method, I added the following for the CABasicAnimation object:
self.rotationAnimation.delegate = nil;
self.rotationAnimation = nil;
Use Instruments to track the retain/release history of CustomAdvancedGPSMapViewController and/or MKMapView :
In Xcode, select "Product > Profile" from the menu.
When Instruments starts, select the "Allocations" template.
If your app starts automatically, click the "Stop" button to stop it.
Click the "i" button on the Allocations instrument, and check "Record reference counts".
Select "View > Extended Detail" from the menu.
Click the "Record" button to start your app, and wait for your app to start in the simulator.
In the simulator, use your app to navigate to the CustomAdvancedGPSMapViewController.
In Instruments, click the "Pause" button
Use the search field in the top-right of the window and search for CustomAdvancedGPSMapViewController. CustomAdvancedGPSMapViewController should appear in the Allocation Summary list.
In the Allocation Summary list, Click the -> arrow next to the CustomAdvancedGPSMapViewController name. This should show that you have one instance of CustomAdvancedGPSMapViewController active in your app.
Click the -> arrow next to address. This will display the retain/release history for this CustomAdvancedGPSMapViewController instance.
Un-pause Instruments, return to the simulator, and dismiss your CustomAdvancedGPSMapViewController and return to the point where you believe the controller should be deallocated.
Return to Instruments, click "Pause" again, and look at the updated retain/release history.
The first event in the retain/release history should be "malloc". Select this row and the Extended Detail view in the right side of the window will display the stack trace for this allocation. You should see your own code in the stack trace. Double-click your code in the stack trace and you should see your line of code that allocated the the CustomAdvancedGPSMapViewController instance.
Above the code view, click the "History" tab to return to the history list.
The last event in the retain/release history should be "free". If that's not the case there may be a leak. Inspect the retain/release history and look for an unmatched retain. There may be a lot of noise, related to CoreAnimation, etc. Look for events in which your code appears in the stack trace.
Compare the retain/release history with a different view controller that is not leaking.
If CustomAdvancedGPSMapViewController isn't leaking, try inspecting the history of MKMapView.
The code which you have written is correct and you should not be releasing vc since it is been autoreleased already.
-(UIViewController *) viewControllerForItem: (Item*)item
{
/* create controller for the item --
* alloc init with increase the retain count of your object by 1
* autorelease will reduce the retain count of the object by 1
*/
return [[[MyCustomViewController alloc] init] autorelease];
}
UIViewController *vc = [self viewControllerForItem:item];
[self.NavigationController pushViewController:vc];
You cannot release 'vc' since you dont own it, in the sense you have not done 'alloc init' or 'retain' for it.
I have faced issues with Mapview's not releasing the memory even after getting released. It seems to be an apple bug and this memory will be destroyed only when you get a memory warning for mapview. But you can force the release by doing a hack.
Changing the mapType appears to release the memory the mapview is holding. So try resetting the mapType just before the release of the mapview object in mapviewcontroller. You can see the memory going down just after that statement is executed.
- (void)dealloc
{
// this is a trick for releasing memory
__mapView.mapType = MKMapTypeStandard;
[__mapView removeFromSuperview];
__mapView.delegate = nil;
[__mapview release];
[super dealloc];
}
Hope it helps.
Related
In my iPhone app, for some users the app will always crash, whenever they open a certain window. The same window works fine for me and other people, but always causes a crash for some people. It is unclear at this moment what the difference is between people for whom it fails, and for whom it works fine.
The animation to open the specific view will run fine, but will then cause a crash immediately after the animation is finished.
They have sent me the crashlog, but it is hard to understand what is exactly going wrong. I am hoping you can help me understand. The cause for the failure as given by the crashlog is the following exception:
Last Exception Backtrace:
0 CoreFoundation 0x1836ffd38 __exceptionPreprocess + 124
1 libobjc.A.dylib 0x182c14528 objc_exception_throw + 55
2 CoreFoundation 0x18370d1f8 -[NSObject+ 1372664 (NSObject) doesNotRecognizeSelector:] + 139
3 UIKit 0x18cec7cc4 -[UIResponder doesNotRecognizeSelector:] + 295
4 CoreFoundation 0x1837056e4 ___forwarding___ + 1379
5 CoreFoundation 0x1835eb0dc _CF_forwarding_prep_0 + 91
6 CoreFoundation 0x1835d6be8 CFStringAppend + 519
7 CoreFoundation 0x1836bddf0 __CFStringAppendFormatCore + 9271
8 CoreFoundation 0x1836bf658 _CFStringCreateWithFormatAndArgumentsAux2 + 131
9 AccessibilityUtilities 0x192d6b388 _AXStringForArgs + 279
10 UIKit 0x1a242adf8 -[UIViewControllerAccessibility viewDidAppear:] + 267
11 UIKit 0x18cb2869c -[UIViewController _setViewAppearState:isAnimating:] + 851
12 UIKit 0x18cb28c08 -[UIViewController _endAppearanceTransition:] + 227
13 UIKit 0x18cbcee00 -[UINavigationController navigationTransitionView:didEndTransition:fromView:toView:] + 1327
14 UIKit 0x1a2440cd4 -[UINavigationControllerAccessibility navigationTransitionView:didEndTransition:fromView:toView:] + 111
15 UIKit 0x18cc96bbc __49-[UINavigationController _startCustomTransition:]_block_invoke + 251
16 UIKit 0x18cc229d8 -[_UIViewControllerTransitionContext completeTransition:] + 115
17 UIKit 0x18cd67d30 __53-[_UINavigationParallaxTransition animateTransition:]_block_invoke.124 + 751
18 UIKit 0x18cb47d7c -[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 763
19 UIKit 0x18cb4770c -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 311
20 UIKit 0x18cb47418 -[UIViewAnimationState animationDidStop:finished:] + 295
21 UIKit 0x1a2468970 -[UIViewAnimationStateAccessibility animationDidStop:finished:] + 131
22 QuartzCore 0x1876ebd6c CA::Layer::run_animation_callbacks+ 1232236 (void*) + 283
23 libdispatch.dylib 0x183085048 _dispatch_client_callout + 15
24 libdispatch.dylib 0x183091b74 _dispatch_main_queue_callback_4CF$VARIANT$mp + 1015
25 CoreFoundation 0x1836a7f20 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 11
26 CoreFoundation 0x1836a5afc __CFRunLoopRun + 2011
27 CoreFoundation 0x1835c62d8 CFRunLoopRunSpecific + 435
28 GraphicsServices 0x185457f84 GSEventRunModal + 99
29 UIKit 0x18cb73880 UIApplicationMain + 207
30 Flyskyhy 0x10490bd80 main + 32128 (main.m:17)
31 libdyld.dylib 0x1830ea56c start + 3
The crashlog seems to indicate that it goes wrong while doing a CFStringAppend, but it is not clear which string is the problem, or what is wrong with it, or even why a CFStringAppend is needed. All strings visible in the view have been filled in already before the animation starts, and they all are correct.
EDIT:
As requested, here is the code that starts the view. Everything is under a NavigationController, so the new view controller is pushed on the navigation stack to open it.
WaypointEditController *controller = [[WaypointEditController alloc] initWithNibName:#"WayPointEdit" bundle:nil];
controller.navigationItem.title = #"New Waypoint";
// initialisation of other, custom, fields of controller
[self.navigationController pushViewController:controller animated:YES];
The WaypointEditController class that is pushed is derived from UIViewController. The viewWillAppear is overridden, to do initialisation of the fields of the view. But - relevant here - viewDidAppear is not overridden.
In case relevant, here are the most important actions in the viewWillAppear method:
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:NO animated:YES];
self.navigationItem.title = #"New Waypoint";
// other initialisation of internal fields
}
Like you, I have customers reporting this problem and I could see the stack traces that XCode downloaded from production but I could not reproduce it... until I tried enabling "voice over".
The other accessibility options that I tried worked OK.
The stack trace shows that iOS is sending a selector of "length" to an instance of UILabel. This seemed odd. To see what would happen, I added a "length" method to UILabel to return the length of the UILabel's text property. Then it just failed with an unknown selector of _encodingCantBeStoredInEightBitCFString. So clearly iOS thought that my UILabel was something that it wasn't.
This ended up being because "description" was used for the name of my UILabel property/IBOutlet.
To fix the problem I renamed the property from "description" to something different. I suspect that my synthesized "description" getter was overriding NSObject's description method (which returns an NSString which fits the selectors which were being sent to my UILabel).
I am writing an app with 3 viewControllers contained inside of a MainViewController. One of these is controlled through the storyboard and shows ads. The other two viewControllers are displaying information. Depending on the menu button pressed and the viewController to be presented the app determines which viewController to change.
So far everything is working well except when ANY textField is selected. This causes the error to display. The instance is the viewController containing the textField, and is also the UIViewController named in the error. Also, the instance is not nil. I've placed a breakpoint at: textFieldShouldBeginEditing:
and this method is called before the crash happens. The app is universal and doesn't crash on the iPhone version, which uses the same setup except it only has the ads and another viewController displayed. Let me know if you need to see more code or have any ideas. I can't find the selector _keyboard anywhere and have no idea what to do from here.
I've tried to create a new project with minimal code to show the error, but new projects all work fine, so the problem isn't having too many viewControllers visible at once. I also know my transitioning code works fine because it works in the new projects. The viewControllers I've written are also not the problem, because the exact same viewController is used in the iPhone part of the app as well as in a new iPad only test project and the problem doesn't show up on them at all.
[edit - removed code, I tested the code in a new project and it worked fine]
[edit2 - added code and explanation]
#implementation FSMainiPadViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.leftView = [[UIView alloc] init];
self.rightView = [[UIView alloc] init];
if (!self.testVC) {
self.testVC = [[FSTestViewController alloc] initWithNibName:nil bundle:nil];
}
self.inputViewController = self.testVC;
self.resultsVC = [[FSResultsTableViewController alloc] initWithNibName:nil bundle:nil];
self.dataViewController = self.resultsVC;
self.leftView.frame = CGRectMake(0, VIEWFRAMEOFFSET/2, self.view.frame.size.width/2 , self.view.frame.size.height - IPADBANNERHEIGHT - VIEWFRAMEOFFSET/2 - MENUHEIGHT);
self.rightView.frame = CGRectMake((self.view.frame.size.width)/2, VIEWFRAMEOFFSET/2, self.view.frame.size.width/2, self.view.frame.size.height - IPADBANNERHEIGHT - VIEWFRAMEOFFSET/2 - MENUHEIGHT);
[self addChildViewController:self.inputViewController];
[self addChildViewController:self.dataViewController];
[self.view addSubview:self.inputViewController.view];
[self.view addSubview:self.dataViewController.view];
[self.dataViewController didMoveToParentViewController:self];
[self.inputViewController didMoveToParentViewController:self];
}
Selecting the textField causes this same error. I have literally commented out everything else in my MainViewController and it still causes this issue, but if I create a new project, even including my more complicated code and xib's, I can't recreate the crash.
Let me know if you want more code.
Stacktrace
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[FSSettingsViewController _keyboard]: unrecognized selector sent to instance 0x7da1dbf0'
*** First throw call stack:
(
0 CoreFoundation 0x0326d946 __exceptionPreprocess + 182
1 libobjc.A.dylib 0x02ef6a97 objc_exception_throw + 44
2 CoreFoundation 0x032755c5 -[NSObject(NSObject) doesNotRecognizeSelector:] + 277
3 CoreFoundation 0x031be3e7 ___forwarding___ + 1047
4 CoreFoundation 0x031bdfae _CF_forwarding_prep_0 + 14
5 UIKit 0x01e46d91 -[UIInputViewSet keyboard] + 52
6 UIKit 0x01b0807c -[UIKeyboardImpl setOrientation] + 94
7 UIKit 0x01b082c8 -[UIKeyboardImpl setFrame:] + 197
8 UIKit 0x01939084 UIViewCommonInitWithFrame + 1072
9 UIKit 0x01938bea -[UIView initWithFrame:] + 124
10 UIKit 0x01b02b62 -[UIKeyboardImpl initWithFrame:] + 107
11 UIKit 0x01b01c58 +[UIKeyboardImpl sharedInstance] + 158
12 UIKit 0x01e3bf4f -[UIPeripheralHost(UIKitInternal) _reloadInputViewsForResponder:] + 962
13 UIKit 0x01a845a5 -[UIResponder(UIResponderInputViewAdditions) reloadInputViews] + 316
14 UIKit 0x01a838ec -[UIResponder becomeFirstResponder] + 562
15 UIKit 0x0194a1c0 -[UIView(Hierarchy) becomeFirstResponder] + 114
16 UIKit 0x02115477 -[UITextField becomeFirstResponder] + 51
17 UIKit 0x01d183ef -[UITextInteractionAssistant(UITextInteractionAssistant_Internal) setFirstResponderIfNecessary] + 200
18 UIKit 0x01d1aa16 -[UITextInteractionAssistant(UITextInteractionAssistant_Internal) oneFingerTap:] + 2762
19 UIKit 0x01d0e287 _UIGestureRecognizerSendActions + 327
20 UIKit 0x01d0cb04 -[UIGestureRecognizer _updateGestureWithEvent:buttonEvent:] + 561
21 UIKit 0x01d0eb4d -[UIGestureRecognizer _delayedUpdateGesture] + 60
22 UIKit 0x01d124ca ___UIGestureRecognizerUpdate_block_invoke661 + 57
23 UIKit 0x01d1238d _UIGestureRecognizerRemoveObjectsFromArrayAndApplyBlocks + 317
24 UIKit 0x01d06296 _UIGestureRecognizerUpdate + 3720
25 UIKit 0x0191f26b -[UIWindow _sendGesturesForEvent:] + 1356
26 UIKit 0x019200cf -[UIWindow sendEvent:] + 769
27 UIKit 0x018e5549 -[UIApplication sendEvent:] + 242
28 UIKit 0x018f537e _UIApplicationHandleEventFromQueueEvent + 20690
29 UIKit 0x018c9b19 _UIApplicationHandleEventQueue + 2206
30 CoreFoundation 0x031911df __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
31 CoreFoundation 0x03186ced __CFRunLoopDoSources0 + 253
32 CoreFoundation 0x03186248 __CFRunLoopRun + 952
33 CoreFoundation 0x03185bcb CFRunLoopRunSpecific + 443
34 CoreFoundation 0x031859fb CFRunLoopRunInMode + 123
35 GraphicsServices 0x0519f24f GSEventRunModal + 192
36 GraphicsServices 0x0519f08c GSEventRun + 104
37 UIKit 0x018cd8b6 UIApplicationMain + 1526
38 FoodStorage 0x000a795d main + 141
39 libdyld.dylib 0x04e14ac9 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
This is the first time the Google machine has let me down. In all the problems I've had making this app, this is the only problem I can't seem to find anyone else having.
I'm going to assume this code works flawlessly when running on an iOS7 device and probably when compiled against the iOS7 SDK on an iOS8 device.
You appear to have had the misfortune of naming one of your properties the same thing as an Apple added property:
#interface UIResponder (UIResponderInputViewAdditions)
// Called and presented when object becomes first responder. Goes up the responder chain.
#property (nonatomic, readonly, retain) UIInputViewController *inputViewController NS_AVAILABLE_IOS(8_0);
#end
When the user taps on your text field, UIKit will grab your view controller thinking it's a UIInputViewController and send the private message _keyboard. Your view controller doesn't implement this method and it crashes the app.
The only thing you need to do here is rename your property from inputViewController to something else like myInputViewController.
The problem is in your iPad storyboard. Check all the view controllers' connections. You might have a connection in the storyboard that doesn't get use, delete them. It has got to be there if it works on iPhone and not the iPad. Place breakpoints everywhere to see the last position before crash.
Can't reproduce following crash.
I already handled the case : not segueing the viewcontroller while one viewcontroller is animating. Similar problem mentioned here: iOS app error - Can't add self as subview. I have implemented this solution for safe segueing.
Still I am getting following crash.
Note: getting crash on both iOS 7 and 8 but more crash occurrence for iOS 8.(if that helps). Not getting crash in simulator even if segueing from viewDidLoad.
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Can't add self as subview'
Application Specific Backtrace 1:
0 CoreFoundation 0x24503f87 <redacted> + 126
1 libobjc.A.dylib 0x31c62c77 _objc_exception_throw + 38
2 CoreFoundation 0x24503ecd -[NSException initWithCoder:] + 0
3 UIKit 0x279880b3 -[UIView _addSubview:positioned:relativeTo:] + 114
4 UIKit 0x27988037 -[UIView addSubview:] + 30
5 UIKit 0x27b4d491 <redacted> + 1236
6 UIKit 0x2798e701 +[UIView performWithoutAnimation:] + 72
7 UIKit 0x27b4cd79 -[_UINavigationParallaxTransition animateTransition:] + 808
8 UIKit 0x27b0b787 -[UINavigationController _startCustomTransition:] + 2854
9 UIKit 0x27a2ab2f -[UINavigationController _startDeferredTransitionIfNeeded:] + 422
10 UIKit 0x27a2a931 -[UINavigationController __viewWillLayoutSubviews] + 44
11 UIKit 0x27a2a8c9 -[UILayoutContainerView layoutSubviews] + 184
12 UIKit 0x2797f25f -[UIView layoutSublayersOfLayer:] + 514
13 QuartzCore 0x273aa1d5 -[CALayer layoutSublayers] + 136
14 QuartzCore 0x273a5bd1 <redacted> + 360
15 QuartzCore 0x273a5a59 <redacted> + 16
16 QuartzCore 0x273a5447 <redacted> + 222
17 QuartzCore 0x273a5251 <redacted> + 324
18 UIKit 0x27980c31 <redacted> + 1384
19 CoreFoundation 0x244ca807 <redacted> + 14
20 CoreFoundation 0x244c9c1b <redacted> + 222
21 CoreFoundation 0x244c8299 <redacted> + 768
22 CoreFoundation 0x24415db1 _CFRunLoopRunSpecific + 476
23 CoreFoundation 0x24415bc3 _CFRunLoopRunInMode + 106
24 GraphicsServices 0x2b7a0051 _GSEventRunModal + 136
25 UIKit 0x279e0f01 _UIApplicationMain + 1440
This also happens when for some reason you push the segue / viewcontroller multiple times. One of such case is when you are observing for a notification and if for some reason that notification was posted multiple times and in the observing method, if you were pushing a view controller, it will push to more than once which eventually will cause this kind of crash.
Sorry for being late for the party. I recently had this issue wherein my navigationbar goes into corrupted state because of pushing more than one view controller at the same time. This happens because the other view controller is pushed while the first view controller is still animating. Taking hint from the nonamelive answer from here
I came up with my simple solution that works in my case. You just need to subclass UINavigationController and override the pushViewController method and check if previous view controller animation is finished as yet. You can listen to the animation completion by making your class a delegate of UINavigationControllerDelegate and setting the delegate to self.
I have uploaded a gist here to make things simple.
Just make sure you set this new class as the NavigationController in your storyboard.
I'm struggling with this intermittent crash issue on my UITableView which has UICollectionViews.
I have a navigation controller whose root view controller has:
UITableView with 3 sections
Each section has one row
Each row has a UICollectionView
The top row of UITableView (which is a collection view) is made to scroll automatically based on NSTimer.
The crash occurs when I push into the navigation controller and pop out back and forth. It happens when I do pushing and popping 3-4 times
The trace:
Thread 0 Crashed:
0 libobjc.A.dylib 0x38f74626 objc_msgSend + 6
1 UIKit 0x312a6740 -[UIScrollView(UIScrollViewInternal) _notifyDidScroll] + 60
2 UIKit 0x31020798 -[UIScrollView setContentOffset:] + 600
3 UIKit 0x312a76b6 -[UIScrollView(UIScrollViewInternal) _adjustContentOffsetIfNecessary] + 1394
4 UIKit 0x310d33d2 -[UIScrollView(UIScrollViewInternal) _stopScrollingNotify:pin:tramplingDragFlags:] + 414
5 UIKit 0x310d322a -[UIScrollView(UIScrollViewInternal) _stopScrollingNotify:pin:] + 26
6 UIKit 0x310d31e2 -[UIScrollView removeFromSuperview] + 26
7 UIKit 0x31001952 -[UIView dealloc] + 374
8 CoreFoundation 0x2e700140 CFRelease + 556
9 CoreFoundation 0x2e70b668 -[__NSArrayM dealloc] + 156
10 libobjc.A.dylib 0x38f79b66 objc_object::sidetable_release(bool) + 170
11 libobjc.A.dylib 0x38f7a0ce (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 354
12 CoreFoundation 0x2e70347c _CFAutoreleasePoolPop + 12
13 CoreFoundation 0x2e798f0e __CFRunLoopRun + 1310
14 CoreFoundation 0x2e703724 CFRunLoopRunSpecific + 520
15 CoreFoundation 0x2e703506 CFRunLoopRunInMode + 102
16 GraphicsServices 0x336726ce GSEventRunModal + 134
17 UIKit 0x3106486c UIApplicationMain + 1132
18 BoatSenzeDev 0x00110648 main (main.m:16)
19 libdyld.dylib 0x39468ab4 start + 0
I think there's a bug somewhere on iOS 8 regarding the timing of UITableViewController (or plain UIViewController containing a UITableView) dealloc when dealing with transition animations. Somehow the view controller is already deallocated, but the table view is still trying to send messages to its delegate.
As a workaround, you can implement the dealloc method on the UITableViewController like this:
- (void)dealloc
{
self.tableView.delegate = nil;
self.tableView.dataSource = nil;
}
Thread : Crashed: com.apple.main-thread
0 libobjc.A.dylib 0x000000019a5639d0 objc_msgSend + 16
1 UIKit 0x00000001915af1d0 -[UISearchDisplayController _cleanUpSearchBar] + 196
2 UIKit 0x00000001915af0a0 -[UISearchBar willMoveToSuperview:] + 68
3 UIKit 0x0000000191788ea4 __UIViewWillBeRemovedFromSuperview + 192
4 UIKit 0x00000001914b83f4 -[UIView(Hierarchy) removeFromSuperview] + 72
5 UIKit 0x00000001914bb4fc -[UIView dealloc] + 424
6 UIKit 0x000000019159f354 -[UIScrollView dealloc] + 972
7 UIKit 0x000000019165fc40 -[UITableView dealloc] + 1304
8 UIKit 0x000000019159ed60 -[UIScrollView removeFromSuperview] + 80
9 UIKit 0x00000001914bb4fc -[UIView dealloc] + 424
10 UIKit 0x000000019165010c -[UIViewController dealloc] + 464
11 Gogobot 0x000000010017e560 -[GBListPageViewController dealloc] (GBListPageViewController.m:288)
12 Gogobot 0x0000000100189f84 __destroy_helper_block_982 (GBListPageViewController.m)
13 libsystem_blocks.dylib 0x000000019ab7f908 _Block_release + 256
14 libsystem_blocks.dylib 0x000000019ab7f908 _Block_release + 256
15 libsystem_blocks.dylib 0x000000019ab7f908 _Block_release + 256
16 Foundation 0x000000018f198b78 __destroy_helper_block_165 + 28
17 libsystem_blocks.dylib 0x000000019ab7f908 _Block_release + 256
18 Foundation 0x000000018f0a138c -[NSBlockOperation dealloc] + 68
19 libdispatch.dylib 0x000000019ab383e0 _dispatch_client_callout + 16
20 libdispatch.dylib 0x000000019ab3b56c _dispatch_main_queue_callback_4CF + 344
21 CoreFoundation 0x000000018e5aad64 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
22 CoreFoundation 0x000000018e5a90a4 __CFRunLoopRun + 1452
23 CoreFoundation 0x000000018e4e9b38 CFRunLoopRunSpecific + 452
24 GraphicsServices 0x0000000193f0f830 GSEventRunModal + 168
25 UIKit 0x00000001915280e8 UIApplicationMain + 1156
26 Gogobot 0x0000000100202c20 main (main.m:16)
27 libdyld.dylib 0x000000019ab53aa0 start + 4
Here are the crash log i got from crashlytics. From this two lines, seems like something wrong with the dealloc,
11 Gogobot 0x000000010017e560 -[GBListPageViewController dealloc] (GBListPageViewController.m:288)
12 Gogobot
but i am using ARC, and didn't even implement anything in dealloc. It never happen to me when i test, but we got the same crash report from Crashlytcis, 10-20 times a day. And some user has 30% free ram. Doesn't look like memory issue. But all the report are coming from iPhone 5s.
I have been trying to reproduce that on my iphone 5s and 5. can't recreate at all... any idea would be appreciated.
here is my dealloc in my GBListPageViewController:
- (void)dealloc
{
[[NSNotificationCenter defaultCenter]removeObserver:self name:kGBListPageVCSortSelected object:nil];
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil];
}
======================================================================
New Edit:
we try to remove delegate and observers in dealloc, but seems like that didn't solve the problem. And from our crash reports, seems like all the crashes happen on iphone5s + 7.0.x OS.
here is the code we used to remove delegate, pretty simply.
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
self.searchDisplayController.searchBar.delegate = nil;
self.searchDisplayController.delegate = nil;
}
Anyone has the same issue?...
My bet would be on the view controller being released before the view, while the view still has a reference to the delegate and tries to call a delegate method. I've seen many of these in iOS 7.X.
Set your search bar's and search display controller's delegates to nil in the view controller's dealloc.
I've had this problem as well. My workaround was rather unorthodox; in the segue's destination view controller, I set a property to hold a pointer to the source view controller, then set it to nil in viewWillAppear:animated. Like I said, it's unorthodox, but it works, giving the source view controller enough time to clean up before deallocating it.
Edit:
#property (nonatomic, strong) id vcToHoldForARCDeallocBug;
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.vcToHoldForARCDeallocBug = nil;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
self.vcToHoldForARCDeallocBug = segue.destinationViewController;
}
It sets a pointer to the destination view controller when it's presented. Once the user navigates back, in viewDidAppear it clears the pointer and allows ARC to deallocate the destination view controller since everything has been cleaned up by the time viewDidAppear is called.