Cant call methods on instance - objective-c

While working on a project i made a class i instantiate in another class (nothing special) but if i try to call a method for this instance i get this:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[CALayer animate]: unrecognized selector sent to instance
here is the class .h :
#import <QuartzCore/QuartzCore.h>
#interface SFStripe : CALayer {
NSTimer *animation;
}
- (id)initWithXPosition:(NSInteger)positionX yPosition:(NSInteger)positionY;
- (id)initEndedWithXPosition:(NSInteger)positionX yPosition:(NSInteger)positionY;
- (void)animate;
- (void)reduceSize;
- (void)logSomething;
#property NSTimer *animation;
#end
and here the .m :
#import "SFStripe.h"
#implementation SFStripe
#synthesize animation;
- (id)initWithXPosition:(NSInteger)positionX yPosition:(NSInteger)positionY {
self = [CALayer layer];
self.backgroundColor = [UIColor blackColor].CGColor;
self.frame = CGRectMake(positionX, positionY, 5, 20);
self.cornerRadius = 5;
return self;
}
- (id)initEndedWithXPosition:(NSInteger)positionX yPosition:(NSInteger)positionY {
self = [CALayer layer];
self.backgroundColor = [UIColor grayColor].CGColor;
self.frame = CGRectMake(positionX, (positionY + 7.5), 5, 5);
self.cornerRadius = 2;
self.delegate = self;
return self;
}
- (void) logSomething {
NSLog(#"It did work!");
}
- (void)reduceSize {
if (self.frame.size.width > 0 && self.frame.size.height >= 5) {
self.frame = CGRectMake(self.frame.origin.x, (self.frame.origin.y - 0.5), self.frame.size.width, (self.frame.size.height - 0.5));
[self setNeedsDisplay];
NSLog(#"Width: %d", (int)self.frame.size.width);
NSLog(#"Height: %d", (int)self.frame.size.height);
} else {
self.backgroundColor = [UIColor grayColor].CGColor;
self.frame = CGRectMake(self.frame.origin.x, (self.frame.origin.y + 7.5), 5, 5);
[animation invalidate];
}
}
- (void)animate {
animation = [NSTimer scheduledTimerWithTimeInterval:0.03 target:self selector:#selector(reduceSize) userInfo:nil repeats:YES];
}
#end
i imported this class into a fresh project just to see if it is working there but get the same error. here is how i call one of the methods for an instance of the class (i get the same error for all of the methods)
in the mainview.h (of the clean project):
#import <UIKit/UIKit.h>
#import "SFStripe.h"
#import <QuartzCore/QuartzCore.h>
#interface STViewController : UIViewController {
SFStripe *stripe;
}
- (IBAction)animate:(id)sender;
#end
i created the instance and in the .m i let the action call the method for the instance:
#import <QuartzCore/QuartzCore.h>
#import "STViewController.h"
#import "SFStripe.h"
#interface STViewController ()
#end
#implementation STViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
stripe = [[SFStripe alloc] initWithXPosition:30 yPosition:30];
[self.view.layer addSublayer:stripe];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)animate:(id)sender {
[stripe animate];
}
#end
sorry for all the code but i cant find an answer for this problem that helps and hope someone can help me!

This is not the correct way to write an initializer:
- (id)initWithXPosition:(NSInteger)positionX yPosition:(NSInteger)positionY
{
self = [CALayer layer];
...
You're assigning self to be a plain old CALayer instance, rather than an instance of your subclass.
Use self = [super init] instead, and then check that self is not nil.

Related

Using a block in Object-C, I get "Thread 1:EXC_BAD_ACCESS(code=1,address=0x0)"

I want to add GestureRecognizer on an imageView and use a block in the clickAction.
But when I run it, I get this error in the block:
Thread 1:EXC_BAD_ACCESS(code=1,address=0x0)
#import "blockImage.h"
#implementation blockImage
-(instancetype)init{
if (self = [super init]) {
self = [[blockImage alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];
self.tag = 10;
self.backgroundColor = [UIColor redColor];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(tapActionWithBolck:)];
[self addGestureRecognizer:tap];
}
return self;
}
-(void)tapActionWithBolck:(void(^)(NSInteger idx))completion{
completion(10);
}
#end
and
#import "ViewController.h"
#import "blockImage.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
blockImage *img = [[blockImage alloc] init];
[self.view addSubview:img];
}
#end
You can not use method like this with UITapGestureRecognizer
-(void)tapActionWithBolck:(void(^)(NSInteger idx))completion;
it should be like that
-(void)tapAction:(UIGestureRecognizer *)sender;
or
-(void)tapAction;
If you want to use block on tap, you should keep it in variable (in init for example) and than call it in method. But keep in mind about retain cycles.

moving SpriteNode method from gamescene to own class file for first time, node not drawing

I'm trying to move a method from my main GameScene to a new file/class for the first time, so I can keep things cleaner, really just trying to keep the code the same as much as possible and just put it in its own file in the project.
It's a SKSpriteNode method, once I set it up I can see my NSLog showing up but I can't get the node itself to be drawn to the screen, I must be doing something wrong with how I'm creating/assigning/pointing to this spritenode in this new file/class or something?
If someone could spare a sec and have a look and help me understand any help would be fantastic
Currently in GameScene.m I do this method like
#implementation GameScene
{
SKSpriteNode *myNode;
}
//own method in GameScene
- (SKSpriteNode *)createMyNode
{
myNode = [SKSpriteNode spriteNodeWithColor:[SKColor greenColor] size:CGSizeMake(20, 20)];
myNode.position = CGPointMake(50, 50);
//etc
return myNode;
}
-(void)didMoveToView:(SKView *)view {
[self addChild: [self createMyNode]];
}
//it then is successfully created on screen
Now I'm trying to add the above into a new file/class it's own file etc
newclassfile.m
#import "newclassfile.h"
#implementation newclassfile {
SKSpriteNode myNode
}
- (SKSpriteNode *)createMyNode
{
myNode = [SKSpriteNode spriteNodeWithColor:[SKColor greenColor] size:CGSizeMake(20, 20)];
myNode.position = CGPointMake(50, 50);
//etc
NSLog(#"newclassfile myNode check");
return myNode;
}
newclassfile.h
#import <SpriteKit/SpriteKit.h>
#interface newclassfile : SKSpriteNode
-(SKSpriteNode*)createMyNode;
#end
then back at GameScene.m
//import header
#import "newclassfile.h"
-(void)didMoveToView:(SKView *)view {
newclassfile *myNode=[[newclassfile alloc]init];
[myNode createMyNode];
}
I hope to see my new spritenode but don't see it, I do however see the NSLog(#"newclassfile myNode check"); in console which tells me the method is being run I guess.
Any help with this would be much appreciated
In newclassfile.h, add the following method prototypes
#import <SpriteKit/SpriteKit.h>
#interface newclassfile : SKSpriteNode
+ (instancetype) createMyNode;
+ (instancetype) spriteNodeWithColor:(UIColor *)color size:(CGSize)size;
- (id) initWithColor:(UIColor *)color size:(CGSize)size;
#end
In newclassfile.m, declare a method to initialize a sprite node and a convenience methods to alloc/init a new node.
#import "newclassfile.h"
#implementation newclassfile
+ (instancetype) createMyNode
{
return [[newclassfile alloc] initWithColor:[SKColor greenColor] size:CGSizeMake(20, 20)];
}
+ (instancetype) spriteNodeWithColor:(UIColor *)color size:(CGSize)size
{
return [[newclassfile alloc] initWithColor:color size:size];
}
- (id) initWithColor:(UIColor *)color size:(CGSize)size
{
if (self=[super initWithColor:color size:size]) {
self.position = CGPointMake(200, 200);
// Create a physics body
self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:size];
}
return self;
}
#end
in GameViewController.m, change the following
scene.scaleMode = SKSceneScaleModeAspectFill;
to this
scene.scaleMode = SKSceneScaleModeResizeFill;
and lastly in GameScene.m, create a new sprite node with
- (void) didMoveToView:(SKView *)view {
newclassfile *myNode = [newclassfile createMyNode];
[self addChild:myNode];
}

getting into the loop when doing progress view, ios

I am creating progress view by using CALayer by following
Header class
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#interface ProgressBar : UIView
#property (strong, nonatomic) CALayer *subLayer;
#property (nonatomic) CGFloat progress;
#end
Implementation class
#implementation ProgressBar
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.progress = 0;
self.backgroundColor = [UIColor whiteColor];
self.subLayer = [CALayer layer];
self.subLayer.frame = self.bounds;
self.subLayer.backgroundColor = [UIColor orangeColor].CGColor;
[self.layer addSublayer:self.subLayer];
}
return self;
}
- (void)setProgress:(CGFloat)value {
NSLog(#"what is going on here");
if (self.progress != value) {
self.progress = value;
[self setNeedsLayout];
}
}
- (void)layoutSubviews {
CGRect rect = [self.subLayer frame];
rect.size.width = CGRectGetWidth([self bounds]) * self.progress;
[self.subLayer setFrame:rect];
}
In my viewcontroller, I am doing
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.pBar = [[ProgressBar alloc] initWithFrame:CGRectMake(0, 50, 320, 10)];
[self.view addSubview:self.pBar];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)click:(id)sender {
[self.pBar setProgress:.8];
}
When (IBAction)click is fired, I am getting into the infinitive loop like the picture below
Does anyone know what I am getting into this loop. Please advice me on this issue. Thanks
The problem is that your setProgress: method calls the setProgress: method - recursion.
- (void)setProgress:(CGFloat)value {
NSLog(#"what is going on here");
if (self.progress != value) {
self.progress = value; // <-- This calls [self setProgress:value]
[self setNeedsLayout];
}
}
Change the bad line to:
_progress = value;
Setting the ivar directly is always required when you implement the setter method of a property.

CCLayer is null

I am trying to change the color of a CCLayerColor called bgColorLayer, however when I check to see if it is initialized it returns null. I have a color picker that calls the setBGColor: method. I know the colorpicker is calling the method and it is spitting out the correct colors. I am just at a loss as to why the bgColorLayer is null.
This is Cocos2D for Mac.
Any thoughts on why?
In my AppDelegeate method I have an IBOUTLET that is is tied to the NSColorWell
- (IBAction)colorwellBackground:(id)sender {
NSLog(#"Color Well: %#", [sender color]);
// Yes I know the sender color isn’t passing the correct value
AnimationViewerLayer * bkg = [AnimationViewerLayer alloc];
[bkg setBGColor:[sender color]];
}
AnimationViewerLayer.h
#interface AnimationViewerLayer : CCLayer
{
CCLayerColor * bgColorLayer;
}
+ (CCScene *) scene;
#end
AnimationViewLayer.m
#import "AnimationViewerLayer.h"
#implementation AnimationViewerLayer
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
AnimationViewerLayer *layer = [AnimationViewerLayer node];
[scene addChild: layer];
return scene;
}
-(id) init
{
if( (self=[super init])) {
float red = 25.0 * 255;
bgColorLayer = [CCLayerColor layerWithColor:ccc4(57, 109, 58, 255)];
[self addChild:bgColorLayer z:1];
}
return self;
}
- (void) setBGColor: (ccColor3B) color{
NSLog(#"SET BG COLOR");
[bgColorLayer setColor:ccRED];
}
- (void) dealloc {
[super dealloc];
}
#end

How to use drawRect to draw in a existing view?

I'm doing a GPS tracking app. Every time it receives a Latitude/Longitude it converts it to (x,y) coordinates and calls drawRect to draw a line between two (x,y) pairs.
However, the drawRect method just clear all the old contents before it draw new thing. How I can make the drawRect to draw new thing on the existing canvas? Thanks in advance
here is my viewController.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#class routetrack;
#interface simpleDrawViewController : UIViewController <CLLocationManagerDelegate> {
CLLocationManager *locationManager;
IBOutlet routetrack *routeroute;
float latOld;
float longOld;
float latNew;
float longNew;
}
- (IBAction) gpsValueChanged;
#property (nonatomic,retain) CLLocationManager *locationManager;
#property (retain,nonatomic) routetrack *routeroute;
ViewController.m
#import "simpleDrawViewController.h"
#import "routetrack.h"
#implementation simpleDrawViewController
#synthesize locationManager,btn,routeroute;
- (IBAction) gpsValueChanged{
[routeroute setLocationX:longNew setLocationY:latNew
oldLocation:longOld oldLocationY:latOld ];
[routeroute setNeedsDisplay];
}
- (void)viewDidLoad {
[super viewDidLoad];
if (nil == locationManager)
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void) locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
if (oldLocation) {
latOld=oldLocation.coordinate.latitude;
longOld=oldLocation.coordinate.longitude;
latNew=newLocation.coordinate.latitude;
longNew=newLocation.coordinate.longitude;
}
else {
latOld=53.3834;
longOld=-6.5876;
latNew=53.3835;
longNew=-6.5877;
}
[self gpsValueChanged];
}
- (void) locationManager:(CLLocationManager *)manager didFailwithError:
(NSError *)error
{
if([error code] == kCLErrorDenied)
[locationManager stopUpdatingLocation];
NSLog(#"location manger failed");
}
- (void)dealloc {
[locationManager release];
[super dealloc];
}
#end
my drawing class, a subclass of UIView
#import "routetrack.h"
#implementation routetrack
- (void) setLocationX:(float) loX setLocationY:(float) loY
oldLocation:(float) oldX oldLocationY:(float) oldY {
self->locationX = loX;
self->locationY = loY;
self->oldLoX = oldX;
self->oldLoY = oldY;
scaleX= 36365.484375;
scaleY= 99988.593750;
maxLat= 53.3834;
maxLog= -6.5976;
drawX = locationX;
drawY = locationY;
tempX=(maxLog - drawX) * scaleX;
tempY=(maxLat - drawY) * scaleY;
lastX = (int) tempX;
lastY = (int) tempY;
drawX = oldLoX;
drawY = oldLoY;
tempX=(maxLog - drawX) * scaleX;
tempY=(maxLat - drawY) * scaleY;
startX = (int) tempX;
startY = (int) tempY;
}
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
- (void)drawRect:(CGRect)rect {
int firstPointX = self->startX;
int firstPointY = self->startY;
int lastPointX = self->lastX;
int lastPointY = self->lastY;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextSetLineWidth(context, 2.0);
CGContextMoveToPoint(context, firstPointX, firstPointY);
CGContextAddLineToPoint(context, lastPointX , lastPointY);
CGContextStrokePath(context);
}
UIView does not have a canvas model. If you want to keep a canvas, you should create a CGLayer or a CGBitmapContext and draw onto that. Then draw that in your view.
I would create an ivar for a CGLayerRef, and then drawRect: would look something like this (untested):
- (void)drawRect:(CGRect)rect {
if (self.cgLayer == NULL) {
CGLayerRef layer = CGLayerCreateWithContext(UIGraphicsContextGetCurrent(), self.bounds, NULL);
self.cgLayer = layer;
CGLayerRelease(layer);
}
... various Core Graphics calls with self.cgLayer as the context ...
CGContextDrawLayerInRect(UIGraphicsContextGetCurrent(), self.bounds, self.cgLayer);
}
Whenever you wanted to clear your canvas, just self.cgLayer = NULL.
setCgLayer: would be something like this:
- (void)setCgLayer:(CGLayerRef)aLayer {
CGLayerRetain(aLayer);
CGLayerRelease(cgLayer_);
cgLayer_ = aLayer;
}
What exactly to you mean by "old contents"? If you want to draw a line from your GPS data, you have to draw all points every time in the implementation of drawRect.