Hide a UIlabel after some seconds - ios

I'm using this following code to hide a UILabel after some seconds. Unfortunately if the user close the view during the NSInvocation is in progress the app crashes
- (void)showStatusBarwithText:(NSString*)text{
lblNotification.hidden=NO;
NSInvocation* invoc = [NSInvocation invocationWithMethodSignature:[lblNotification methodSignatureForSelector:#selector(setHidden:)]];
[invoc setTarget:lblNotification];
[invoc setSelector:#selector(setHidden:)];
lblNotification.text=text;
BOOL yes = YES;
[invoc setArgument:&yes atIndex:2];
[invoc performSelector:#selector(invoke) withObject:nil afterDelay:1];
}
and that's the error
*** -[UILabel setHidden:]: message sent to deallocated instance 0x1a8106d0
How can I solve? I have tried using
[NSObject cancelPreviousPerformRequestsWithTarget:lblNotification]
In the - (void)viewDidDisappear:(BOOL)animated but it doesn't work.

Here is how you should use performSelector
- (void)showStatusBarwithText:(NSString*)text{
lblNotification.hidden=NO;
[self performSelector:#selector(hideLabel) withObject:nil afterDelay:1];//1sec
}
-(void)hideLabel{
lblNotification.hidden= YES;
}
or with the timer
[NSTimer scheduledTimerWithTimeInterval:1//1sec
target:self
selector:#selector(hideLabel)
userInfo:nil
repeats:NO];

Why don't you just use dispatch_afer? The syntax is much more clear:
- (void)showStatusBarwithText:(NSString*)text{
lblNotification.hidden=NO;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
lblNotification.hidden = YES;
});
}

It's because you pass lblNotification instead of infoc object here:
[NSObject cancelPreviousPerformRequestsWithTarget:lblNotification]
It will be better to do this way:
- (void)showStatusBarwithText:(NSString*)text{
lblNotification.hidden=NO;
lblNotification.text=text;
[lblNotification performSelector:#selector(setHidden:) withObject:#(1) afterDelay:2];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated]
[NSObject cancelPreviousPerformRequestsWithTarget:lblNotification];
}

Related

UIPageViewController scroll automatically issue

I have implemented automatic scrolling of UIPageViewController after every 5 seconds using timer like this:
_bannerTimer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:#selector(loadNextController)
userInfo:nil
repeats:YES];
- (void)loadNextController
{
self.index++;
HeaderAdVC *nextViewController;
if(self.index>arrayImages.count-1)
{
self.index=0;
[pageIndicator setCurrentPage:0];
nextViewController = [self viewControllerAtIndex:0];
}
else
{
nextViewController = [self viewControllerAtIndex:self.index];
}
[pageIndicator setCurrentPage:self.index];
[pageController setViewControllers:#[nextViewController]
direction:UIPageViewControllerNavigationDirectionForward
animated:YES
completion:nil];
}
and removing the timer in viewWillDisappear
-(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[_bannerTimer invalidate];
}
Problem :
My problem is when the loadNextController method is called my app stop responding.
If i switch to next page still getting the same problem on every view.
Do some changes like below , do all non-ui task in background thread and all UI operation in Main thread ,try this
- (void)loadNextController
{
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
self.index++;
HeaderAdVC *nextViewController;
if(self.index>arrayImages.count-1)
{
self.index=0;
[pageIndicator setCurrentPage:0];
nextViewController = [self viewControllerAtIndex:0];
}
else
{
nextViewController = [self viewControllerAtIndex:self.index];
}
dispatch_async(dispatch_get_main_queue(), ^{
[pageIndicator setCurrentPage:self.index];
[pageController setViewControllers:#[nextViewController]
direction:UIPageViewControllerNavigationDirectionForward
animated:YES
completion:nil];
});
});
}
i hope this will help you ..

UIView animation not performing immediately after the first run.

So basically I have two methods that I run when the user clicks an Annotation in the map.
- (void) methodA{
[UIView animateWithDuration:kRequestButtonAnimationDuration animations:^(void){
self.button.transform = CGAffineTransformMakeTranslation(0,-(self.navigationController.view.frame.size.height - self.button.frame.origin.y)); }]; }
- (void) methodB:(double)value andBoolean:(BOOL) boolean{
if (self.timer) {
[self.timer invalidate];
self.timer = nil;
}
if (boolean) {
self.timer = [NSTimer scheduledTimerWithTimeInterval:value target:self selector:#selector(pullButtonUp) userInfo:nil repeats:NO];
} else{
self.timer = [NSTimer scheduledTimerWithTimeInterval:value target:self selector:#selector(showTabBar) userInfo:nil repeats:NO];
}}
-(void)pullButtonUp{
[(LLTabBarViewController*)self.tabBarController showTabBarAnimated];}
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{
[self methodA];
[self methodB:2.0 andBoolean:TRUE];
}
So during the first time I select an annotation, it works well: it runs methodA, then methodB after 2.0 seconds.
But when I try it again, it runs both A and B at the same time (basically methodA waits 2.0 seconds to execute).
Could this be related to Loops?
How should I track this problem? Any instrument? Which one?
I am a bit lost, help me please!
I think this is what you want to do
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
__weak typeof(self) weakSelf = self;
BOOL arbitraryBool = YES;
[UIView animateWithDuration:2
animations:^{
self.button.transform = CGAffineTransformMakeTranslation(0,-(self.navigationController.view.frame.size.height - self.button.frame.origin.y));
} completion:^(BOOL finished) {
if (finished) {
if (arbitraryBool) {
[weakSelf pullButtonUp];
} else {
[weakSelf showTabBar];
}
}
}]:
}

Multiple NsTimer view transition

i am trying to using a Nstimer view transition on multiple view controllers but if i copy and paste it i get an error saying Duplicate declaration of method . how would i fix it ? please explain in your answer how to do this . i found out how to do this from this link .
http://x-code-tutorials.com/2013/06/19/nstimer-trigger-uiviewcontroller-transition/
- (void)viewDidAppear:(BOOL)animated {
[self startTimerMethod];
}
- (void) startTimerMethod {
transitionTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(transitionView) userInfo:nil repeats:NO];
}
- (void) transitionView {
[self performSegueWithIdentifier:#"viewTransition" sender:self];
}
- (void)viewDidAppear:(BOOL)animated {
[self startTimerMethod];
}
- (void) startTimerMethod {
transitionTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(transitionView) userInfo:nil repeats:NO];
}
- (void) transitionView {
[self performSegueWithIdentifier:#"viewTransition" sender:self];
}
You have copy and paste below three methods two times let it define or declare single time:-
-(void)viewDidAppear:(BOOL)animated
-(void) startTimerMethod
-(void) transitionView

UIView animation not working in iOS 7

I am working on a sample project in which I have a vertical scrollview and a horizontal scrollview. The vertical scrollview has a number of subviews. In scrollviewDidScroll I am performing some actions. Along with this I now want to animate a subview inside the vertical scrollview when that particular subview is visible on the screen. For this I am doing a certain calculation which is correct. The animation is as follows:
The subview contains multiple custom views. I am trying to animate(reducing and then again increasing alpha value for the view) each of these views in some particular time sequence(so that the animation looks to be in sequence). For this I am posting notification to the views and the animation sequence and logic is perfect according to what I want.
But I am facing the problem that the code is executing when I put the breakpoint, but the animation does not show up. In case if I post the notification after I stop scrolling then the animation happens perfectly fine. But I want is the animation to happen even when I am scrolling and the view is on screen.
I am adding my code snippet as below:
SubView: (Inside my scrollview)
- (void)animateSequenceTemplate {
if (!hasSequenceTemplateAnimated) {
[self performSelector:#selector(animateSequenceSlides) withObject:nil afterDelay:0];
hasSequenceTemplateAnimated = YES;
}
else {
return;
}
}
- (void)animateSequenceSlides {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:imageAsset forKey:#"assetMO"];
[[NSNotificationCenter defaultCenter]postNotificationName:AnimateSequenceSlide object:nil userInfo:userInfo];
}
Subviews inside the above subview:
- (void)animateSlideView:(NSNotification *)notification {
NSDictionary *userInfo = notification.userInfo;
if ([userInfo objectForKey:#"assetMO"] == assetMO) {
[[NSNotificationCenter defaultCenter]removeObserver:self name:AnimateSequenceSlide object:nil];
CGFloat duration = 0.035;
float delay = (self.slideCount * duration);
CGFloat timeDelay = 0;
[self performSelector:#selector(animationPhase1) withObject:nil afterDelay:delay];
timeDelay = delay + duration;
[self performSelector:#selector(animationPhase2) withObject:nil afterDelay:timeDelay];
if (self.slideCount == (self.maxSlideCount - 1)) {
timeDelay += duration * 18; //No animation till 18 frames
}
else {
timeDelay += duration;
}
[self performSelector:#selector(animationPhase3) withObject:nil afterDelay:timeDelay];
timeDelay += duration;
[self performSelector:#selector(animationPhase4) withObject:nil afterDelay:timeDelay];
}
}
- (void)animationPhase1 {
[UIView animateWithDuration:0.035 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^ {
[self setAlpha:0.85];
}completion:^(BOOL finished) {
}];
}
There occurs two scenarios inside - (void)animateSequenceTemplate:
I call as [self animateSequenceSlides];. In this case the animation does not show up.
[self performSelector:#selector(animateSequenceSlides) withObject:nil afterDelay:0.0f];. In this case the animation shows up but after the scrollview rests.
I am compelled to use the UIView animation using perform selector because if I remove this and use either nested UIView animate blocks / or directly call these methods, then again animation does not show up. Now at lease it shows up after the I rest scrolling.
I would like advice on a solution or any guess on what mistake I might be making.
It possible, that you executing it not on the main queue.
dispatch_async(dispatch_get_main_queue, block()) might help.
When working with animation, main queue the only place for executing code, that makes animation happen.
EDIT:
[self performSelector:#selector(animationPhase1) withObject:nil afterDelay:delay];
I’m not sure, where it happens, but I don't think on main thread.
Try this:
[self performSelectorOnMainThread:#selector(animationPhase1)
withObject:nil
waitUntilDone:YES];
I’m not sure about delay, that’s why I prefer GCD functions and blocks.
Finally, i got the solution to my question and it is working very fine as expected.
Changes Made:
From "animateSequenceTemplate", calling "animateSequenceSlides"
method directly
In "animateSlideView" method mentioned above, instead of using perform selector I created NSTimer object with the required delay,
repeat set to NO, and adding the timer in the current run loop
Did the same for calling all the four animationPhase methods
Code works fine as accepted
- (void)animateSequenceTemplate {
if (!hasSequenceTemplateAnimated && self.isSequenceSlideCreated) {
hasSequenceTemplateAnimated = YES;
[self animateSequenceSlides];
}
}
- (void)animateSlideView:(NSNotification *)notification {
NSDictionary *userInfo = notification.userInfo;
if ([userInfo objectForKey:#"assetMO"] == assetMO) {
[[NSNotificationCenter defaultCenter]removeObserver:self name:AnimateSequenceSlide object:nil];
CGFloat duration = 0.035;
float delay = (self.slideCount * duration);
CGFloat timeDelay = 0;
NSTimer *animate1 = [NSTimer scheduledTimerWithTimeInterval:delay target:self selector:#selector(animationPhase1) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop]addTimer:animate1 forMode:NSRunLoopCommonModes];
timeDelay = delay + duration;
NSTimer *animate2 = [NSTimer scheduledTimerWithTimeInterval:timeDelay target:self selector:#selector(animationPhase2) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop]addTimer:animate2 forMode:NSRunLoopCommonModes];
if (self.slideCount == (self.maxSlideCount - 1)) {
timeDelay += duration * 18; //No animation till 18 frames
}
else {
timeDelay += duration;
}
NSTimer *animate3 = [NSTimer scheduledTimerWithTimeInterval:timeDelay target:self selector:#selector(animationPhase3) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop]addTimer:animate3 forMode:NSRunLoopCommonModes];
timeDelay += duration;
NSTimer *animate4 = [NSTimer scheduledTimerWithTimeInterval:timeDelay target:self selector:#selector(animationPhase4) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop]addTimer:animate4 forMode:NSRunLoopCommonModes];
}
}
I am not satisfied with the goodness of the code structure. If you think of any other smart way of doing it, please share.

NSTimer automatically increases when I change view controller

In my viewController I inserted a timer for a calculation of numbers taken directly from my database of Parse.com.
The timer is working correctly, were inserted in viewDidAppear and in ViewDidDisappear in such a way as to lock the sequence when changing view controller.
The problem I have is that when I change the view controller with the Push the timer does not stop you give an example:
I open the application and the calculation is done correctly with the animation of NSTimer.
Change View, and then I go back with the back button to view where the timer at this point I see that the numbers contiunano to increase every time I change view and go back ...
Can you explain where I'm wrong?
-(void)viewDidAppear:(BOOL)animated {
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
[self.navigationController.navigationBar setBackgroundImage:[UIImage new]forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage = [UIImage new];
[self.navigationController.navigationBar setBackgroundColor:[UIColor clearColor]];
self.title = NSLocalizedString(#"", nil);
[self animatelayertopoint:0];
[self AnimationMenuView:600];
[self QueryForViewPrincipal];
[self QueryForCollectionView];
[self ShowBadgeNumber];
[self Timer];
[collectionView reloadData];
}
-(void)Timer{
timer = [NSTimer scheduledTimerWithTimeInterval:0.012 target:self selector:#selector(CalcoloMediadiLaurea) userInfo:nil repeats:YES];
}
-(void) CalcoloMediadiLaurea{
PFUser *CurrentUser = [PFUser currentUser];
NSNumber *NumeroUndici = [NSNumber numberWithInt:11];
NSNumber *NumeroTre = [NSNumber numberWithInt:3];
NSNumber *ValoreMediaPonderata = [CurrentUser objectForKey:FF_USER_MEDIA_PONDERATA];
int FFValoreTre = [NumeroTre intValue];
int FFValoreUndici = [NumeroUndici intValue];
double MediaPonderata = [ValoreMediaPonderata doubleValue];
double RisultatoMoltiplicazioneValoriPonderataUndici;
RisultatoMoltiplicazioneValoriPonderataUndici = MediaPonderata * FFValoreUndici;
double RisultatoMediaLaurea;
RisultatoMediaLaurea = RisultatoMoltiplicazioneValoriPonderataUndici / FFValoreTre;
CalcoloMediaLaureaLabel.text = [NSString stringWithFormat:#"%.1f", FFTickValoreMediaLaurea ];
FFTickValoreMediaLaurea++;
if(FFTickValoreMediaLaurea > RisultatoMediaLaurea){
[timer invalidate];
timer = nil;
}
}
-(void)viewDidDisappear:(BOOL)animated {
[self animatelayertopoint:0];
[self AnimationMenuView:600];
[self CalcoloMediadiLaurea];
}
The timer get rescheduled again on view did appear without getting invalidated to the previous one.You should make instance of timer in .h and then hold the reference of timer in it .And on view did appear when you are scheduling the timer just invalidate it and then schedule it again.
if([self.timer isValid])
{
[self.timer invalidate];
self.timer=nil;
self.timer=[NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(CalcoloMediadiLaurea:) userInfo:nil repeats:YES];
}
This worked for me which is along the lines of the above answer but a little more explicitly stated.
- (void)viewWillAppear:(BOOL)animated
{
NSTimeInterval secondsBetween = [endDate timeIntervalSinceDate:currentTime];
secondsLeft = secondsBetween;
[self countdownTimer];
}
- (void)viewDidDisappear:(BOOL)animated
{
[self.timer invalidate];
self.timer = nil;
}
//Initiates timer
- (void)countdownTimer
{
[self.timer invalidate];
self.timer = nil;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(updateCounter:) userInfo:nil repeats:YES];
}
It's because you are creating new timers without invalidating old ones. The timers don't get invalidated automatically, you have to do it yourself. So if U go on second view and return before your invalidate condition is true you will create new timer and have two of them :)... And so on.

Resources