play animation regardless of any screen iphone - iphone

i have some animation to be played at some point in time. that time is decided by some thread running in the backgroud. now i want to play the animation regardless of which screen the user is on. here is screen hierarchy.
login-->homescreen(thread starts running from viewdidload).
from home screen the user may navigate to any other screen and i want the animation to be played. right now i have the animationviewcontrller a membervariable in the homescreen and i am calling it by allocing and initing and pushing and popping when animation is done. and it works only 10% of the time. i have tried performselectoronmainthread and its still the same.
How do i redesign my code such that is plays on anyscreen.
here is my code for my thread.
[self startTimerThread]; // in viewdidload
-(void)startTimerThread
{
homescreenthread = [[NSThread alloc] initWithTarget:self selector:#selector(setupTimerThread) object:nil];
[homescreenthread start];
}
-(void)setupTimerThread
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSTimer* timer = [NSTimer timerWithTimeInterval:5
target:self
selector:#selector(findnewmessages)
userInfo:nil
repeats:YES];
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:timer forMode:NSRunLoopCommonModes];
//[runLoop addTimer:timer forModes:NSRunLoopCommonModes];
[runLoop run];
[pool release];
}
-(void)findnewmessages
{//finding message from server here. i am using the following request
NSData *serverReply = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString *replyString = [[NSString alloc] initWithBytes:[serverReply bytes] length:[serverReply length] encoding: NSASCIIStringEncoding];
//i have omitted lot of other code.
}

use the delegate of the app to display the animation view.
id appDelegate = [UIApplication sharedApplication].delegate;
[appDelegate.m_window addSubview:viewController.view];
Also if you are tying to draw anything on the screen it should be done on main thread.
Please let me know if it helps.

Related

Updating Interface from Result of NSURL Request

