I Have an iOS app with multiple view controllers and ARC enabled. One of the view controllers has an IBOutlet
for UIScrollView
and UIPageControl
. When that view controller is loaded this error is printed in the console:
*** -[NSRecursiveLock dealloc]: lock (<NSRecursiveLock: 0xcb88cb0> '(null)')
deallocated while still in use
While trying to fix the problem, I created a symbolic breakpoint for the symbol _NSLockError
with the module set to Foundation. Now Xcode breaks with breakpoint 1.1 on "0x12d2b58: pushl %ebp"
, which is on thread 1.
Foundation`_NSLockError:
-----------------------------------------------------
|> 0x12d2b58: pushl %ebp <|Thread 1: breakpoint 1.1|
-----------------------------------------------------
0x12d2b59: movl %esp, %ebp
0x12d2b5b: subl $8, %esp
0x12d2b5e: calll 0x12d2b63 ; _NSLockError + 11
0x12d2b63: popl %eax
0x12d2b64: leal 2118709(%eax), %eax
0x12d2b6a: movl %eax, (%esp)
0x12d2b6d: calll 0x125689d ; NSLog
0x12d2b72: addl $8, %esp
0x12d2b75: popl %ebp
0x12d2b76: ret
Here is the code in my application for the problematic ViewController:
header file (.h):
#import <UIKit/UIKit.h>
@class AboutViewController;
@protocol AboutViewControllerDelegate
- (void)aboutViewControllerDidFinish:(AboutViewController *)controller;
@end
@interface AboutViewController : UIViewController<UIScrollViewDelegate>
@property (strong, nonatomic,retain) id <AboutViewControllerDelegate> delegate;
@property (nonatomic,strong,) IBOutlet UIScrollView *scrollView;
@property (nonatomic, strong) IBOutlet UIPageControl *pageControl;
@property (nonatomic, strong) NSArray *imageArray;
@property(nonatomic, assign) IBOutlet UILabel *label;
- (IBAction)done:(id)sender; //returns back to main menu after a button is pressed
@end
implementation file (.m):
#import "AboutViewController.h"
@interface AboutViewController ()
@end
@implementation AboutViewController
@synthesize scrollView;
@synthesize pageControl;
@synthesize imageArray;
int page;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//load the images for the scrollview in an array
imageArray = [[NSArray alloc] initWithObjects:@"1.png", @"2.png", @"3.png", nil];
for (int i = 0; i < [imageArray count]; i++ ) {
int page = scrollView.contentOffset.x / scrollView.frame.size.width;
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame];
imageView.image = [UIImage imageNamed:[imageArray objectAtIndex:i]];
[self.scrollView addSubview:imageView];
NSLog (@"page %d",page);
if (page==0) {
self.label.text = [NSString stringWithFormat:@"%s","page1"];
}
}
scrollView.contentSize = CGSizeMake(scrollView.frame.size.
width *[imageArray count], scrollView.frame.size.height);
}
#pragma mark - UIScrollView Delegate
- (void)scrollViewDidScroll:(UIScrollView *)sender
{
CGFloat pageWidth = self.scrollView.frame.size.width;
//calculate current page in scrollview
int page = floor((self.scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
self.pageControl.currentPage = page;
NSLog (@"page %d",page);
if (page==0) {
//change the image caption
self.label.text = [NSString stringWithFormat:@"%s","Hello"];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
[_label setAlpha:1];
[UIView commitAnimations];
}
if (page==1) {
//change the image caption
self.label.text = [NSString stringWithFormat:@"%s","World"];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
[_label setAlpha:1];
[UIView commitAnimations];
}
if (page==2) {
//change the image caption
self.label.text = [NSString stringWithFormat:@"%s","Foobar"];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
[_label setAlpha:1];
[UIView commitAnimations];
}
}
- (IBAction)done:(id)sender
{
[self.delegate aboutViewControllerDidFinish:self];
}
@end
After a (lldb)bt:
* thread #1: tid = 0x1c8f63, 0x012d2b58 Foundation`_NSLockError, queue = 'com.apple.main-thread, stop reason = breakpoint 1.1
frame #0: 0x012d2b58 Foundation`_NSLockError
frame #1: 0x01247153 Foundation`-[NSRecursiveLock dealloc] + 159
frame #2: 0x01820692 libobjc.A.dylib`objc_object::sidetable_release(bool) + 268
frame #3: 0x01821adf libobjc.A.dylib`-[NSObject release] + 25
frame #4: 0x05a89385 UIFoundation`_freeExtraData + 48
frame #5: 0x05a895d5 UIFoundation`-[NSLayoutManager dealloc] + 381
frame #6: 0x01820692 libobjc.A.dylib`objc_object::sidetable_release(bool) + 268
frame #7: 0x01821adf libobjc.A.dylib`-[NSObject release] + 25
frame #8: 0x00a91065 UIKit`-[UITextView dealloc] + 168
frame #9: 0x00453e6b UIKit`-[UIView release] + 89
frame #10: 0x0045f2d4 UIKit`-[UIView(Hierarchy) removeFromSuperview] + 292
frame #11: 0x0047b4fd UIKit`-[UIScrollView removeFromSuperview] + 84
frame #12: 0x004565db UIKit`-[UIView dealloc] + 432
frame #13: 0x00477eaf UIKit`-[UIScrollView dealloc] + 1156
frame #14: 0x00453e6b UIKit`-[UIView release] + 89
frame #15: 0x0045f2d4 UIKit`-[UIView(Hierarchy) removeFromSuperview] + 292
frame #16: 0x0047b4fd UIKit`-[UIScrollView removeFromSuperview] + 84
frame #17: 0x004565db UIKit`-[UIView dealloc] + 432
frame #18: 0x00453e6b UIKit`-[UIView release] + 89
frame #19: 0x01ba2380 CoreFoundation`CFRelease + 272
frame #20: 0x01bc18b4 CoreFoundation`-[__NSArrayM dealloc] + 196
frame #21: 0x01820692 libobjc.A.dylib`objc_object::sidetable_release(bool) + 268
frame #22: 0x0181fe81 libobjc.A.dylib`objc_release + 49
frame #23: 0x01820ce7 libobjc.A.dylib`(anonymous namespace)::AutoreleasePoolPage::pop(void*) + 537
frame #24: 0x01bc1fc8 CoreFoundation`_CFAutoreleasePoolPop + 24
frame #25: 0x00402c6e UIKit`_wrapRunLoopWithAutoreleasePoolHandler + 59
frame #26: 0x01be89ee CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30
frame #27: 0x01be893f CoreFoundation`__CFRunLoopDoObservers + 399
frame #28: 0x01bc6cb0 CoreFoundation`__CFRunLoopRun + 1936
frame #29: 0x01bc610d CoreFoundation`CFRunLoopRunSpecific + 445
frame #30: 0x01bc5f3b CoreFoundation`CFRunLoopRunInMode + 123
frame #31: 0x032e2ff2 GraphicsServices`GSEventRunModal + 192
frame #32: 0x032e2e19 GraphicsServices`GSEventRun + 104
frame #33: 0x004054eb UIKit`UIApplicationMain + 1225
frame #34: 0x0000789d Monarch`main(argc=1, argv=0xbfffee1c) + 141 at main.m:16
My question is why was NSRecursiveLock
deallocated in the first place?
I never mentioned NSRecursiveLock
any where in the code. There was a similar question on SO about this but it was not very detailed.
Does ARC come into play here?
In this case of NSRecursiveLock being Deallocated while still in use, the problem was with the IDE, Xcode. Using the latest official version of it resolved the issue.