Using NSTimer with two intervals - objective-c

I'm creating an app that converts text to Morse code, and then flash it out using the iPhone's flashlight. I have used string replacement, to convert the content of a NSString to Morse code.
// some of the code :
str = [str stringByReplacingOccurrencesOfString:#"5" withString:n5];
str = [str stringByReplacingOccurrencesOfString:#"6" withString:n6];
str = [str stringByReplacingOccurrencesOfString:#"7" withString:n7];
str = [str stringByReplacingOccurrencesOfString:#"8" withString:n8];
str = [str stringByReplacingOccurrencesOfString:#"9" withString:n9];
str = [str stringByReplacingOccurrencesOfString:#"0" withString:n0];
NSString *morseCode = [[NSString alloc] initWithFormat:str];
self.label.text = morseCode;
I have found a script that turns the iPhone's flashlight on and off, with adjustable intervals using NSTimer. But I can't figure out how to add two different intervals, one for the dot and one for the Morse dash.
- (void)viewDidLoad
{
[super viewDidLoad];
int spaceTime;
spaceTime = 1;
int dashTime;
dashTime = 2;
int dotTime;
dotTime = 0.8;
strobeIsOn = NO;
strobeActivated = NO;
strobeFlashOn = NO;
flashController = [[FlashController alloc] init];
self.strobeTimer = [
NSTimer
scheduledTimerWithTimeInterval:spaceTime
target:self
selector:#selector(strobeTimerCallback:)
userInfo:nil
repeats:YES
];
self.strobeFlashTimer = [
NSTimer scheduledTimerWithTimeInterval:dotTime
target:self
selector:#selector(strobeFlashTimerCallback:)
userInfo:nil
repeats:YES
];
}
- (void)strobeTimerCallback:(id)sender {
if (strobeActivated) {
strobeIsOn = !strobeIsOn;
// ensure that it returns a callback. If no, returns only one flash
strobeFlashOn = YES;
} else {
strobeFlashOn = NO;
}
}
- (void)strobeFlashTimerCallback:(id)sender {
if (strobeFlashOn) {
strobeFlashOn = !strobeFlashOn;
[self startStopStrobe:strobeIsOn];
} else {
[self startStopStrobe:NO];
}
}
Should I use two timers or can I have one with different intervals? Should I put the content of the string in an array?
I'm new in Obj-C ..

I would try to make a recursive function:
parseAndFlash
{
NSString *codeString = #"-.-. --- -.. .";
int currentLetterIndex = 0;
//codeString and currentLetterIndex should be declared outside this function as members or something
double t_space = 2, t_point = 0.5, t_line = 1, t_separator = 0.1;
double symbolDuration = 0;
if(currentLetterIndex >= [codeString length])
return;
char currentLetter = [codeString characterAtIndex:currentLetterIndex];
switch (currentLetter) {
case '-':
symbolDuration = t_line;
[self flashOnFor:t_line];
break;
case '.':
symbolDuration = t_point;
[self flashOnFor:t_point];
break;
case ' ':
symbolDuration = t_space;
[self flashOff];
break;
default:
break;
}
currentLetterIndex ++;
symbolDuration += t_separator;
[self performSelector:#selector(parseAndFlash) withObject:nil afterDelay:symbolDuration];
}

you can try to run code in sequence on background treed and sleep it for as long as you need. It would be much easier code to write and maintain than to use bunch of timers.
// execute in background
[self performSelectorInBackground:#selector(doTheMagic) withObject:nil];
- (void)doTheMagic {
NSLog(#"Turn ON");
[NSThread sleepForTimeInterval:1];
NSLog(#"Turn OFF");
[NSThread sleepForTimeInterval:0.1f];
NSLog(#"Turn ON");
[NSThread sleepForTimeInterval:1.0f];
// ...
}

Related

[AVFoundation]: Thumbnail generation hangs after some time

I have server application which serves informations about the videos on server. One of the requests is URL:PORT/video/:id/:time ... which I parse and get the video file, prepare the time and ask method to generate the thumbnail. It works for first 5 minutes really fast (generates image under 200ms), then the process of image generation suddenly takes even 10 seconds...
Do you have any idea why ? Code used:
-(NSImage *)thumbnailAt: (CMTime) time
withSize: (NSSize) size
error: (NSError **) error {
#autoreleasepool {
if ( self.assetChanged ) {
self.generate = [[AVAssetImageGenerator alloc] initWithAsset:_asset];
self.generate.appliesPreferredTrackTransform = TRUE;
self.assetChanged = NO;
}
self.generate.maximumSize = NSSizeToCGSize(size);
CGImageRef imageReference = [self.generate copyCGImageAtTime:time actualTime:NULL error:error];
if ( imageReference != nil ) {
NSImage* ret = [[NSImage alloc] initWithCGImage:imageReference size:size];
CGImageRelease(imageReference);
return ret;
}
return nil;
}
}
Any idea what I am doing wrong or any suggestion how to do it differently (eg. using AVAssetReader) ?
In the end I solved it by using different approach: I used asynchronous images
-(NSImage *)createAsyncThumbnailAtTime:(CMTime)time withSize:(NSSize)size {
if ( self.updated ) {
[_generator cancelAllCGImageGeneration]; // Stop we did not comply in time.
_generator = [AVAssetImageGenerator assetImageGeneratorWithAsset:_asset];
_generator.maximumSize = NSSizeToCGSize(size);
}
NSMutableArray * times = [NSMutableArray array];
[times addObject:[NSValue valueWithCMTime:time]];
__block NSImage * image;
__block BOOL finished = NO;
[_generator generateCGImagesAsynchronouslyForTimes:times completionHandler:^(CMTime requestedTime, CGImageRef imageRef, CMTime actualTime, AVAssetImageGeneratorResult result, NSError *error) {
image = nil;
if ( result == AVAssetImageGeneratorCancelled ) {
image = nil;
NSLog(#"CANCELLED %#", error);
finished = YES;
}
else
if ( result == AVAssetImageGeneratorFailed ) {
image = nil;
NSLog(#"FAILDED %#", error);
finished = YES;
}
else /* result == AVAssetImageGeneratorSucessed */
{
image = [[NSImage alloc] initWithCGImage:imageRef size:size];
finished = YES;
}
}];
while ( !finished ) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
return thumbnail->image;
}

Stop pinwheel of death in infinite loop Objective C

I am writing a simple timer program for myself in objective c for my mac. The timer counts down properly, but I get the spinning pinwheel of death. How can I make the pinwheel go away? I think its because I have an infinite loop but there must be someway to bypass it.
I have an IBAction that triggered on a button click (the button is start). And from there, it calls another function that does the work.
Here is my IBAction:
- (IBAction)timerStart:(id)sender {
self.timerDidPause = NO;
[self timerRunning];
}
And here is timerRunning:
- (void)timerRunning {
for (;;) {
usleep(1000000);
if (self.timerDidPause == YES) {
}
else {
if (self.seconds == 0) {
if (self.minutes == 0) {
[self timerDone];
break;
}
else {
self.seconds = 59;
self.minutes = self.minutes - 1;
[self formatTimerLabel:self.hours :self.minutes :self.seconds];
}
}
else {
self.seconds = self.seconds - 1;
[self formatTimerLabel:self.hours :self.minutes :self.seconds];
}
}
}
}
In this function, the function formatTimerLabel is called so here is that:
- (void)formatTimerLabel:(int)hours
:(int)minutes
:(int)seconds {
NSString *minuteString = [[NSString alloc] init];
NSString *secondString = [[NSString alloc] init];
if (minutes < 10) {
minuteString = [NSString stringWithFormat:#"0%d", minutes];
}
else {
minuteString = [NSString stringWithFormat:#"%d", minutes];
}
if (seconds < 10) {
secondString = [NSString stringWithFormat:#"0%d", seconds];
}
else {
secondString = [NSString stringWithFormat:#"%d", seconds];
}
[self.timerLabel setStringValue:[NSString stringWithFormat:#"%d:%#:%#", hours, minuteString, secondString]];
[self.timerLabel display];
}
You're causing the UI thread to hang with your loop. After a couple of seconds of that, the OS switches the cursor to a pinwheel.
You need to look into NSTimer and the Timer Programming Guide to schedule the timer to run outside of the UI thread.

EXC_BAD_ACCESS Error for type NSString

I'm new to this mac application development.
The app is working fine for some data and the app crashes for few entries.
-(void)presentClientsss
{
[productVendorTextField setStringValue:[NSString stringWithFormat:#"%#", [[popUpVendor selectedItem] title]]];
NSMenuItem *tempMenuItem = [popUpVendor selectedItem];
NSString *selectedItemTitle = [tempMenuItem title];
for (int k = 0; k < [appDelegate.vendorInfoArr count]; k++)
{
VendorInfo *tempCustomerInfoModel = [appDelegate.vendorInfoArr objectAtIndex:k];
if ([tempCustomerInfoModel.vendorName isEqualToString:selectedItemTitle])
{
oldVendorIde = [NSString stringWithFormat:#"%ld", tempCustomerInfoModel.rowId];
NSLog(#"Selected RowID = %#",oldVendorIde);
break;
}
}
}
I'm sending the oldVendorIdestring to next method.
- (ItemModel *)itemNodelWithAttributes {
isProductIdExist = NO;
if ([senderInfo isEqualToString:#"nP"]) {
for (int i = 0; i < [appDelegate.itemsArr count]; i++) {
ItemModel *tempIM = [appDelegate.itemsArr objectAtIndex:i];
if ([tempIM.productId isEqualToString:[[productIdTextField stringValue] uppercaseString]]) {
isProductIdExist = YES;
break;
}
}
}
if ([senderInfo isEqualToString:#"eP"]) {
for (int i = 0; i < [appDelegate.itemsArr count]; i++) {
ItemModel *tempIM = [appDelegate.itemsArr objectAtIndex:i];
if (tempIM.itemId == itemIdentity) {
if ([tempIM.productId isEqualToString:[[productIdTextField stringValue] uppercaseString]]) {
isProductIdExist = NO;
}
}
else if ([tempIM.productId isEqualToString:[[productIdTextField stringValue] uppercaseString]]) {
isProductIdExist = YES;
}
}
}
int tempItemExists = [self saveProductImage:[[productIdTextField stringValue] uppercaseString]];
NSLog(#"oldVendorIde =%#",oldVendorIde);
ItemModel *iM = [[ItemModel alloc] initWithItemId:itemIdentity defaultItemMinimumValue:[productMinValueTextField floatValue] staticItemPrice:[productPriceTextField doubleValue] dynamicItemQuantity:[productCurrentStockTextField doubleValue] staticItemDescription:[productDescriptionTextField stringValue] prodId:[[productIdTextField stringValue] uppercaseString] itemVendor:oldVendorIde itemImgExists:tempItemExists stockAvailable:0 itemNotes:[notesTextField string] BarcodeDesc:[BarcodeDescTextView stringValue]];
return iM;
}
In this method the same oldVendorIde is working fine for some data and some time it gets crashed at this point.
The oldVendorIde sometime doesnot get any value in itemNodelWithAttributes method and the app crashes at that point.
Can Sone help me to solve the issue.. Thanks in advance..
The text from a UITextField is accessed through the text property ([productIdTextField text]), not through stringValue.

Cocos2D - Detecting collision

I am a beginner in cocos2d and im facing a problem with detecting collision for my coins.
Sometimes it works sometimes it doesn't.
So basically, im creating a game which the user (ship) have to avoid the obstacles and collect coins on the way. The collision of the obstacle works well but not for the coins.
I was thinking maybe the loops for creating many coins is the problem but im not sure.
Can anyone help?
My codes:
- (void)update:(ccTime)dt{
double curTime = CACurrentMediaTime();
if (curTime > _nextBridgeSpawn) {
float randSecs = [self randomValueBetween:3.0 andValue:5.0];
_nextBridgeSpawn = randSecs + curTime;
float randX = [self randomValueBetween:50 andValue:500];
float randDuration = [self randomValueBetween:8.0 andValue:10.0];
CCSprite *bridge = [_bridge objectAtIndex:_nextBridge];
_nextBridge++;
if (_nextBridge >= _bridge.count) _nextBridge = 0;
[bridge stopAllActions];
bridge.position = ccp(winSize.width/2, winSize.height);
bridge.visible = YES;
[bridge runAction:[CCSequence actions:
[CCMoveBy actionWithDuration:randDuration position:ccp(0, -winSize.height)],
[CCCallFuncN actionWithTarget:self selector:#selector(setInvisible:)],
nil]];
this is where i declare my coins (continued from the update method)
int randCoin = [self randomValueBetween:0 andValue:5];
_coin = [[CCArray alloc] initWithCapacity:randCoin];
for(int i = 0; i < randCoin; ++i) {
coin = [CCSprite spriteWithFile:#"coin.png"];
coin.visible = NO;
[self addChild:coin];
[_coin addObject:coin];
}
float randCoinX = [self randomValueBetween:winSize.width/5 andValue:winSize.width - (border.contentSize.width *2)];
float randCoinY = [self randomValueBetween:100 andValue:700];
float randCoinPlace = [self randomValueBetween:30 andValue:60];
for (int i = 0; i < _coin.count; ++i) {
CCSprite *coin2 = [_coin objectAtIndex:i];
coin2.position = ccp(randCoinX, (bridge.position.y + randCoinY) + (randCoinPlace *i));
coin2.visible = YES;
[coin2 runAction:[CCSequence actions:
[CCMoveBy actionWithDuration:randDuration position:ccp(0, -winSize.height-2000)],
[CCCallFuncN actionWithTarget:self selector:#selector(setInvisible:)],
nil]];
}
}
this is to check for collision (also in the update method)
for (CCSprite *bridge in _bridge) {
if (!bridge.visible) continue;
if (CGRectIntersectsRect(ship.boundingBox, bridge.boundingBox)){
bridge.visible = NO;
[ship runAction:[CCBlink actionWithDuration:1.0 blinks:5]];
}
}
}
//this is the collision for coins which only work at times
for (CCSprite *coin2 in _coin) {
if (!coin2.visible) continue;
if (CGRectIntersectsRect(ship.boundingBox, coin2.boundingBox)) {
NSLog(#"Coin collected");
coin2.visible = NO;
}
}
}
Thank you.
Why you just don't check distances?
float dist = ccpDistance(ship.position, coin2.position);
float allowedDist = ship.contentSize.width*0.5 + coin2.contentSize.width*0.5;
if (dist<allowedDist){
NSLog(#"Collision detected");
}
If your sprites are not on the same layer, these layers should have at least same positions.
what is phone in the last piece of code? you check there if it's boundingBox intersects coins one, but I cannot see it anywhere else. Another one, boundingBox will work only if your objects have the same parent, because it returns "local" rect, relatieve to it's parent
another one point is that in case of too fast movement speed of your objects it is possible, that they will pass throw each other during tick time. I mean, that one update will be called before collision, so it will not detect it and the next one will be called after collision was finished, so it will not detect it either.
I've solved my problem by creating a timer in init and call it every 10 secs to create my coins.
My codes:
-(void) createCoins:(ccTime)delta{
CGSize winSize = [CCDirector sharedDirector].winSize;
int randCoin = [self randomValueBetween:0 andValue:10];
_coin = [[CCArray alloc] initWithCapacity:randCoin];
for(int i = 0; i < randCoin; i++) {
coin = [CCSprite spriteWithFile:#"coin30p.png"];
coin.visible = NO;
[self addChild:coin];
[_coin addObject:coin];
}
float randCoinX = [self randomValueBetween:winSize.width/5 andValue:winSize.width - (border.contentSize.width *2)];
float randCoinY = [self randomValueBetween:100 andValue:700];
float randCoinPlace = [self randomValueBetween:30 andValue:60];
for (int i = 0; i < _coin.count; i++) {
CCSprite *coin2 = [_coin objectAtIndex:i];
coin2.position = ccp(randCoinX, (winSize.height + randCoinY) + (randCoinPlace *i));
coin2.visible = YES;
[coin2 runAction:[CCSequence actions:
[CCMoveBy actionWithDuration:8 position:ccp(0, -winSize.height-2000)],
[CCCallFuncN actionWithTarget:self selector:#selector(setInvisible:)],
nil]];
}
}
in the update method:
for (CCSprite *coins in _coin){
if (!coins.visible) continue;
if (CGRectIntersectsRect(phone.boundingBox, coins.boundingBox)) {
NSLog(#"Coin collected");
coins.visible = NO;
}
}
Thank you everyone for the help(:

execution stops on [textView insertText:] without exception!

I am writing a very simple OSX app. In this app, there is a main thread that keeps updating some stuff, then calculates some statistics and prints them on a textView.
While developing, i used the same received IBAction to perform this cycle. I got it all working, then switched to NSThread to prevent the UI from locking while computing.
As soon as i did that, the app started running very few cycles (about 7-8), then the whole app freezes without any exception. By debugging, i noticed that it freezes when trying to print statistics on the textView, and i have absolutely no clue about how to solve this. It works if not inside a thread...
Anyone can help? Code below. Thanks in advance :)
-(IBAction) Evolve:(id)sender{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[NSThread detachNewThreadSelector:#selector(Evolve) toTarget:self withObject:nil];
[pool drain];
}
And this is the whole cycle
-(void) Evolve{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
srandom(time(NULL));
//Tag 0: Minimo, Tag 1: Massimo
int tagMinMax = [MinMax selectedTag];
//Tag 0: Rimpiazza sempre, Tag 1: Rimpiazza solo se migliori
int tagRimpiazzo = [[Rimpiazzo selectedItem] tag];
int PopNum = [tf_popNum intValue];
int maxGen = [tf_maxGen intValue];
int target = [tf_targetVal intValue];
int chromosomeLength = [tf_chromosomeLength intValue];
Environment *env = [[Environment alloc] init];
NSMutableArray *pop = [[NSMutableArray alloc] init];
for (int i = 0; i < PopNum; i++) {
[pop addObject:[[Individual alloc] initWithRandomGenesWithChromosomeLength:chromosomeLength]];
}
[env setPopulation:pop];
[pop release];
BOOL earlyBestFound = NO;
Individual *earlyBest = nil;
int i=0;
float best, avg;
while (i<maxGen && !earlyBestFound) {
NSLog(#"while");
NSArray *parents = [env selectParents];
NSLog(#"parents selected");
NSMutableArray *offspring = [[NSMutableArray alloc] init];
for (int i = 0; i < [parents count]; i+=2) {
if (i+1<[parents count]) {
NSLog(#"beginning SEX");
Individual *parent1 = [parents objectAtIndex:i];
Individual *parent2 = [parents objectAtIndex:i+1];
NSArray *children = [parent1 kCrossOverWithOtherIndividual:1 individual:parent2];
Individual *child1 = [children objectAtIndex:0];
Individual *child2 = [children objectAtIndex:1];
NSLog(#"children born");
if (tagRimpiazzo!=0) {
if (([child1 fitness] > [parent1 fitness] && tagMinMax == 0)||([child1 fitness] < [parent1 fitness] && tagMinMax == 1)) {
child1 = parent1;
}
if (([child2 fitness] > [parent2 fitness] && tagMinMax == 0)||([child2 fitness] < [parent2 fitness] && tagMinMax == 1)) {
child2 = parent2;
}
}
NSLog(#"Replacement happened");
[offspring addObject:child1];
[offspring addObject:child2];
}
}
NSLog(#"Calculating statistics");
avg = 0;
for(Individual *X in offspring){
if (([X fitness] > best && tagMinMax == 1)||([X fitness] < best && tagMinMax == 0)) {
best = [X fitness];
}
avg += [X fitness];
if ([X fitness]==target) {
earlyBestFound = YES;
earlyBest = X;
}
}
avg = avg/(float)PopNum;
[env setPopulation:offspring];
NSLog(#"Releasing some memory");
[offspring release];
NSLog(#"Printing statistics");
NSString *toPrint = [NSString stringWithFormat:#"Fine generazione: %d avg: %.2f best: %.2f \r\n", i,avg,best];
[textView insertText:toPrint];
i++;
}
NSLog(#"Fine");
NSString *toPrint = [NSString stringWithFormat:#"Fine! best: %.2f - avg: %.2f \r\n", i,avg,best];
[textView insertText:toPrint];
[env release];
[pool drain];
}
P.S.
Sorry if the english's not perfect, i'm italian :)
Your application is crashing because you are accessing textView from a background thread. UI objects may only be accessed from the main thread.
To solve the problem, you will need to forward you textview updates to the main UI thread. You can do this using the -performSelectorOnMainThread: method. For example:
[textView performSelectorOnMainThread:#selector(insertText:)
withObject:toPrint
waitUntilDone:YES];