I am fairly new to objective-c and iOS programming in Xcode, and while making my first app I ran into the problem of creating barriers around the edge of the screen which the object cannot pass through. I tried placing objects at the boundary and using CGRectIntersectsRect, but the collision between the boundary and the main object is not registered. Does anyone know how I would go about in doing this?
this is the code that I have used for the object's movement:
const float rate= 0.025;
NSTimer *goLeft;
NSTimer *goRight;
- (IBAction)right {
goRight=[NSTimer scheduledTimerWithTimeInterval:rate
target:self
selector:#selector(goRight)
userInfo:nil
repeats:YES];
if (goRight == nil){
goRight=[NSTimer scheduledTimerWithTimeInterval:rate target:self selector:#selector(goRight) userInfo:nil repeats:YES];
}
}
- (IBAction)left{
goLeft=[NSTimer scheduledTimerWithTimeInterval:rate
target:self
selector:#selector(goLeft)
userInfo:nil
repeats:YES];
if (goLeft == nil){
goLeft=[NSTimer scheduledTimerWithTimeInterval:rate target:self selector:#selector(goLeft) userInfo:nil repeats:YES];
}
}
-(IBAction)stopLeft{
[goLeft invalidate];
goLeft=nil;
}
-(IBAction)stopRight{
[goRight invalidate];
goRight=nil;
}
-(void)goLeft{
_userToken.center =CGPointMake(_userToken.center.x -20, _userToken.center.y);
}
-(void)goRight{
_userToken.center =CGPointMake(_userToken.center.x +20, _userToken.center.y);
}
And for collision with object at left border (userToken and friendly are both UIImageView). However when they collide NSLog is not executed.
-(void)checkForCollision{
if (CGRectIntersectsRect(_userToken.frame, _friendly.frame)){
NSLog(#"Left Intersect");
}
}
You don't say what _userToken.frame and _friendly.frame are set to when you test - it's a good idea to log them while testing so you can manually verify.
An alternative approach, if the valid screen area is a rect, is to check the intersection of the token and the valid area and verify that it is equal to the token frame:
if (CGRectEqualToRect(CGRectIntersection(_userToken.frame, validFrame), _userToken.frame)) { ...
It's important when checking by any method that the frames are in the same coordinate space (that the views have the same superview, or that you convert them to the same common superview) - again, logging will help you to verify this.
Aside:
Trying to recreate the timer if it just failed is unlikely to help. And you should really check for an existing timer and invalidate it before creating a new timer (otherwise you could end up with multiple timers running and no way to stop them).
Related
I want to create a CVPixelBuffer, since it need a CGImageRef I used [VLCThumbnailer fetchThumbnail] method and crashed with
"Assertion failed: ([thumbnailer dataPointer] == *p_pixels), function
unlock, file
/Users/apple/opensource/vlc-ios/ImportedSources/VLCKit/Sources/VLCMediaThumbnailer.m,
line 74." neither can I find the route"/Users/apple".
Here is the code:
- (void)viewDidLoad {NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(catchThumbnail) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];}
- (void)catchThumbnail {
if (self.vlcPlayer.hasVideoOut) {
[self.thumbnailer fetchThumbnail];
}}
// VLCMediaThumbnailerDelegate
-(void)mediaThumbnailer:(VLCMediaThumbnailer *)mediaThumbnailer didFinishThumbnail:(CGImageRef)thumbnail {
NSLog(#"-----%#------",thumbnail);
}
worth mentioning: first time it logged :MobileVLCKitPlayer[2736:1068033] -----<CGImage 0x7f803bed56e0>------,but SECOND time crashed
Could someone help me,thanks a lot! :)
I have fixed it, if somebody facing the same issue, remember to set thumbnailer.thumbnail = nil after handling it everytime :)
I am using an NSTimer to call a method which is titled Lose. I had a timer which when it ran out, it called Lose, but I lost everything due to a hard drive error. After trying to code it all again, I can't seem to get the method to be called.
Timer = [NSTimer timerWithTimeInterval:timeMax target:self selector:#selector(Lose) userInfo:nil repeats:NO];
Lose is declared in my .h file, like this:
-(void)Lose;
Also, my method looks like this:
-(void)Lose{
Text.hidden = NO;
scoreLabel.hidden = NO;
Target.hidden = YES;
Targetx.hidden = YES;
if (Score > highScoreNumber) {
highScoreAchieved.hidden = NO;
highScoreNumber = Score;
}
}
The variable timeMax is an int declared in my .h file, like last time.
whenever a target is tapped in my game, timeMax becomes .03 seconds shorter. I do it like this:
timeMax = 5 - (Score * 0.03);
I don't remember it looking different before the massive hardware failure, but why isnt it working?
You have to schedule the timer on a run loop or just use this line instead which schedules it for you:
Timer = [NSTimer scheduledTimerWithTimeInterval:timeMax
target:self
selector:#selector(Lose)
userInfo:nil
repeats:NO];
It's also a good idea to always back up your code...which reminds me.
I am working on an iOS app which provides/makes calls from app. We can make two calls one after another. First time we are making 1st call. Once call get established, the NSTimer should be fired and it would show the duration of the call.
For this I am doing following for timer
self.switchTimer1 = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(setTimerLabel1:)
userInfo:nil
repeats:YES];
[self.switchTimer1 fire];
after establishing this first call, user can make second call.
Once second call gets established, it would fire second timer.
if (hasSecondCall)
{
self.switchTimer2 = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(setTimerLabel2:)
userInfo:nil
repeats:YES];
timeSec=0;
timeMin=0;
[self.switchTimer2 fire];
}
It's working fine while making first time of both calls.
Suppose if I ended 2nd call and again I made call, that time 2nd timer before establishing the call the timer automatically calling and once call established, the timer incrementing value very fast like double values showing. Like, 2,4, 6, etc.
For secondtimer after firing method following
- (void)setTimerLabel2:(NSTimer *)timer {
timeSec=timeSec+1;
NSLog(#"timeSec+1 %d",timeSec+1);
if (timeSec == 60)
{
timeSec = 0;
timeMin=timeMin+1;
}
NSString* timeNow = [NSString stringWithFormat:#"%02d:%02d", timeMin, timeSec];
[_switchCallLCD setStatus:timeNow labelNumber:2];
}
While disconnecting call we calling following
- (void)endingCallWithId:(UInt32)call_id {
if (hasSecondCall&& call_id==_current_call) {
if (self.switchTimer2) {
//NSLog(#"self.predictNumber %#",self.predictNumber);
self.predictNumber=self.predictNumber2;
[_lcd setText:self.predictNumber];
[self.switchTimer2 invalidate];
self.switchTimer2 = nil;
[self.switchTimer2 release];
[_switchCallLCD setStatus:NSLocalizedString(#"call ended",nil) labelNumber:2];
timeSec = 0;
timeMin = 0;
}
I have searched so many forums regarding this issue, but I couldn't figure out solution. I heard, if we use multiple timers there is some issue like this.
You likely still have the previous instance of the timer(s) running. When you make a second set of calls you then have 2 instances of switchTimer1 running and 2 instances of switchTimer2 running.
As soon as you end a call, you need to invalidate the timer:
[self.switchTimer1 invalidate];
and then set it to nil for good measure:
self.switchTimer1 = nil;
I have the following pair of functions in a MessagePlayerViewController(UIViewController) which move a slider to reflect playback progress of an AVAudioPlayer:
-(void)startTrackingPlayback
{
if(!self.isPlaying)
{
self.isPlaying = YES;
self.playbackTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(updateProgress) userInfo:nil repeats:YES];
}
}
-(void)stopTrackingPlayback
{
if(self.playbackTimer)
{
if(self.playbackTimer.isValid)
{
[self.playbackTimer invalidate];
self.playbackTimer = nil;
}
}
self.isPlaying = NO;
}
Intermittently, and following no discernible pattern, I get an Exec Bad Access ith the top two items in the stack as:
0 objc_msgSend
1 [MessagePlayerViewController stopTrackingPlayback];
How can this be? I check if the timer exists before I call isValid and I check isValid before I invalidate it.
Using a breakpoint I can see that the timer does exist, but the error occurs when I set it to nil. If I remove this line, I get an identical error on the line:
[self.playbackTimer invalidate];
I would suggest inspecting the way you use your MessagePlayerViewController. It seems to me that both the stack trace and the behaviour you describe hint at the fact that it is the controller that is being deallocated earlier than your timer.
Take into account the fact that the run loop where the timer is scheduled will keep the timer alive.
Maybe the fix is as simple as calling invalidate in your controller's dealloc method (or somewhere else where it makes sense), but if you do not provide more code, it is not possible to say.
I am trying to invoke a function that contains ccactioninterval in Cocos3d. I want to call that function at specific time intervals.When I tried NSTimer , i found that it works sometimes and sometimes not.
NSTimer makeTarget=[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(createTargets) userInfo:nil repeats:YES];
Here createTargets is the function that contains action events. when i run the function straightit works fine for single time. Problem comes when i try to schedule it. I ve tried different methods already explained for related questions . But nothing worked for me. . . .
Here is the code
-(void) addTargets {
NSTimer *makeTarget = [NSTimer scheduledTimerWithTimeInterval:2.0
target:self selector:#selector(createTargets) userInfo:nil repeats:YES];
}
-(void)createTargets {
CC3MeshNode *target = (CC3MeshNode*)[self getNodeNamed: #"obj1"];
int minVal=-5;
int maxVal=5;
float avgVal;
avgVal = maxVal- minVal;
float Value = ((float)arc4random()/ARC4RANDOM_MAX)*avgVal+minVal ;
[target setLocation:cc3v(Value, 5.0, 0.0)];
CCActionInterval *moveTarget = [CC3MoveBy actionWithDuration:7.0 moveBy:cc3v(0.0, -10.0, 0.0)];
CCActionInterval *removeTarget = [CCCallFuncN actionWithTarget:self selector:#selector(removeTarget:)];
[target runAction:[CCSequence actionOne:moveTarget two:removeTarget]];
}
-(void)removeTarget:(CC3MeshNode*)targ {
[self removeChild:targ];
targ=nil;
}
Without much code its hard to tell what you issues is, but here are some things to try apologies if any of this is obvious.
Are you holding onto a reference to the timer?
This might be useful for debugging. If you have a property called makeTargetTimer, then you could do this:
NSTimer * makeTargetTimer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(createTargets) userInfo:nil repeats:YES];
self.makeTargetTimer = makeTargetTimer // Save to a property for later use (or just use an iVar)
The only way to stop a re-occurring timer is to invalidate it. Therefore you could check to see if its been invalidated.
BOOL isInvalidated = [self.makeTargetTimer isValid];
Also you might want to do this in your dealloc method anyway:
- (void) dealloc {
[_makeTargetTimer invalidate]; // Stops the timer from firing (Assumes ARC)
}
Are you scrolling when the even should be received?
If you want the timer to be fired while scrolling then you need to use NSRunLoopCommonModes. There is a excellent expiation in this question.
[[NSRunLoop currentRunLoop] addTimer:makeTargetTimer forMode:NSRunLoopCommonModes];
What is your implementation of createTargets like?
Have you put NSLog statements on the body of this method. Are you certain its not being called?