I'm trying to render a UIImage in Objective-C (working on a simple iPhone app (breakout-type thing) to get used to the environment). However, I'm getting an "Error: CGContextDrawImage: invalid context" error when I try and draw it.
My question is: how do I set the context that the DrawAtPoint method of UIImage uses?
Here the relevant code for how I'm initializing / calling everything:
#interface GameItem : NSObject
{
IBOutlet UIImage * sprite;
CGPoint pos;
}
- (id) initWithPositionAndSprite: (CGPoint)placementPosition :(UIImage*) blockImage;
- (void) update;
#property CGPoint pos;
#end
in update:
[sprite drawAtPoint:pos];
And initializing it like:
newBall = [[Ball alloc] initWithPositionAndSprite:CGPointMake(3.0, 4.0) :[UIImage imageNamed:#"ball.png"]];
(Ball inherits from GameItem, doesn't do anything different just yet)
I'm getting the invalid context from the drawAtPoint call afaik. Any help/pointers to somewhere that will explain how to set the context would be greatly appreciated.
Thanks!
If this is to be drawn to the screen, you'll need to locate your drawing code within the -drawRect: method of a UIView (or –drawInContext: of a CALayer). To update its contents, you'd need to call -setNeedsDisplay on the UIView or CALayer. Attempting drawing at any other time will cause the "invalid context" error you're seeing.
Try wrapping the call in UIGraphicsBeginImageContext() and UIGraphicsEndImageContext().
Related
I'll preface this question by saying that I am a total noob when it comes to Objective-C. So please, be patient with my question. :)
So here is my issue. I am basically allowing the user to 'rub out' an image by using alpha blending and such, and then converting the created texture to a CCSprite. I am then able to store the CCSprite in a function within my singleton class. Like so:
erasedTextureSprite = [CCSprite spriteWithTexture:darknessLayer.sprite.texture];
[[MySingleton sharedMySingleton] setRevealTexture:erasedTextureSprite];
Here is the setRevealTexture & getRevealTexture function as well as the revealTexture variable initialisation in my MySingleton.h file:
#interface MySingleton : NSObject
{
CCSprite *revealTexture;
}
...
-(void) setRevealTexture: (CCSprite *) texture;
-(CCSprite *) getRevealTexture;
And here are both functions in my MySingleton.m file:
-(void) setRevealTexture: (CCSprite *) texture
{
NSLog(#"set reveal texture.");
revealTexture = texture;
NSLog(#"%f", [revealTexture boundingBox].size.width);
}
-(CCSprite *) getRevealTexture
{
NSLog(#"got reveal texture.");
NSLog(#"%f", revealTexture.contentSize.width);
return revealTexture;
}
If I set the reveal texture, and then get it right away, it seems to return the sprite correctly. However, if I set the texture and then transition to another scene, it seems to lose it's value, and throws me an error when I try and call the getRevealTexture function.
Question: Why is my function not retaining it's value when I transition between scenes?
If any more clarification is needed please let me know!
Practically there is no point in using your own setter and getter if your not doing anything fancy.
What you are doing is using an iVar which should have been a strong property.
you could achieve the same by doing:
#property (nonatomic, strong) CCSprite *revealTexture;
in your header file.
You would then get the following 2 functions by default:
[[MySingleton sharedMySingleton] revealTexture];
[[MySingleton sharedMySingleton] setRevealTexture:texture];
My next point of failure that I would presume if this doesn't work is that your singleton function is not working properly and your actually getting a new instance each time.
You can easily find this out by doing in the debugger:
po [MySingleton sharedMySingleton]
And seeing the instance that is returned each time.
example for a basic singleton code:
static MySingleton *__sharedMySingleton = nil;
+ (id)sharedMySingleton {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
__sharedMySingleton = [MySingleton new]; // or a specific alloc init function
});
return __sharedMySingleton;
}
Due to the request - here is a short image to explain how to enter debugger commands in xcode 5:
I'm trying to apply Unsynchronized's answer (Drawing waveform with AVAssetReader) while using ARC. There were only a few modifications required, mostly release statements. Many thanks for a great answer! I'm using Xcode 4.2 targeting iOS5 device.
But I'm getting stuck on one statement at the end while trying to invoke the whole thing.
Method shown here:
-(void) importMediaItem {
MPMediaItem* item = [self mediaItem];
waveFormImage = [[UIImage alloc ] initWithMPMediaItem:item completionBlock:^(UIImage* delayedImagePreparation){
[self displayWaveFormImage];
}];
if (waveFormImage) {
[self displayWaveFormImage];
}
}
On the call to initWithMPMediaItem I get the following error:
Automatic Reference Counting Issue. Receiver type 'UIImage' for instance message
does not declare a method with selector 'initWithMPMediaItem:completionBlock:'
Since I do have the method initWithMPMediaItem declared in the class header, I really don't understand why I'm getting this error.
- (id) initWithMPMediaItem:(MPMediaItem*)item
completionBlock:(void (^)(UIImage* delayedImagePreparation))completionBlock;
Been trying to wrap my head around this for several hours now but to no avail. Is my method declaration wrong for this type of method? Thanks!
It looks like initWithMPMediaItem should be declared as an initializer for UIImage. So you should declare it inside a UIImage category in your header file:
#interface UIImage (MPMedia)
- (id) initWithMPMediaItem:(MPMediaItem*)item
completionBlock:(void (^)(UIImage* delayedImagePreparation))completionBlock;
#end
I have a subclass of CALayer called MyLayer:
#interface MyLayer : CALayer
#property (nonatomic,readonly) BOOL busy;
-(void)performTask1;
-(void)performTask2;
-(void)performTask3;
#end
In performTask* functions I say:
-(void)performTask*
{
CAKeyframeAnimation *animation = [...];
...
animation.removedOnCompletion = YES; // "YES" is default anyway
...
[self addAnimation:animation
forKey:TASK*_KEY];
}
The busy property is for the caller and implemented like this:
#dynamic busy;
-(BOOL)busy
{
// i.e. for some specific ids
return ([self animationForKey:TASK1_KEY] != nil ||
[self animationForKey:TASK3_KEY] != nil);
}
What I see is that this approach is not reliable... I can see on the screen that animation is finished (nothing is moving, etc.), while animationForKey: does NOT return nil. The behavior is semi-random... Most of times it goes as expected. But sometimes it takes 1-2 seconds before I start getting nil-s.
This weird behavior disappears, if I set a delegate to animation animation.delegate = self and implement animationDidStop:finished:.
Someone experienced this as well?
Declaring #dynamic causes CALayer to implement the accessor method for you (see Properties on CALayer subclass aren't getting observed by CATransaction and CALayer and CAAnimation's dynamic resolution of unimplemented property accessors). So it's possible that you are just seeing confusion in which version of "busy" is getting called. Why did you declare "#dynamic" in the first place?
There could also be something funky happening with animationForKey, but I'd try removing the "#dynamic" first.
I am trying to make a sprite display on the screen in Cocos2d. But, I don't want to use a CCSprite directly. I have a class Unit which will have some additional properties that I will need later on in my game. The class declaration of Unit is as follows:
#interface Unit : CCSprite {
CCSprite *sprite;
}
-(void)init;
#property(nonatomic, retain) NSNumber *type;
#property(nonatomic, retain) CCSprite *sprite;
#end
And my init method for it looks like this:
-(void)init {
self.sprite = [CCSprite spriteWithFile:#"BasicUnit.png"];
self.sprite.position = ccp(50, 100);
}
Now what I need to do is apply it to the screen. So, I have another class called Playscene which is the scene where I want to display sprites and things. Here is what the init method (the method that should draw the sprites) looks like in Playscene:
-(id) init {
if( (self=[super init] )) {
self.isTouchEnabled = YES;
[army init];
[self addChild:army.sprite];
}
return self;
}
But, when I run this I get a ton of error data including: "terminate called after throwing an instance of 'NSException'" and probably of more importance: "Assertion failure in -[PlayScene addChild:]". I don't know how I can solve this. Any help would be appreciated.
Based on your snippets it is very difficult to know what goes wrong. That said I assume that army in your last snipped is of type Unit. But because that is inside the init() method it could be that it is nil because it is not created here like in army = [[Unit] alloc] initXXX];.
That said I am not sure what you want to accomplish with subclassing CCSprite in your Unit class because you are referencing CCSpirit and so there is not need to subclass it.
Finally your Assertion is probably because your army.spirit is either NIL or it is already added and the assertion inside Coco2d throws the exception (I am assuming that the last snippet is from a subclass of CCNode).
My suggestions:
Don't extend CCSpirit in Unit (not needed as far as I can see)
Don't have a method - (void) init but overwrite - (id) init
Make sure army is properly instantiated using [[Unit alloc] init] (see point above)
Using alloc you need to make sure that if it is assigned to a retaining property that you also release it to offset the alloc.
Hope that helps.
I am having trouble doing this:
CALayer *myLayer = myUIImageView.layer; //works, no error from compiler
CGRect visRect = myLayer.visibleRect; //fat error, see below
The Error I get is:
error: request for member
'visibleRect' in something not a
structure or union
but the documentation says:
visibleRect
Returns the visible region
of the receiver, in its own coordinate
space. (read-only) #property(readonly)
CGRect visibleRect
I have included QuartzCore.framework, CoreGraphics.framework, UIKit.framework, Foundation.framework.
So if that returns a CGRect, why doesn't it work? Any idea?
I'm 99% sure you are missing the import statement. It's not enough to just include the framework in your project.
I just tried this on a brand new project and it worked as expected. The following is what I added to the ViewController.
#import <QuartzCore/QuartzCore.h>
...
- (void)viewDidLoad
{
[super viewDidLoad];
CALayer *test_layer = self.view.layer;
CGRect test_rect = test_layer.visibleRect;
NSLog(#"%f, %f", test_rect.origin.x,
test_rect.size.width);
}
output was:
2009-04-21 17:53:55.999 Throwaway[72422:20b] 0.000000, 320.000000
Your code looks correct. You aren't retaining anything, which could be dangerous, but technically isn't wrong.
the below message usually means that something is wrong with myLayer.
error: request for member 'visibleRect' in something not a structure or union
Are you doing anything inbetween the two lines of code?
Inspect the myLayer object, make sure it's correct. Also, confirm myUIImageView is initialized and not nil.
Also, try bypassing properties, by calling [myLayer visibleRect];