I'm trying to draw something simple on screen when NSSetUncaughtExceptionHandler gets called but nothings happen.
Is there any other way to catch an exception and quickly draw something on screen?
NSSetUncaughtExceptionHandler(&exceptionHandler);
void exceptionHandler(NSException *exception)
{
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(10.0, 10.0)];
[path moveToPoint:CGPointMake(10.0, 10.0)];
[path addLineToPoint:CGPointMake(10.0, 450.0)];
[path addLineToPoint:CGPointMake(310.0, 450.0)];
[path addLineToPoint:CGPointMake(310.0, 10.0)];
[path addLineToPoint:CGPointMake(10.0, 10.0)];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
[APP_DELEGATE_WINDOW.rootViewController.view.layer addSublayer:shapeLayer];
[APP_DELEGATE_WINDOW makeKeyAndVisible];
}
I'm not sure that the NSSetUncaughtExceptionHandler is a good place to draw stuff on the screen.
Sets the top-level error-handling function where you can perform
last-minute logging before the program terminates.
Most crash reporters carefully log the trace and try not to "touch" anything besides.
If you really want to draw something (what?) you should maybe catch a particular exception first. Just not any uncaught exception.
I think Rivera is right, about NSSetUncaughtExceptionHandler. And maybe you need to write: [path fill];
P.S : I'm sorry that i write here, comments disabled, small reputation...
Like Rivera said, you won't be able to rescue the application at this stage, but if you really needed to draw something here, you could probably launch another process (which you would have to design) just to show this image.
Related
I need to draw a separator line with some dots on it. I have decided I will do this using the draw method, as opposed to including images of the separator. I will do this for performance and for customisability, as the separator changes sometimes.
Now I have looked into the draw() method on UIView and I have noticed that Apple suggests using GLKView when drawing using OpenGL.
For a simple separator, won't it be too much of a hassle to call OpenGL? Or is the OpenGL overhead negligible? When would I want to use the native UIKit draw() then?
FYI I don't know either method, but want to learn both methods, so don't reply "what you know best". I am simply asking about performance.
OpenGL uses GPU instead of CPU for computation. If you are making something like a gaming app, then you can think of using OpenGL. I believe you want to draw a line in an iOS App. For that you can either use drawRect method in UIView or create a shapeLayer and add it as a sublayer.
The following examples will show you:
CAShapeLayer *simpleLine = [CAShapeLayer layer];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0, 80)];
[path addLineToPoint:CGPointMake(300, 80)];
simpleLine.lineWidth = 1.0;
simpleLine.path = path.CGPath;
simpleLine.strokeColor = [[UIColor blackColor] CGColor];
[[self.view layer] addSublayer:simpleLine];
For using drawRect, you are supposed to do this inside a Custom UIView as opposed to the above method.
- (void)drawRect:(CGRect)rect {
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0, 80)];
[path addLineToPoint:CGPointMake(300, 80)];
path.lineWidth = 1.0;
[[UIColor blueColor] setStroke];
[path stroke];
}
If your separator parameters changes and if you are making an app, it's better to use drawRect method. You can call this method anytime by using [CustomUIView setNeedsDisplay:YES]
Edit
What you're asking for is circle over line. You can do that by drawing UIBezierPath for line first and then add UIBezierPath for circle later.
Normal Line
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(10.0, 10.0)];
[path addLineToPoint:CGPointMake(100.0, 100.0)];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor redColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
[self.view.layer addSublayer:shapeLayer];
Dotted Line
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(10.0, 10.0)];
[path addLineToPoint:CGPointMake(100.0, 100.0)];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor redColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
shapeLayer.lineDashPattern = #[#4, #2];
[self.view.layer addSublayer:shapeLayer];
I am having an app in which I am doing some calculations and based on that I want to draw a traverse like shown below.
Here is an image of the traverse.
I have distance of AB, BC and so on.
Based on this values I need to draw an image shown above.
I know how to draw a line using UIBezierPath and using the below code.
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(100.0, 100.0)];
[path addLineToPoint:CGPointMake(100.0, 100.0)];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
But how to draw this with this calculations. I am confused with it. I just want some guidance on it.
My main aim is to draw image with the design pattern shown below.
EDIT
I have a distance of 50.0 and an angle of 37 for line AB. How to draw a line AB from that?
Please help.
Any help will be appreciated. Thanks.
Example:
- (void)drawTraverseWithFirstPoint:(CGPoint)firstPoint secondPoint:(CGPoint)point thirdPoint:(CGPoint)thirdPoint fourthPoint:(CGPoint)fourthPoint andLastPoint:(CGPointLastPoint) {
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:your_start_point];
[path addLineToPoint:firstPoint];
[path addLineToPoint:secondPoint];
[path addLineToPoint:thirdPoint];
[path addLineToPoint:fourthPoint];
[path addLineToPoint:lastPoint];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
}
Just do the calculations first and pass it as paramethers or pass an Array with points however it is easier for you, i hope you will understand my example good day.
I am trying to make a game where a ball is bouncing off a user drawn line. The code for drawing the line is included below and works fine but how would I remove the line once the ball makes contact with it or the player draws a new line?
path = [UIBezierPath bezierPath];
// Start Coords of Line
[path moveToPoint:CGPointMake(pos2x, pos2y)];
[path addLineToPoint:CGPointMake(pos1x, pos1y)];
// End Coords of Line
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor whiteColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
[self.view.layer addSublayer:shapeLayer];
Thanks in advance!
When you say this:
[self.view.layer addSublayer:shapeLayer];
...also keep a reference to that shape layer. For example, you might have a property currentShapeLayer:
self.currentShapeLayer = shapeLayer;
Now that you have a reference, you can easily remove the layer:
[self.currentShapeLayer removeFromSuperlayer];
Programming iOS is all about keeping references to things you know you'll need later on. If there are more paths, meaning more shape layers, you will need a more complex, intelligent way of distinguishing which is which and which one you want to remove.
I copied the code below from the Stanford ios7 course for adding a Bezier path to a view. however, when I included this code in ViewDidLoad it didn't show anything on the screen
UIBezierPath *path = [[UIBezierPath alloc] init];
[path moveToPoint:CGPointMake(75, 10)];
[path addLineToPoint: CGPointMake(160, 150)];
[path addLineToPoint:CGPointMake(10, 150)];
[[UIColor whiteColor] setStroke];
[[UIColor whiteColor] setFill];
[path stroke];
[path fill];
Afterwards, I added this log statement NSLog(#"path: %#", path); which prints this ominous error message.
This is a serious error. This application, or a library it uses, is
using an invalid context and is thereby contributing to an overall
degradation of system stability and reliability. This notice is a
courtesy: please fix this problem. It will become a fatal error in an
upcoming update.
Can you explain what I am doing wrong?
I have accomplished this by creating a CAShapeLayer, and adding it as a sublayer of the view's layer. What's neat is that you can use the UIBezierPath's CGPath attribute to set up the layer.
CAShapeLayer *layer = [CAShapeLayer layer];
layer.path = path.CGPath;
layer.strokeColor = [UIColor whiteColor].CGColor;
[self.view.layer addSublayer:layer];
The error message is exactly correct. You are using drawing commands, but you are not inside a drawing (graphics) context. Hence your commands are just thrown away (and are bad).
You should give drawing commands only when you are within a graphics context. There are two main such situations:
You're in a UIView subclass's drawRect:.
You've created an image graphics context with UIGraphicsBeginImageContextWithOptions.
You are in neither situation. You can make a bezier path object, constructing the path, but you cannot draw the object; commands like setStroke and stroke are thus illegal.
I'm getting a BAD ACCESS error using [UIBezierPath CGPath] with CAShapeLayer under ARC. I've tried bridging in various ways but I'm not clear if that is the problem. I have isolated the crash to using the result of the makeToPath method:
maskLayer = [CAShapeLayer layer];
maskLayer.path = [self makeToPath];
But this doesn't crash:
maskLayer = [CAShapeLayer layer];
maskLayer.path = [self makeFromPath];
Is there something invalid with the path created by makeToPath? I'm planning to use the from and to paths with a CABasicAnimation once I sort this crash out. What is the correct ARC bridging for CGPathRefs from UIBezierPath?
-(CGPathRef)makeToPath
{
UIBezierPath* triangle = [UIBezierPath bezierPath];
[triangle moveToPoint:CGPointZero];
[triangle addLineToPoint:CGPointMake(self.view.frame.size.width,0)];
[triangle addLineToPoint:CGPointMake(0, self.view.frame.size.height)];
[triangle closePath];
return [triangle CGPath];
}
-(CGPathRef)makeFromPath
{
UIBezierPath*rect = [UIBezierPath bezierPathWithRect:self.view.frame];
return [rect CGPath];
}
UPDATE So I changed my .h file per an answer below but I am still getting the crash
-(CGPathRef)makeToPath CF_RETURNS_RETAINED;
-(CGPathRef)makeFromPath CF_RETURNS_RETAINED;
I also tried making my methods return a UIBezierPath instance per the answer here (shown below). Still no success. Anyone want to give me the longform explanation on how to fix this?
maskLayer.path = [[self makeToPath] CGPath];// CRASHES
morph.toValue = CFBridgingRelease([[self makeToPath] CGPath]);// CRASHES
-(UIBezierPath*)makeToPath
{
UIBezierPath* triangle = [UIBezierPath bezierPath];
[triangle moveToPoint:CGPointZero];
[triangle addLineToPoint:CGPointMake(self.view.frame.size.width,0)];
[triangle addLineToPoint:CGPointMake(0, self.view.frame.size.height)];
[triangle closePath];
return triangle;
}
The problem is with returning the CGPath. The value returned is a CGPathRef which is not covered by ARC. The UIBezierPath you create is released after the method ends. Thus also freeing the CGPathRef.
You can specify a source annotation to let ARC know your intent:
In the .h file:
-(CGPathRef)makeToPath CF_RETURNS_RETAINED;
-(CGPathRef)makeFromPath CF_RETURNS_RETAINED;
As the other poster pointed out, you are returning a CGPath reference taken from a UIBezierPath object that goes out of scope at the end of the method. As the docs on the UIBezierPath CGPath property say:
The path object itself is owned by the UIBezierPath object and is
valid only until you make further modifications to the path.
You need to create a copy of your CGPath and return that:
-(CGPathRef)makeToPath
{
UIBezierPath* triangle = [UIBezierPath bezierPath];
[triangle moveToPoint:CGPointZero];
[triangle addLineToPoint:CGPointMake(self.view.frame.size.width,0)];
[triangle addLineToPoint:CGPointMake(0, self.view.frame.size.height)];
[triangle closePath];
CGPathRef theCGPath = [triangle CGPath];
return CGPathCreateCopy(theCGPath);
}
The way I read the link to the llvm project, I think that the cf_returns_retained qualifier is intended to tell the caller the memory management policy for the returned value, rather than doing the retain for you.
Thus I think you would both need to create a copy of the path AND add the cf_returns_retained qualifier. I'm not clear on the syntax of that qualifier, however. (Never used it before.)
Assuming the other poster had the right syntax, it would look something like this:
-(CGPathRef)makeToPath CF_RETURNS_RETAINED;
{
UIBezierPath* triangle = [UIBezierPath bezierPath];
[triangle moveToPoint:CGPointZero];
[triangle addLineToPoint:CGPointMake(self.view.frame.size.width,0)];
[triangle addLineToPoint:CGPointMake(0, self.view.frame.size.height)];
[triangle closePath];
CGPathRef theCGPath = [triangle CGPath];
return CGPathCreateCopy(theCGPath);
}