image flickering like a strobe light - ios

I'm trying to create a magnet reset dot for my app, when someone clicks on the reset button it performs a reset of the hardware I use, and also flashes an orange circle from orange to green....
[NSThread detachNewThreadSelector:#selector(myMethod) toTarget:self withObject:nil];
- (void)myMethod {
UIImage *image = [UIImage imageNamed: #"orangeDot.png"];
[dot setImage: image];
sleep(1);
image = [UIImage imageNamed: #"greenDot.png"];
[dot setImage: image];
}
As you can see this occurs on a thread.
Anyway, here's my issue: The orangeDot is not being shown, even though there is a 1 second sleep?

-(void) onTick {
[self battery];
}
- (void) resetMagnet:(UIButton *) sender {
[[MySlateManager sharedManager] doReset];
if(![SettingsManager shared].isVibrationDisabled)
{
[[VibrationHelper sharedInstance]singleShortVibration];
}
NSLog(#"Testttt");
[self flickerOrange];
NSTimer *t = [NSTimer scheduledTimerWithTimeInterval: 0.1
target: self
selector:#selector(onTick)
userInfo: nil repeats:NO];
}
That worked!

Related

How to recognize a touch event on UIImageView while animating in ios using objective c code?

Hi i am animating 4 images in UIImageView by the following code.
But the problem is image is not appearing in UIImageView. If i try removal of swipeImage code then image is appearing in UIImageView. How to make imageview appear in UIImageView ?
Oulet had made to UIImageView property, if i try to set image without animation code, UIImageView has image. Withanimation, UIImageView has no appearance of image. Thanks in advance for any help.
Property
#property (weak , nonatomic )IBOutlet UIImageView *imgslide;
Declaration
int scrlNo;
NSTimer *aTimer;
View did load code
scrlNo = 0;
imgslide.userInteractionEnabled = YES;
[self addGestures];
[self SwipeImages];
Add gesture code
-(void)addGestures //Adding Single Tap Gesture here
{
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageViewTap:)]; //init the TapGesture with the selector
singleTap.cancelsTouchesInView = YES;
[imgslide addGestureRecognizer:singleTap]; //Add it to imgslide, not to self.view
}
ImageViewTap code
-(void)imageViewTap :(UITapGestureRecognizer *) gesture
{
NSLog(#"Clicked image %d", scrlNo);
}
Swipe Images Code or animation code
- (void)SwipeImages
{
if (scrlNo==1) {
imgslide.image = [UIImage imageNamed:#"promo_banner_2.png"];
scrlNo=2;
[aTimer invalidate];
aTimer = nil;
aTimer=[NSTimer scheduledTimerWithTimeInterval:15
target:self
selector:#selector(SwipeImages)
userInfo:nil
repeats:YES];
}else if (scrlNo==0) {
// UIImage * img = [UIImage imageNamed:#"promo_banner_1.png"];
//
// [self.imageViewOutlet setImage:img];
imgslide.image = [UIImage imageNamed:#"promo_banner_1.png"];
scrlNo=1;
[aTimer invalidate];
aTimer = nil;
aTimer=[NSTimer scheduledTimerWithTimeInterval:15
target:self
selector:#selector(SwipeImages)
userInfo:nil
repeats:YES];
}
else if (scrlNo==2) {
// UIImage * img = [UIImage imageNamed:#"promo_banner_3.png"];
//
// [self.imageViewOutlet setImage:img];
imgslide.image = [UIImage imageNamed:#"promo_banner_3.png"];
scrlNo=3;
[aTimer invalidate];
aTimer = nil;
aTimer=[NSTimer scheduledTimerWithTimeInterval:15
target:self
selector:#selector(SwipeImages)
userInfo:nil
repeats:YES];
}
else if (scrlNo==3) {
//
// UIImage * img = [UIImage imageNamed:#"promo_banner_7.png"];
//
// [self.imageViewOutlet setImage:img];
imgslide.image = [UIImage imageNamed:#"promo_banner_7.png"];
scrlNo=0;
[aTimer invalidate];
aTimer = nil;
aTimer=[NSTimer scheduledTimerWithTimeInterval:15
target:self
selector:#selector(SwipeImages)
userInfo:nil
repeats:YES];
}
else if (scrlNo==4) {
}
}
Add this method & load this method on viewDidLoad instead of loading SwipeImages on viewDidLoad
-(void)addTimer
{
aTimer=[NSTimer scheduledTimerWithTimeInterval:15
target:self
selector:#selector(SwipeImages)
userInfo:nil
repeats:YES];
}
Then your viewDidLoad looks like
scrlNo = 0;
imgslide.userInteractionEnabled = YES;
[self addGestures];
[self addTimer];
And Edit SwipeImages to this,
- (void)SwipeImages
{
if (scrlNo==1) {
imgslide.image = [UIImage imageNamed:#"promo_banner_2.png"];
scrlNo=2;
}else if (scrlNo==0) {
imgslide.image = [UIImage imageNamed:#"promo_banner_1.png"];
scrlNo=1;
}
else if (scrlNo==2) {
imgslide.image = [UIImage imageNamed:#"promo_banner_3.png"];
scrlNo=3;
}
else if (scrlNo==3) {
imgslide.image = [UIImage imageNamed:#"promo_banner_7.png"];
scrlNo=0;
}
else if (scrlNo==4) {
}
}

Function after animation (image sequence)

I've searched everywhere but I did not find a proper solution for my problem. I have a image-sequence playing on start up. After this sequence I want to trigger a function. A function that activates an Image which. So the animation will run fluently into the image without break. I found a lot of solutions on the internet e.g. doing it with a timer but running the code via simulator it works, on device it doesn't and gets delayed :(. Is it a good way to set the timer just by testing when the animation is finished? The method "animationDone" is always triggered on the wrong time!
Here my example code:
- (void)viewDidLoad {
imageView.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"Rad_start_00000.png"],
[UIImage imageNamed:#"Rad_start_00001.png"],
[UIImage imageNamed:#"Rad_start_00002.png"],
[UIImage imageNamed:#"Rad_start_00003.png"],
[UIImage imageNamed:#"Rad_start_00004.png"],
[UIImage imageNamed:#"Rad_start_00005.png"],
[UIImage imageNamed:#"Rad_start_00006.png"],
[UIImage imageNamed:#"Rad_start_00007.png"],
[UIImage imageNamed:#"Rad_start_00008.png"],
[UIImage imageNamed:#"Rad_start_00009.png"],
[UIImage imageNamed:#"Rad_start_00010.png"],
[UIImage imageNamed:#"Rad_start_00011.png"],
[UIImage imageNamed:#"Rad_start_00012.png"],
[UIImage imageNamed:#"Rad_start_00013.png"],
[UIImage imageNamed:#"Rad_start_00014.png"],
[UIImage imageNamed:#"Rad_start_00015.png"],
[UIImage imageNamed:#"Rad_start_00016.png"],
[UIImage imageNamed:#"Rad_start_00017.png"],nil];
[imageView setAnimationDuration:0.7];
[imageView setAnimationRepeatCount:1];
[imageView startAnimating];
[self performSelector:#selector(animationDone) withObject:nil afterDelay:1.2];
}
First, you should try using the same interval for both the afterDelay parameter to performSelector and the setAnimationDuration (e.g., 0.7 seconds for both).
If that doesn't quite do what you want, you can programmatically call timer, constantly checking to see if the animation is done. For example, you could set up a display link (it's like a timer, but linked to updates to the display), and check imageView.isAnimating, e.g.:
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UIImageView *imageView;
#property (nonatomic, strong) CADisplayLink *displayLink;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.imageView.animationImages = #[[UIImage imageNamed:#"Rad_start_00000.png"],
[UIImage imageNamed:#"Rad_start_00001.png"],
[UIImage imageNamed:#"Rad_start_00002.png"],
[UIImage imageNamed:#"Rad_start_00003.png"],
[UIImage imageNamed:#"Rad_start_00004.png"],
[UIImage imageNamed:#"Rad_start_00005.png"],
[UIImage imageNamed:#"Rad_start_00006.png"],
[UIImage imageNamed:#"Rad_start_00007.png"],
[UIImage imageNamed:#"Rad_start_00008.png"],
[UIImage imageNamed:#"Rad_start_00009.png"],
[UIImage imageNamed:#"Rad_start_00010.png"],
[UIImage imageNamed:#"Rad_start_00011.png"],
[UIImage imageNamed:#"Rad_start_00012.png"],
[UIImage imageNamed:#"Rad_start_00013.png"],
[UIImage imageNamed:#"Rad_start_00014.png"],
[UIImage imageNamed:#"Rad_start_00015.png"],
[UIImage imageNamed:#"Rad_start_00016.png"],
[UIImage imageNamed:#"Rad_start_00017.png"]];
[self.imageView setAnimationDuration:0.7];
[self.imageView setAnimationRepeatCount:1];
[self.imageView startAnimating];
[self startDisplayLink];
}
- (void)startDisplayLink
{
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(handleDisplayLink:)];
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
- (void)stopDisplayLink
{
[self.displayLink invalidate];
self.displayLink = nil;
}
- (void)handleDisplayLink:(CADisplayLink *)displayLink
{
if (!self.imageView.isAnimating) {
[self stopDisplayLink];
NSLog(#"done");
// do whatever else you want here
}
}
#end
try using the delegate of the animation
and the setAnimationDidStopSelector:
https://developer.apple.com/library/ios/documentation/uikit/reference/UIView_Class/UIView/UIView.html#//apple_ref/occ/clm/UIView/setAnimationDelegate:

Double Tap Recognizer Not Working with NSTimer running

I have a timer:
[NSTimer scheduledTimerWithTimeInterval:(float)jpegInterval/1000 target:self selector:#selector(jpegDownloaderSelector:) userInfo:url repeats:YES];
jpegDownloaderSelector perform the fetching of image from url and set it at imageView as below:
-(void) jpegDownloaderSelector:(NSTimer*)timer{
[self performSelectorInBackground:#selector(jpegDownloader:) withObject:(NSString*)[timer userInfo]];
}
-(void) jpegDownloader:(NSString*)imageUrl{
dispatch_async(dispatch_get_main_queue(), ^{
imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://10.8.9.100:509/jpeg"]];
imageView.image = [UIImage imageWithData:imgData];
});
}
I have also set imageView with gestureRecognizer
[imageView addGestureRecognizer:singleTapRecognizer];
[imageView addGestureRecognizer:doubleTapRecognizer];
where the recognizer definitions are:
singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(functoCall:)];
singleTapRecognizer.numberOfTapsRequired = 1;
singleTapRecognizer.numberOfTouchesRequired = 1;
doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(funcToCall2:)];
doubleTapRecognizer.numberOfTapsRequired = 2;
doubleTapRecognizer.numberOfTouchesRequired = 1;
The problem i have is, when timer starts, and i double tap imageView, double tap recognizer does not response, instead single tap responded.
If i set NO for timer repeats parameter, double tap responded. Thus, i suspect double tap is not responding due to running of background functions that is called by timer.
Anyone has suggestion that i can implement the background function and no problem with recognizing double tap.
When you do this:
dispatch_async(dispatch_get_main_queue(), ^{
You're pushing the task on to the main thread, just after a very short delay. So your image download is done on the main thread and is blocking all other interaction.
Instead, you should run the download on a background thread (dispatch_get_global_queue) and then push back to the main thread ONLY to handle the result.
-(void) jpegDownloader:(NSString*)imageUrl {
dispatch_async(dispatch_get_global_queue(), ^{
imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://10.8.9.100:509/jpeg"]];
dispatch_async(dispatch_get_main_queue(), ^{
imageView.image = [UIImage imageWithData:imgData];
});
});
}

iOS image startAnimating isn't animating (most of the time)

I have an animation that is not animating for some reason.
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationController.navigationBar.hidden = YES;
self.nameLabel.text = [self.name uppercaseString];
self.gradient1.alpha = .9;
self.gradient1.image = [UIImage imageNamed:#"heart.png"];
self.gradient1.animationImages = [[NSArray alloc] initWithObjects:
[UIImage imageNamed:#"gradiant1.png"],
[UIImage imageNamed:#"gradiant2.png"],
...
[UIImage imageNamed:#"gradiant26.png"], nil];
self.gradient1.animationDuration = .5;
self.gradient1.animationRepeatCount = 1;
[self updateStats:nil];
}
-(void)updateStats:(NSTimer*)timer{
Utilities *utility = [[Utilities alloc] init];
[utility getDataWithSSID:self.ssID completion:^(bool *finished, NSArray *objects) {
if (finished){
...
[self.gradient1 startAnimating];
}
self.twoSecTimer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self
selector:#selector(updateStats:)
userInfo:nil
repeats:NO];
}];
}
Sometimes it animates once or twice and then stops even though the timer continues to hit over and over. Other times it just doesn't animate at all. However, I have a couple placeholder buttons that I put on the storyboard that aren't tied to anything and whenever I press one of the buttons it animates the next time the timer hits (Actually whenever I hit the screen even though I don't have any sort of gesture recognizers..). Also, when I add in all the other garbage I want to do in this ViewController it animates every other time it's being called. So I think it's something deeper than me forgetting so set some property.
It might be a better idea to move the animation trigger to a moment when that view is actually visible - hence to viewDidAppear:.
Also your way of creating a recursive timer scheduling makes me shiver. I guess it works fine for you but I would definitely suggest to use the repeats flag set to YES instead.
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationController.navigationBar.hidden = YES;
self.nameLabel.text = [self.name uppercaseString];
self.gradient1.alpha = .9;
self.gradient1.image = [UIImage imageNamed:#"heart.png"];
self.gradient1.animationImages = [[NSArray alloc] initWithObjects:
[UIImage imageNamed:#"gradiant1.png"],
[UIImage imageNamed:#"gradiant2.png"],
...
[UIImage imageNamed:#"gradiant26.png"], nil];
self.gradient1.animationDuration = .5;
self.gradient1.animationRepeatCount = 1;
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
//animate right away...
[self updateStats:nil];
//trigger new animations every two seconds
self.twoSecTimer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self
selector:#selector(updateStats:)
userInfo:nil
repeats:YES];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self stopUpdatingStats];
}
-(void)stopUpdatingStats
{
[self.twoSecTimer invalidate];
}
-(void)updateStats:(NSTimer*)timer
{
NSLog(#"updating");
[self.gradient1 startAnimating];
}

UIImageView not redrawing when image set to nil

I am using a UIImageView to display both still and animated images. So sometimes, I'm using .image and sometimes I'm using .animationImages. This is fine.
Whether it's static or animated, I store the UIImages's in item.frames (see below)
The problem is that I'd like to display a UIActivityIndicatorView in the center of the view when the animation frames are loading. I would like this to happen with no images or frames in there. The line that isn't doing what it's supposed to is:
[self.imageView removeFromSuperview];
As a matter of fact, setting it to another image at this point doesn't do anything either. It seems like none of the UI stuff is happening in here. BTW,
NSLog(#"%#", [NSThread isMainThread]?#"IS MAIN":#"IS NOT");
prints IS MAIN.
The image that is in there will stick around until the new animation frames are all in there (1-2 seconds) and they start animating
This is all being run from a subclass of UIView with the UIImageView as a subview.
- (void)loadItem:(StructuresItem *)item{
self.imageView.animationImages = nil;
self.imageView.image = nil;
[self.spinner startAnimating];
self.item = item;
if (item.frameCount.intValue ==1){
self.imageView.image = [item.frames objectAtIndex:0];
self.imageView.animationImages = nil;
}else {
[self.imageView removeFromSuperview];
self.imageView =[[UIImageView alloc] initWithFrame:self.bounds];
[self addSubview:self.imageView ];
if( self.imageView.isAnimating){
[self.imageView stopAnimating];
}
self.imageView.animationImages = item.frames;
self.imageView.animationDuration = self.imageView.animationImages.count/12.0f;
//if the image doesn't loop, freeze it at the end
if (!item.loop){
self.imageView.image = [self.imageView.animationImages lastObject];
self.imageView.animationRepeatCount = 1;
}
[self.imageView startAnimating];
}
[self.spinner stopAnimating];
}
My ignorant assessment is that something isn't being redrawn once that image is set to nil. Would love a hand.
What I have found is not an answer to the question, but rather a much better approach to the problem. Simply, use NSTimer instead of animationImages. It loads much faster, doesn't exhaust memory and is simpler code. yay!
Do this:
-(void)stepFrame{
self.currentFrameIndex = (self.currentFrameIndex + 1) % self.item.frames.count;
self.imageView.image = [self.item.frames objectAtIndex:self.currentFrameIndex];
}
and this
-(void)run{
if (self.item.frameCount.intValue>1){
self.imageView.image = [self.item.frames objectAtIndex:self.currentFrameIndex];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1/24.0f target:self selector:#selector(stepFrame) userInfo:nil repeats:YES];
}else{
self.imageView.image = [self.item.frames objectAtIndex:0];
}
}

Resources