when I launch my app, I keep getting this CGContextFillEllipseInRect: invalid context error. My app is simply to make the circle 'pinchable'.
The debugger shows me this:
[Session started at 2010-05-23 18:21:25 +0800.]
2010-05-23 18:21:27.140 Erase[8045:207] I'm being redrawn.
Sun May 23 18:21:27 Sidwyn-Kohs-MacBook-Pro.local Erase[8045] <Error>: CGContextFillEllipseInRect: invalid context
2010-05-23 18:21:27.144 Erase[8045:207] New value of counter is 1
2010-05-23 18:21:27.144 Erase[8045:207] I'm being redrawn.
Sun May 23 18:21:27 Sidwyn-Kohs-MacBook-Pro.local Erase[8045] <Error>: CGContextFillEllipseInRect: invalid context
2010-05-23 18:21:27.144 Erase[8045:207] New value of counter is 2
2010-05-23 18:21:27.144 Erase[8045:207] I'm being redrawn.
Sun May 23 18:21:27 Sidwyn-Kohs-MacBook-Pro.local Erase[8045] <Error>: CGContextFillEllipseInRect: invalid context
2010-05-23 18:21:27.144 Erase[8045:207] New value of counter is 3
2010-05-23 18:21:27.145 Erase[8045:207] I'm being redrawn.
Sun May 23 18:21:27 Sidwyn-Kohs-MacBook-Pro.local Erase[8045] <Error>: CGContextFillEllipseInRect: invalid context
2010-05-23 18:21:27.145 Erase[8045:207] New value of counter is 4
2010-05-23 18:21:27.148 Erase[8045:207] I'm being redrawn.
Sun May 23 18:21:27 Sidwyn-Kohs-MacBook-Pro.local Erase[8045] <Error>: CGContextFillEllipseInRect: invalid context
2010-05-23 18:21:27.149 Erase[8045:207] New value of counter is 5
2010-05-23 18:21:27.150 Erase[8045:207] I'm being redrawn.
Sun May 23 18:21:27 Sidwyn-Kohs-MacBook-Pro.local Erase[8045] <Error>: CGContextFillEllipseInRect: invalid context
2010-05-23 18:21:27.150 Erase[8045:207] New value of counter is 6
My implementation file is:
//
// ImageView.m
// Erase
//
#import "ImageView.h"
#import "EraseViewController.h"
#implementation ImageView
-(void)setNewRect:(CGRect)anotherRect{
newRect = anotherRect;
}
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
newRect = CGRectMake(0,0,0,0);
ref = UIGraphicsGetCurrentContext();
}
return self;
}
- (void)drawRect:(CGRect)rect {
static int counter = 0;
CGRect veryNewRect = CGRectMake(30.0, 210.0, 60.0, 60.0);
NSLog(#"I'm being redrawn.");
if (counter == 0){
CGContextFillEllipseInRect(ref, veryNewRect);
}
else{
CGContextFillEllipseInRect(ref, rect);
}
counter++;
NSLog(#"New value of counter is %d", counter);
}
- (void)setNeedsDisplay{
[super setNeedsDisplay];
[self drawRect:newRect];
}
- (void)dealloc {
[super dealloc];
}
#end
I've got two questions:
1) Why is it updating counter 6 times? I removed the line [super setNeedsDisplay]; but it becomes 4 times.
2) What is that invalid context error?
Thanks guys.
I'm not sure about the six calls, but at least two calls are happening because the framework is calling drawRect: and so are you. You don't need to call drawRect: yourself (and hence you don't need to override setNeedsDisplay:).
You should call UIGraphicsGetCurrentContext from inside drawRect:. Don't cache it. It may be failing because the framework doesn't guarantee to use the same context on each call, or because you are calling drawRect: directly, or both; I'm not sure which.
Related
I have the application that uses sizeWithFont method. It crashes on about 5% of launches of the application on iOS 7. The method is deprecated on SDK 7, so I replaced it with the following category:
#import "NSString+mySizeWithFont.h"
#import "Constants.h"
#implementation NSString (mySizeWithFont)
- (CGSize)mySizeWithFont:(UIFont *)font {
if (is_iOS7) {
CGSize size = CGSizeMake(MAXFLOAT, MAXFLOAT);
return [self mySizeWithFont:font constrainedToSize:size];
} else {
return [self sizeWithFont:font];
}
}
- (CGSize)mySizeWithFont:(UIFont*)font constrainedToSize:(CGSize)size {
if (is_iOS7) {
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil];
CGRect frame = [self boundingRectWithSize:size options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading) attributes:attributesDictionary context:nil];
return frame.size;
} else {
return [self sizeWithFont:font constrainedToSize:size];
}
}
#end
But now I have another crashes on the same 5% of launches. There are crash reports of 2 types:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0005006f
Triggered by Thread: 0
Thread 0 Crashed:
0 libobjc.A.dylib 0x3902cb76 objc_msgSend + 22
1 CoreFoundation 0x2ec74c56 +[__NSDictionaryI __new:::::] + 358
2 CoreFoundation 0x2ec749c6 -[__NSPlaceholderDictionary initWithObjects:forKeys:count:] + 238
3 CoreFoundation 0x2ec794d4 +[NSDictionary dictionaryWithObjectsAndKeys:] + 372
4 *** MYAPP *** 0x000cd99e -[NSString(mySizeWithFont) mySizeWithFont:constrainedToSize:] (NSString+mySizeWithFont.m:25)
5 *** MYAPP *** 0x000cd7e6 -[NSString(mySizeWithFont) mySizeWithFont:] (NSString+mySizeWithFont.m:17)
6 *** MYAPP *** 0x000d36ae -[LiteVersionHomepageLink drawRect:] (LiteVersionHomepageLink.m:43)
And this one:
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Triggered by Thread: 0
Last Exception Backtrace:
0 CoreFoundation 0x2ed36e86 __exceptionPreprocess + 126
1 libobjc.A.dylib 0x390316c2 objc_exception_throw + 34
2 CoreFoundation 0x2ed3a7b2 -[NSObject(NSObject) doesNotRecognizeSelector:] + 198
3 CoreFoundation 0x2ed390b2 ___forwarding___ + 702
4 CoreFoundation 0x2ec87e94 __forwarding_prep_0___ + 20
5 UIFoundation 0x3660790e __NSStringDrawingEngine + 2950
6 UIFoundation 0x36606d5a -[NSString(NSExtendedStringDrawing) boundingRectWithSize:options:attributes:context:] + 130
7 *** MYAPP *** 0x000e89d4 -[NSString(mySizeWithFont) mySizeWithFont:constrainedToSize:] (NSString+mySizeWithFont.m:26)
8 *** MYAPP *** 0x000e87e6 -[NSString(mySizeWithFont) mySizeWithFont:] (NSString+mySizeWithFont.m:17)
9 *** MYAPP *** 0x000ee6ae -[LiteVersionHomepageLink drawRect:] (LiteVersionHomepageLink.m:43)
LiteVersionHomepageLink is inherited from UIView:
#interface LiteVersionHomepageLink : UIView {
NSString *text;
UIFont *textFont;
}
And mySizeWithFont is called from the following method:
- (void)drawRect:(CGRect)rect {
[[UIImage imageNamed:#"cal_top_back#2x"] drawInRect:rect];
if (text && textFont) {
[[UIColor whiteColor] set];
float height = [text mySizeWithFont:textFont].height / 2;
[text drawInRect:CGRectMake(0, rect.size.height / 2 - height, rect.size.width, rect.size.height / 2 + height) withFont:textFont lineBreakMode:NSLineBreakByCharWrapping alignment:NSTextAlignmentCenter];
}
}
What's wrong? How to fix crashes? Thanks a lot for any help!
It looks to me like you're calling your routine mySizeWithFont with an invalid font. Either one that has been released, or one that was never allocated. I'd put in NSLog breadcrumbs near your font allocation and just before the breadcrumbs to make sure your font is allocated first. If it is, it may be that ARC is tossing your font before you go to use it - may need #property(strong) or something like that.
My two cents: I had, in my app, an overrelease bug with a UIFont object. I'd invoke [UIFont systemFontOfSize:] and store the result in a file-static variable without retaining.
Up until iOS 7, I'd get away with it, then crashes in [sizeWithFont] started coming. Looks like iOS<7 would return font instances from a pool or a cache, so that a single unmatched release won't deallocate them. In iOS 7 - not anymore.
Working on an application and using resignFirstResponder method for edittext.
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
return YES;
}// return NO to disallow editing.
- (void)textFieldDidBeginEditing:(UITextField *)textField {
CGPoint scrollPoint = CGPointMake(0, textField.frame.origin.y);
[scrollView setContentOffset:scrollPoint animated:YES];
}// became first responder
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
return YES;
}// return YES to allow editing to stop and to resign first responder status. NO to disallow the editing session to end
- (void)textFieldDidEndEditing:(UITextField *)textField {
[scrollView setContentOffset:CGPointZero animated:YES];
}// may be called if forced even if shouldEndEditing returns NO (e.g. view removed from window) or endEditing:YES called
- (BOOL)textFieldShouldClear:(UITextField *)textField {
return NO;
}// called when clear button pressed. return NO to ignore (no notifications)
-(BOOL)textFieldShouldReturn:(UITextField*)textField;
{
NSInteger nextTag = textField.tag + 1;
// Try to find next responder
UIResponder* nextResponder = [textField.superview viewWithTag:nextTag];
if (nextResponder) {
// Found next responder, so set it.
[nextResponder becomeFirstResponder];
} else {
// Not found, so remove keyboard.
[textField resignFirstResponder];
}
return NO; // We do not want UITextField to insert line-breaks.
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
if ([emailField isFirstResponder] && [touch view] != emailField) {
[emailField resignFirstResponder];
}
else if ([passwordField isFirstResponder] && [touch view] != passwordField) {
[passwordField resignFirstResponder];
}
[super touchesBegan:touches withEvent:event];
}
I have been looking into for so long.. But app crashes on random. Sometimes runs smooth and sometimes it get crashed right after I tap on any UIEdittext..
Please help. I have also tried: How to resign first responder from text field when user tap elsewhere?
but it also crashes in dismiss keyboard method on random cases. Can't find that..
Please help.
Device Log
Oct 8 19:09:28 iPhone-5 wifid[15] <Notice>: WiFi:[402934168.667607]:
Oct 8 19:09:28 iPhone-5 wifid[15] <Notice>: Too frequent(0.169014 secs) rssi event from driver, ignoring
Oct 8 19:09:28 iPhone-5 wifid[15] <Notice>:
Oct 8 19:09:36 iPhone-5 wifid[15] <Notice>: WiFi:[402934176.114689]: WiFiLocaleManagerCheckLocale: trying to determine locale...
Oct 8 19:09:36 iPhone-5 wifid[15] <Notice>: WiFi:[402934176.115691]: WiFiManagerCoreLocationGetCachedLocation: getting cached location...
Oct 8 19:09:36 iPhone-5 wifid[15] <Notice>: WiFi:[402934176.119252]: __WiFiLocaleManagerGetLocaleFromMcc: finding iso country code for mcc 410 ....
Oct 8 19:09:36 iPhone-5 wifid[15] <Notice>: WiFi:[402934176.119628]: Starting Low Accuracy Location Monitoring, locationMonitoringTimeout=60.000000
Oct 8 19:09:36 iPhone-5 wifid[15] <Notice>: WiFi:[402934176.120057]: WiFiManagerCoreLocationStartLocationUpdates: starting location updates...
Oct 8 19:09:36 iPhone-5 wifid[15] <Notice>: WiFi:[402934176.120356]: Location Monitoring successfully started with accuracy=3000.000000meters
Oct 8 19:09:36 iPhone-5 wifid[15] <Notice>: WiFi:[402934176.120673]: __WiFiLocationServiceManagerEventCallback, got cb dict <dictionary> {
Oct 8 19:09:36 iPhone-5 wifid[15] <Notice>: eventType : 0
Oct 8 19:09:36 iPhone-5 wifid[15] <Notice>: location : <+33.53914677,+73.10165631> +/- 1414.00m (speed -1.00 mps / course -1.00) # 10/8/13, 7:09:36 PM Pakistan Standard Time
Oct 8 19:09:36 iPhone-5 wifid[15] <Notice>: }
Oct 8 19:09:36 iPhone-5 wifid[15] <Notice>: WiFi:[402934176.124702]: __WiFiLocationServiceManagerProcessLocationAvailableEvent: isValidHighAccuracyLocation 0, isValidLowAccuracyLocation 1
Oct 8 19:09:36 iPhone-5 wifid[15] <Notice>: WiFi:[402934176.125013]: __WiFiLocationServiceManagerProcessLocationAvailableEvent: give low accuracy callback
Oct 8 19:09:36 iPhone-5 wifid[15] <Notice>: WiFi:[402934176.125276]: __WiFiLocaleManagerGetLocaleFromLocation: <+33.53914677,+73.10165631> +/- 1414.00m (speed -1.00 mps / course -1.00) # 10/8/13, 7:09:36 PM Pakistan Standard Time
Oct 8 19:09:36 iPhone-5 wifid[15] <Notice>: WiFi:[402934176.127336]: locale from bounding box
Oct 8 19:09:36 iPhone-5 wifid[15] <Notice>: WiFi:[402934176.127564]: new locale: , locale:
Oct 8 19:09:36 iPhone-5 wifid[15] <Notice>: WiFi:[402934176.127795]: Stopping Low Accuracy Location Monitoring
Oct 8 19:09:36 iPhone-5 wifid[15] <Notice>: WiFi:[402934176.128050]: Location Monitoring stopped
Oct 8 19:09:36 iPhone-5 wifid[15] <Notice>: WiFi:[402934176.128296]: WiFiManagerCoreLocationStopLocationUpdates: stopping location updates...
Oct 8 19:09:36 iPhone-5 wifid[15] <Notice>: WiFi:[402934176.128696]: Stopping Low Accuracy Location Monitoring
Oct 8 19:09:36 iPhone-5 wifid[15] <Notice>: WiFi:[402934176.128949]: CLMonitoring is already stopped
Oct 8 19:09:37 iPhone-5 wifid[15] <Notice>: WiFi:[402934177.474861]:
Oct 8 19:09:37 iPhone-5 wifid[15] <Notice>: Too frequent(3.971344 secs) rssi event from driver
Oct 8 19:09:37 iPhone-5 wifid[15] <Notice>:
Oct 8 19:09:38 iPhone-5 wifid[15] <Notice>: WiFi:[402934178.504655]:
Oct 8 19:09:38 iPhone-5 wifid[15] <Notice>: Too frequent(1.029793 secs) rssi event from driver
Oct 8 19:09:38 iPhone-5 wifid[15] <Notice>:
Oct 8 19:09:58 iPhone-5 wifid[15] <Notice>: WiFi:[402934198.509395]:
Oct 8 19:09:58 iPhone-5 wifid[15] <Notice>: Too frequent(4.996233 secs) rssi event from driver
Oct 8 19:09:58 iPhone-5 kernel[0] <Debug>: AppleD1972PMUPowerSource: limiting USB input current to 490 mA (measured 496 mA)
Oct 8 19:09:58 iPhone-5 kernel[0] <Debug>: AppleD1972PMUPowerSource: limiting USB input current to 390 mA (measured 468 mA)
Oct 8 19:09:58 iPhone-5 kernel[0] <Debug>: 086669.986712 wlan.A[10295] AppleBCMWLANNetManager::updateLinkQualityMetrics(): Report LQM to User Land 100, fAverageRSSI -70
Oct 8 19:09:58 iPhone-5 wifid[15] <Notice>:
In an ios project, there are numerous viewcontroller files, developed my many people, over a period of time. I launched simulator, and navigated to various screens. In middle of navigation, I want to find which action method will be called when a button is pressed in a screen. How to find it easily without much analyzing the project and without using breakpoints.
Create UIButton category and make sure it is included at your target:
UIButton+actionsFinder.h
#import <UIKit/UIKit.h>
#interface UIButton (actionsFinder)
#end
UIButton+actionsFinder.m
#import "UIButton+actionsFinder.h"
#implementation UIButton (actionsFinder)
-(void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
NSLog(#"%s %d %s %# %#\n %#\n %#", __FILE__, __LINE__, __PRETTY_FUNCTION__, #"Button clicked!\n", NSStringFromSelector(action), [target description], [event description]);
[super sendAction:action to:target forEvent:event];
}
#end
When any button sends any action you'll see something like this at console:
/Users/username/appname/targetname/UIButton+actionsFinder.m 15 -[UIButton(actionsFinder) sendAction:to:forEvent:] Button clicked!
onButton:
<MCViewController: 0x715e280>
<UITouchesEvent: 0x7639f40> timestamp: 23516.9 touches: {( <UITouch: 0x7169240> phase: Ended tap count: 1 window: <UIWindow: 0x754e6d0; frame = (0 0; 320 568); autoresize = W+H; layer = <UIWindowLayer: 0x754e7d0>> view: <UIRoundedRectButton: 0x7161290; frame = (123.5 38; 73 44); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x71613b0>> location in window: {149, 81.5} previous location in window: {149, 81.5} location in view: {25.5, 23.5} previous location in view: {25.5, 23.5}
Note that you'll get the following information:
selector name at destination class onButton: which I had declared
and linked to buttons onTouchUpInside event action, actual method
signature looks like
-(IBAction)onButton:(id)button;
the target description showing the destination class:
MCViewController
description of the event which fired the action
I was using __FILE__, __LINE__, __PRETTY_FUNCTION__ macros' to see where NSLog message is coming from.
You can right click on your button to See:
Which selector is added to particular touch event.
Or Print NSLog(#"%s", __PRETTY_FUNCTION__); On each function, so this log will print function name whenever that function will get called.
First, thanks in advance for taking the time to read through this. I have been searching for an answer to this issue for a few days but I cannot seem to find what I am looking for. I know that SIGSEGV errors (or EXEC_BAD_ACCESS faults) are usually caused by memory management issues but after hours of looking at the code, I can't seem to find an error. The static analyzer hasn't found anything either.
As the title says, this error only occurs on the device (never in the simulator) and doesn't happen every time the given view loads. Obviously this means that I can't use NSZombie to debug what is going wrong.
Let's start with the crash dump log:
0 myApp 0x00036659 +[TFCrashHandler backtrace] + 428
1 myApp 0x00036a6f TFSignalHandler + 54
2 libsystem_c.dylib 0x32f48539 _sigtramp + 48
3 UIKit 0x365701df -[UIView(Rendering) setNeedsDisplay] + 86
4 UIKit 0x36598269 -[UILabel setFont:] + 232
5 myApp 0x000190eb +[BruUISettings applyLabelDetailStyle:] (BruUISettings.m:130)
6 myApp 0x0001aa57 -[ActiveChallengeViewController viewDidLoad] (ActiveChallengeViewController.m:115)
7 UIKit 0x365a57ff -[UIViewController view] + 166
8 UIKit 0x365b1c39 -[UIViewController contentScrollView] + 24
9 UIKit 0x365b1aa9 -[UINavigationController _computeAndApplyScrollContentInsetDeltaForViewController:] + 36
10 UIKit 0x365b198f -[UINavigationController _layoutViewController:] + 34
11 UIKit 0x365b115b -[UINavigationController _startTransition:fromViewController:toViewController:] + 318
12 UIKit 0x365b0f53 -[UINavigationController _startDeferredTransitionIfNeeded] + 250
13 UIKit 0x365a5673 -[UINavigationController pushViewController:transition:forceImmediate:] + 806
14 UIKit 0x365a5349 -[UINavigationController pushViewController:animated:] + 36
15 myApp 0x00015dc7 -[ChallengesHomeViewController tableView:didSelectRowAtIndexPath:] (ChallengesHomeViewController.m:325)
16 UIKit 0x3661f565 -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 944
17 UIKit 0x36697ce7 -[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 158
18 Foundation 0x31f7a943 __NSFireDelayedPerform + 414
19 CoreFoundation 0x34ab1a63 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 14
20 CoreFoundation 0x34ab16c9 __CFRunLoopDoTimer + 364
21 CoreFoundation 0x34ab029f __CFRunLoopRun + 1206
22 CoreFoundation 0x34a334dd CFRunLoopRunSpecific + 300
23 CoreFoundation 0x34a333a5 CFRunLoopRunInMode + 104
24 GraphicsServices 0x351a7fed GSEventRunModal + 156
25 UIKit 0x3659a743 UIApplicationMain + 1090
26 myApp 0x000026c5 main (main.m:13)
27 myApp 0x0000265c start + 52
Note, I am using TestFlight from testflightapp.com and it is there exception handler at the top of the stack.
Here is the code that is creating and pushing the view controller in question:
CDAcceptedChallenge *challengeAtIndex = [self.activeChallenges objectAtIndex:[indexPath row]];
ActiveChallengeViewController *view = [[ActiveChallengeViewController alloc] initWithNibName:#"ActiveChallengeViewController"
bundle:nil
activeChallenge:challengeAtIndex];
view.leaveChallengeTarget = self;
[self.navigationController pushViewController:view animated:YES];
[view release];
This code is running inside of a didSelectRowAtIndex method, if that matters at all. This view controller has a bunch of member variables and IBOutlets which reference objects in the nib but here are the ones that correlate to the object mentioned in this error:
in .h:
UILabel *helpLabel;
...
#property (nonatomic, retain) IBOutlet UILabel *helpLabel;
in .m:
#synthesize helpLabel;
I am positive that helpLabel is bound to the correct object in the nib because it does get the correct styling when this doesn't blow up. Next, here is the init method for this view controller:
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
self.activeChallenge = inActiveChallenge;
}
return self;
Here is the viewDidLoad method where we will sometimes see the crash (bolded). Note, there is a lot going on here but nothing touches the self.helpLabel which is what eventually triggers the crash.
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:FALSE];
self.navigationItem.title = #"Details";
// overlay disclosure creation
self.overlayDisclosure = [CustomColoredDisclosureIndicator accessoryWithColor:self.challengeNameLabel.textColor];
self.overlayDisclosure.highlightedColor = [UIColor whiteColor];
[self.overlayDisclosure addTarget:self action:#selector(overlayViewButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.overlayDisclosure];
[[BruNotificationManager instance] registerForTabUpdated:[[[BruCallback alloc] initWithTarget:self
andCallback:#selector(tabUpdated:)] autorelease]];
[[BruNotificationManager instance] registerForActiveChallengesUpdated:[BruCallback buildFromObject:self
andCallback:#selector(challengesUpdatedLocally)]];
[[BruNotificationManager instance] registerForEarnedRewardsUpdated:[BruCallback buildFromObject:self
andCallback:#selector(rewardsUpdatedLocally:)]];
[super refreshEarnedRewardsForChallenge:self.activeChallenge.challenge.identifier];
[super refreshTabForChallenge:self.activeChallenge.challenge.identifier];
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self
action:#selector(addBeer)];
self.navigationItem.rightBarButtonItem = addButton;
[addButton release];
// Request that the object download its image
BruCallback *imageCallback = [BruCallback buildFromObject:self andCallback:#selector(imageRequestCompleted:withData:)];
self.challengeImageView.image = [self.activeChallenge.challenge retrieveImage:self.bruConnection withCallback:imageCallback];
// Create our help label
**[BruUISettings applyLabelDetailStyle:self.helpLabel];**
self.helpLabel.textColor = AccentSecondaryColor;
self.overlayView.alpha = [BruUISettings standardOverlayViewAlpha];
[BruUISettings applyTableStyle:self.rewardsTable];
[BruUISettings applyScrollViewStyle:self.scrollView];
self.needToUpdateTab = YES;
self.needToUpdateRewards = YES;
self.needToUpdateChallenge = NO;
Here is a trimmed down version of the viewDidUnload method, though I don't see why it would matter in this case:
...
self.helpLabel = nil;
...
[super viewDidUnload];
Finally, my [BruUISettings applyLabelDetailStyle] is a method that applies a centralized style to my label. There are a bunch of places in my code that use this function so that I can change all of the styles for those labels by just changing the one function.
+ (void) applyLabelDetailStyle:(UILabel *)inLabel
{
inLabel.font = [UIFont fontWithName:#"Helvetica Neue" size:12.0];
inLabel.textColor = [UIColor darkGrayColor];
inLabel.backgroundColor = [UIColor clearColor];
}
Any thoughts as to what could be happening here would be greatly appreciated. Thanks again.
After a lot of debugging I found that this was actually due to a memory corruption being caused by the QSStrings library which I was using to generate base64 encoded strings. The crashes seemed to happen randomly but only after this library was invoked. When I switched to a different MD5 library, the issue went away. If you are using this library, I would suggest finding a new one to do base64 encoding. I moved to the one found here: http://www.cocoadev.com/index.pl?BaseSixtyFour
I think the problem happens because you have something wrong in your view that owns your label (view of your ActiveChallengeViewController).
When you set the font of your label, that invokes the setNeedsDisplay of your parent view and because something is wrong, setNeedsDisplay crashs.
Your line :
self.challengeImageView.image = [self.activeChallenge.challenge retrieveImage:self.bruConnection withCallback:imageCallback];
Is it a synchronous connection to retrieve the image ?
Maybe the problem happen here when sometimes the image isn't retrieved from your connection and so the image property of your image view is bad.
But i am not sure because setNeedsDisplay doesn't directly invoke the redraw of the view so i don't know if the debugger catches the error just the after setNeedsDisplay call.
Edit :
I think this answer is bad, if image is not ok, the crash must happen when the imageView image property retains the image but i let the answer in the case of it could help you to point to the real problem.
I have many CALayers which are created on the fly while my app is running, and I need to be able to produce a single bitmap of these, which will later be masked.
When I need to create the mask, the CALayers are already drawn to the background (also using shouldRasterize = YES) , and using renderInContext I am able to get a bitmap. However, as the amount of CAlayers increases, the pause caused by renderInContext gets longer and longer. Is there an alternative I can use to renderInContext, or an alternative way I can use it to stop my app temporarily freezing?
The ideal would be to access the already drawn pixel data directly from memory/buffer/cache without using OpenGL, but I am unsure if this is possible with CoreAnimation.
Thanks, any additional information at all would be very useful!
Rob is right about renderInContext: being the right method to use here. Render in context does actually render the layer's pixel data into a context. Here's a sample application that will draw 10,000 layers on a background thread...
The application does the following:
Create's a UIView
Adds 10,000 layers to that view's layer
Rendering begins when you touch the screen (i.e. it's an iOS sample app)
Creates a background thread
Renders the UIView's layer into a context (which in turn renders its sublayers)
Creates a UIImage with the content of the render context
Adds the new image to the screen in a UIImageView
It does all this while running a timer on the main thread, showing that the background thread actually doesn't block the main thread
Here is the code...
First, create a subview with a lot of layers:
#implementation C4WorkSpace {
UIView *v;
dispatch_queue_t backgroundRenderQueue;
CFTimeInterval beginTime;
NSTimer *timer;
NSInteger timerCallCount;
}
-(void)setup {
//create a view to hold a bunch of CALayers
v = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 400, 400)];
v.center = CGPointMake(384,512);
//create a buch of CALayers and add them to a view
for(int i = 0; i < 10000; i++) {
CALayer *l = [[CALayer alloc] init];
l.frame = CGRectMake([self random:390],[self random:390],10,10);
l.backgroundColor = [UIColor blueColor].CGColor;
l.borderColor = [UIColor orangeColor].CGColor;
l.borderWidth = 2.0f;
[v.layer addSublayer:l];
}
//add the view to the application's main view
[self.view addSubview:v];
}
-(NSInteger)random:(NSInteger)value {
srandomdev();
return ((NSInteger)random())%value;
}
Second, create a method that will start a timer and then triggers the render...
-(void)touchesBegan {
timer = [NSTimer scheduledTimerWithTimeInterval:0.03f target:self selector:#selector(printTime) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[self render];
}
-(void)printTime {
NSLog(#"%d (main thread running)",++timerCallCount);
}
Third, create a render loop with a callback method that puts an image on the screen after rendering is completed.
-(void)render {
NSLog(#"render was called");
//create the queue
backgroundRenderQueue = dispatch_queue_create("backgroundRenderQueue",DISPATCH_QUEUE_CONCURRENT);
//create a async call on the background queue
dispatch_async(backgroundRenderQueue, ^{
//create a cgcontext
NSUInteger width = (NSUInteger)v.frame.size.width;
NSUInteger height = (NSUInteger)v.frame.size.height;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
unsigned char *rawData = malloc(height * bytesPerRow);
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
//render the layer and its subviews
[v.layer renderInContext:context];
//create a callback async on the main queue when rendering is complete
dispatch_async(dispatch_get_main_queue(), ^{
//create an image from the context
UIImage *m = [UIImage imageWithCGImage:CGBitmapContextCreateImage(context)];
UIImageView *uiiv = [[UIImageView alloc] initWithImage:m];
//add the image view to the main view
[self.view addSubview:uiiv];
CGColorSpaceRelease(colorSpace);
CGContextRelease(context);
NSLog(#"rendering complete");
[timer invalidate];
});
});
}
NOTE: if your layers aren't all in the same sublayer, you can easily call a for loop that translates the context to and from the origin of each CALayer and draw each layer individually into the context itself
When I run this I get the following output:
2013-03-18 07:14:28.617 C4iOS[21086:907] render was called
2013-03-18 07:14:28.648 C4iOS[21086:907] 1 (main thread running)
2013-03-18 07:14:28.680 C4iOS[21086:907] 2 (main thread running)
2013-03-18 07:14:28.709 C4iOS[21086:907] 3 (main thread running)
2013-03-18 07:14:28.737 C4iOS[21086:907] 4 (main thread running)
2013-03-18 07:14:28.767 C4iOS[21086:907] 5 (main thread running)
2013-03-18 07:14:28.798 C4iOS[21086:907] 6 (main thread running)
2013-03-18 07:14:28.828 C4iOS[21086:907] 7 (main thread running)
2013-03-18 07:14:28.859 C4iOS[21086:907] 8 (main thread running)
2013-03-18 07:14:28.887 C4iOS[21086:907] 9 (main thread running)
2013-03-18 07:14:28.917 C4iOS[21086:907] 10 (main thread running)
2013-03-18 07:14:28.948 C4iOS[21086:907] 11 (main thread running)
2013-03-18 07:14:28.978 C4iOS[21086:907] 12 (main thread running)
2013-03-18 07:14:29.010 C4iOS[21086:907] 13 (main thread running)
2013-03-18 07:14:29.037 C4iOS[21086:907] 14 (main thread running)
2013-03-18 07:14:29.069 C4iOS[21086:907] 15 (main thread running)
2013-03-18 07:14:29.097 C4iOS[21086:907] 16 (main thread running)
2013-03-18 07:14:29.130 C4iOS[21086:907] 17 (main thread running)
2013-03-18 07:14:29.159 C4iOS[21086:907] 18 (main thread running)
2013-03-18 07:14:29.189 C4iOS[21086:907] 19 (main thread running)
2013-03-18 07:14:29.217 C4iOS[21086:907] 20 (main thread running)
2013-03-18 07:14:29.248 C4iOS[21086:907] 21 (main thread running)
2013-03-18 07:14:29.280 C4iOS[21086:907] 22 (main thread running)
2013-03-18 07:14:29.309 C4iOS[21086:907] 23 (main thread running)
2013-03-18 07:14:29.337 C4iOS[21086:907] 24 (main thread running)
2013-03-18 07:14:29.369 C4iOS[21086:907] 25 (main thread running)
2013-03-18 07:14:29.397 C4iOS[21086:907] 26 (main thread running)
2013-03-18 07:14:29.405 C4iOS[21086:907] rendering complete
renderInContext: is the best tool here, but you don't need to run it on the main thread. Just move this to a background thread and it'll stop freezing your app.