I have an app that updates the interface depending on the result of a NSURL request. I have set it up so that the request is fired when my app comes into the foreground, and only if the current view controller is called "ProfileViewController".
My problem is that the interface locks up for a few seconds every time I bring the app back from the background. I am trying to fully understand main/background threads, but am not sure what I can do to make the app remain responsive while the NSURL check is being performed. Any assistance would be great! Thanks!
In my View Did Load Method:
-(void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(appReturnsActive) name:UIApplicationDidBecomeActiveNotification
object:nil];
//additional code
}
Then in my App Returns Active Method:
- (void)appReturnsActive {
[myTimer invalidate];
myTimer = nil;
//ONLY WANT TO PERFORM THE UPDATE IF VIEWING THE PROFILE VIEW CONTROLLER
UIViewController *currentVC = self.navigationController.visibleViewController;
NSString * name = NSStringFromClass([currentVC class]);
if ([name isEqualToString:#"ProfileViewController"]) {
[activityIndicator startAnimating];
[activityIndicatorTwo startAnimating];
locationManagerProfile.delegate = self;
locationManagerProfile.desiredAccuracy = kCLLocationAccuracyBest;
[locationManagerProfile startUpdatingLocation];
}
}
Finally, in my Did Update Location Method, I get the distance between the user and the location. If the result is equal to 1, then I update the Interface to show different buttons. This is where the interface freezes up:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation
*)newLocation fromLocation:(CLLocation *)oldLocation {
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
[self performSelectorOnMainThread:#selector(buttonUpdate:)
withObject:NULL waitUntilDone:NO];
}
}
New Method:
-(void)buttonUpdate {
NSString *userLongitude =[NSString stringWithFormat:#"%.8f",
currentLocation.coordinate.longitude];
NSString *userLatitude = [NSString stringWithFormat:#"%.8f",
currentLocation.coordinate.latitude];
[locationManagerProfile stopUpdatingLocation];
NSString *placeLatitude = [[NSUserDefaults standardUserDefaults]
stringForKey:#"savedLatitude"];
NSString *placeLongitude = [[NSUserDefaults standardUserDefaults]
stringForKey:#"savedLongitude"];
NSString *distanceURL = [NSString
stringWithFormat:#"http://www.website.com/page.php?
lat1=%#&lon1=%#&lat2=%#&lon2=%#",userLatitude, userLongitude, placeLatitude,
placeLongitude];
NSData *distanceURLResult = [NSData dataWithContentsOfURL:[NSURL
URLWithString:distanceURL]];
NSString *distanceInFeet = [[NSString alloc] initWithData:distanceURLResult
encoding:NSUTF8StringEncoding];
if ([distanceInFeet isEqualToString:#"1"])
{
UIBarButtonItem *btnGo = [[UIBarButtonItem alloc] initWithTitle:#"Button 1"
style:UIBarButtonItemStyleBordered target:self
action:#selector(actionTwo)];
self.navigationItem.rightBarButtonItem = btnGo;
UIBarButtonItem *btnGoTwo = [[UIBarButtonItem alloc] initWithTitle:#"Button
Two" style:UIBarButtonItemStyleBordered target:self
action:#selector(actionOne)];
self.navigationItem.rightBarButtonItem = btnGoTwo;
self.navigationItem.rightBarButtonItems = [NSArray arrayWithObjects:btnGo,
btnGoTwo, nil];
}
}
Your CoreLocation delegate methods (e.g. "didUpdateToLocation", etc.) are all happening in the background, on secondary threads, while everything UI-related needs to happen on the main thread.
To fix your problem, you should modify your UI on the main thread. One of the handy foundation API's you can use is:
performSelectorOnMainThread:withObject:waitUntilDone:
To fix your problem, move your button-creating code into a separate method and call that new method via "performSelectorOnMainThread" from the old (being called on a separate thread via the CoreLocation delegate protocol) and you should be good to go.
NSData *distanceURLResult = [NSData dataWithContentsOfURL:[NSURL
URLWithString:distanceURL]];
is a synchronous call. It means your code will wait for the result of the network call to continue. You should make an Asynchronous request, with NSURLConnection (http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/Reference/Reference.html) or AFNetworking.

How to get local notification once folder is determined to be not empty?

I would like to know how to get local notifications while my application's NSTimer is firing in the background. My NSTimer checks a particular folder for files every second for 10 minutes in the background. How would I go about receiving a local notification if a file is found?
EDIT : Code :
- (void) createTimeThread: (float) pIntervalTime
{
[NSThread detachNewThreadSelector:#selector(startTimerThread)
toTarget:self withObject:nil];
}
- (void) startTimerThread
{
UIBackgroundTaskIdentifier bgTask = [[UIApplication sharedApplication]
beginBackgroundTaskWithExpirationHandler:^{}];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
myTimer = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(conditionChecking:)
userInfo:nil
repeats:YES];
[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
[pool release];
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
}
- (void)conditionChecking:(NSIndexPath *)indexPath
{
NSString *pathForFile = #"/User/Library/Logs/CrashReporter";
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:pathForFile]) { // Directory exists
NSArray *listOfFiles = [fileManager contentsOfDirectoryAtPath:pathForFile error:nil];
if (!listOfFiles || !listOfFiles.count)
{
NSLog(#"No Core Dumps found.....");
}
else
{
NSLog(#"Core Dump(s) found! :%#", listOfFiles);
}
}
}
I believe that you want to notify all other classes that folder is filled with files.
Following steps can do that for you.
write following line in initialization of class where you want to receive notification.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(checkFiles:) name:#"FILES_AVAILABLE" object:nil];
Write methods checkFiles with following signature in same class.
-(void)checkFiles:(id)sender
Add following line in timer class when files are available.
[[NSNotificationCenter defaultCenter] postNotificationName:#"FILES_AVAILABLE" object:self];
If this is not helpful then you can use NSUserDefault to store status of application(Files are available or not in you case). OR With if you are interested in design patterns read about Observer Pattern.
In case you want to post notification when your application is in background mode and some process that is still running gets some update then that can be achieved using notification queue. read following link. I am not writing code because code is given in link itself.
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Notifications/Articles/NotificationQueues.html#//apple_ref/doc/uid/20000217-CJBCECJC
Post here if you need more help.

How to call a method on background thread

in my app i am unzipping a zip file(in splash view controller) later i am displaying an image and firing a timer with 4 secs to change image of the previous image view. and later in view did appear i am firing another timer with 10 secs to call next view controller(home view controller).. and there i have a button to go Story view controller...in this i am using the unzipped data...its taking some time to unzip in this case. so the images r displaying later a few seconds...it fine here
the problem is... i called the unzipping on background thread so its displaying the images quickly and its moving to home view controller..while going to next view controller by clicking a button its crashing on device but its working fine in simulator..
can any body help me out please
Thanks.
code...
-(void)viewWillAppear:(BOOL)animated{
[self performSelectorInBackground:#selector(unXip) withObject:nil];
CGRect imageFrame = CGRectMake(0,20,320,460);
splashView.frame = imageFrame;
splashView.image = [UIImage imageNamed:#"Default.png"];
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(changeImg) userInfo:nil repeats:NO];
[NSTimer scheduledTimerWithTimeInterval:3 target:self selector:#selector(changeImg2) userInfo:nil repeats:NO];
}
-(void)unXip{
self.fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
self.documentsDir = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/temp", self.documentsDir];
NSString *filePathbmlg = [NSString stringWithFormat:#"%#/temp/bmlg", self.documentsDir];
NSString *updateURL = [[NSBundle mainBundle] pathForResource:#"bmlg" ofType:#"zip" inDirectory:#"res"];
[fileManager createDirectoryAtPath:filePath
withIntermediateDirectories:NO
attributes:nil
error:nil];
if([fileManager fileExistsAtPath:filePath]) {
NSLog(#"File exists at path: %#", updateURL);
} else {
NSLog(#"File does not exists at path: %#", updateURL);
}
NSLog(#"Checking update at : %#", updateURL);
NSLog(#"Checking filepath at : %#", filePath);
if(![fileManager fileExistsAtPath:filePathbmlg]) {
ZipArchive *zipArchive = [[ZipArchive alloc] init];
if([zipArchive UnzipOpenFile:updateURL]) {
if ([zipArchive UnzipFileTo:filePath overWrite:YES]) {
//unzipped successfully
NSLog(#"Archive unzip Success");
//[self.fileManager removeItemAtPath:filePath error:NULL];
} else {
NSLog(#"Failure To Unzip Archive");
}
} else {
NSLog(#"Failure To Open Archive");
}
[zipArchive release];
}
}
- (void)changeImg{
splashView.image = [UIImage imageNamed:#"screen2.png"];
}
- (void)changeImg2{
splashView.image = [UIImage imageNamed:#"screen3.png"];
}
- (void)viewDidAppear:(BOOL)animated{
[NSTimer scheduledTimerWithTimeInterval:15 target:self selector:#selector(pushCVC) userInfo:nil repeats:NO];
}
- (void)pushCVC{
homeViewController = [[HomeViewController alloc] initWithNibName:#"HomeView" bundle:nil];
[self presentModalViewController:homeViewController animated:YES];
}
It's kind of hard to answer this witout any sample code. One thing to be aware of when using background threads is to make sure that all code that updates the UI runs on the main thread.
Ok, I think this is probably a threading issue. Your unXip method is modifying something on a background thread and then you try to access that "something" from another thread (main thread if you access it from UI code). You need to implement some kind of locking/synchronization mechanism (e.g. NSLock or NSConditionLock).
It looks a bit strange that you are using a timer to call pushCVC. Now, I don't know exactly what your app does but wouldn't it be better to call pushCVC when the unzip has finished by adding this to the end of your unXip method:
[self performSelectorOnMainThread:#selector(pushCVC) withObject:nil waitUntilDone:NO];
and removing the timer.
thanks for your comments and answers....
The problem is the unzipping process is taking a long time...so if i click start button on the home screen before the completion of the unzipping the file, its crashing...because i have to use the data from unzipped file...
Thanks again..

NSOperationQueue returning __getNextReady bad access on resuming

Here's how I start the code:
m_searchTimer = [[NSTimer timerWithTimeInterval:0.5 target:self selector:#selector(launchRequest:) userInfo:nil repeats:FALSE] retain];
[[NSRunLoop mainRunLoop] addTimer:m_searchTimer forMode:NSDefaultRunLoopMode];
then in my -(void)launchRequest method:
- (void)launchRequest:(NSTimer *)timer
{
ASIHTTPRequest *req = [[[m_twitterQueue operations] lastObject] copy];
[m_twitterQueue cancelAllOperations];
[m_twitterQueue addOperation:req];
[m_twitterQueue go];
}
once I reach the - (void)go; method, I get the bad access.
Any idea is welcomed
I have found the issue.
Using ASIHTTPRequest, there is a #property named
shouldCancelAllRequestsOnFailure //Default is YES
By leaving it on, you add a request while cancelling it which makes the queue crash.
Turning it False solved the issue.

Iphone NSTimer Issue

Hi I am new to objective c. I am trying to make an app for iphone. I have a button on my view, and the click on which the function playSound is called. This is working properly. It does plays the sound that i want it to.
Now the problem is with the timer. I want the timer to start on the click on the same button, and the timer value will be displayed in a label. I am not very clear with the NSTimer itself either yet. I guess i am doing something wrong here. Can anyone help me with this.
-(IBAction)playSound { //:(int)reps
NSString *path = [[NSBundle mainBundle] pathForResource:#"chicken" ofType:#"wav"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: path];
AVAudioPlayer* theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
theAudio.delegate = self;
[theAudio play];
[self startTimer];
}
- (void)startTimer {
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(targetMethod) userInfo:nil repeats:YES];
labelA.text = [NSString stringWithFormat:#"%d", timer];
}
Using the code above, when i click on the button, it plays the sound, and then my app closes.
Thanks
Zeeshan
This line:
labelA.text = [NSString stringWithFormat:#"%d", timer];
makes absolutely no sense. The timer will call the method you specify as the selector in scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: when it fires so you have to implement that method and update your label there. The first line of startTimer is almost correct, but the selector must include a colon (because it denotes a method that takes one parameter):
- (void)startTimer {
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timerFired:) userInfo:nil repeats:YES];
}
Note that I named the selector timerFired: so we have to implement that method. If you want the timer to increment a counter, you will have to do that in this method, too:
- (void)timerFired:(NSTimer *)timer {
static int timerCounter = 0;
timerCounter++;
labelA.text = [NSString stringWithFormat:#"%d", timerCounter];
}
Don't forget to invalidate the timer later when you no longer need it.