MBProgressHUD not save the property variables (NULL) - ios

Im trying to implement loading progress by MBProgressHUD.
Here is my code:
//Previously defined #property(nonatomic) NSString *sec;
-(void) viewDidLoad{
HUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:HUD];
HUD.delegate = self;
[HUD showWhileExecuting:#selector(loadData) onTarget:self withObject:nil animated:YES];
//testing the "return" value
NSLog(#"%#", sec);
}
-(void) loadData{
//get data from file named "results.csv"
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
NSString *saving = [docPath stringByAppendingPathComponent:#"results.csv"];
if([[NSFileManager defaultManager] fileExistsAtPath: saving]){
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:saving];
NSString *dataResults = [[NSString alloc]initWithData:[fileHandle availableData] encoding:NSUTF8StringEncoding];
[fileHandle closeFile];
sec = dataResults;
sec = [sec substringFromIndex: [sec length] - 20];
}
}
As you can see in the "loadData" method I need to set the "sec" NSString as the content that saved in the "results.csv" file.
You can see another thing, that after the HUD code: "showWhileExecuting" I was put NSLog to test if it really gets the content of the file and it returns (NULL)!!
Before I added this HUD thing, It did get the real value from the file, but now its return null.
Off-course when I put the NSLog code line at the end of the "loadData" method, it prints a real value instead of (NULL).
So, the big problem that I cant get the variables from the HUD method.
The only solution that I was thinking of, was to create another file and there store all the new variables, but its not help's me.
Anyone know what Im talking about and can help me?

What you see is normal. Your NULL showing NSLog is executed immediately after the showWhileExecuting call, before the loadData has been scheduled to run. You should implement the delegate protocol MBProgressHUDDelegate,
- (void)hudWasHidden:(MBProgressHUD *)hud{
NSLog(#"%#", sec);
}
When loadData completes, the HUD will hide, and call this method. That is when the result of loadData is available to you.
obcit: not tested, from memory, with an 'antique' MBProgressHUD , but a good chance it should work for you.

Related

Recorded video sometimes displaying, sometimes not

I have a view controller which records a (front-facing) video of the user. The following code is used:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = [paths objectAtIndex:0];
NSString *outputPath = [[NSString alloc] initWithFormat:#"%#", [basePath stringByAppendingPathComponent:#"output.mp4"]];
if ([[NSFileManager defaultManager] isDeletableFileAtPath:outputPath])
[[NSFileManager defaultManager] removeItemAtPath:outputPath error:NULL];
NSURL *outputURL = [[NSURL alloc] initFileURLWithPath:outputPath];
[movieFileOutput startRecordingToOutputFileURL:outputURL recordingDelegate:self];
self.outputURL = outputURL;
Where movieFileOutput is a AVCaptureMovieFileOutput object. I can show you the camera configuration/setup code (this is not an image picker controller or any Apple UI; this films the user in the background while they interact with a completely different screen) but in general, I know it works.
Afterwards, [movieFileOutput stopRecording]; is called and the user is navigated to a new screen where the recording that just occured is played. I pass on the outputURL object to this newly initialized view controller, where the VC plays it using the following code:
self.player = [[MPMoviePlayerController alloc] initWithContentURL:self.outputURL];
self.player.view.frame = CGRectMake(0, 0, self.view.frame.size.width, 320);
self.player.movieSourceType = MPMovieSourceTypeFile;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlaybackComplete:) name:MPMoviePlayerPlaybackDidFinishNotification object:self.player];
self.player.controlStyle = MPMovieControlStyleNone;
self.player.shouldAutoplay = YES;
[self.player setFullscreen:YES animated:NO];
[self.player prepareToPlay];
[self.view addSubview:[self.player view]];
[self.player play];
So, the first time, everything works. The app records the video, then the next screen is displayed, and the video is shown. But then, if you click the "Discard" button, which segues all the way back to the start of the app, and do the entire process again, it does not work and instead the player shows a black screen. With that being said, I print out the data length at the path and it is always a large number (hence something exists at that path).
Oddly enough, I decided to just print the NSData object itself like so:
NSLog(#"%#", [NSData dataWithContentsOfURL:self.outputURL]);
And indeed a very large string of characters (perhaps the bytes? not sure) is printed. Yet, for some reason, now everything works fine... when I add this NSLog(), the bug no longer occurs. When I remove it, it occurs again! I have tested this rigorously.
But still there are some odd times with the inclusion of this NSLog() when after three times the black screen is played. I am very confused as to why this bug may occur and how on Earth the inclusion of an NSLog() could change any behavior.
Any ideas?
My guess is that you need to wait for the file to have been saved.
The documentation of AVCaptureFileOutput says:
When recording is stopped either by calling this method, by changing
files using startRecordingToOutputFileURL:recordingDelegate:, or
because of an error, the remaining data that needs to be included to
the file will be written in the background. Therefore, before using
the file, you must wait until the delegate that was specified in
startRecordingToOutputFileURL:recordingDelegate: is notified when all
data has been written to the file using the
captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error:
method.

Slow default access crash in iOS

I have been programming for 3 years on iOS, heavily using core data. However, I have never come across a crash like this before and have no idea why this is occurring. This current app is only 4 very simple view controllers, saving to nsdefaults only about 5 different times. The error I am confused on is "Slow defaults access for key ClientState took 0.037632 seconds, tolerance is 0.020000". I have noted where in my code it says the problem is in my code. Also, this is long after the view controller has loaded. This process occurs after a button press. Lastly, this crash only happens half the time, meaning there are occasions when the code actually works without a crash.
NSUserDefaults *ab = [NSUserDefaults standardUserDefaults];
NSString *frcrat = [ab objectForKey:#"frcrat"];
NSString *lapper = [alertView textFieldAtIndex:0].text;
spinner.hidden = NO;
[spinner startAnimating];
delem = NULL;
delem = [[NSMutableArray alloc] init]; //Line after this line gives error Thread 1: Exc_bad_access (code = 1, address=0xe0bb2f85)
NSString *urlString = [[NSString stringWithFormat:#"http://www.mywebsite.com/enum.php?fracat=%#&num=%#&sap=%#", frcrat, lapper, _sna]stringByAddingPercentEscapesUsingEncoding : NSUTF8StringEncoding ];
NSXMLParser *Parser = [[[NSXMLParser alloc] initWithContentsOfURL:[NSURL URLWithString:urlString]] autorelease];
[Parser setDelegate:self];
[Parser parse];
I assume this code is placed somewhere in your view controller initialization.
The warning you're getting means that it's taking too long for the view controller to load, and this is clearly due to the initWithContentsOfURL: call in your code.
As you can read here, initWithContentsOfURL: is blocking, meaning that you should never call it on the main thread. You should perform the XML parser initialization asynchronously. Something like:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSString *urlString = [[NSString stringWithFormat:#"http://www.mywebsite.com/enum.php?fracat=%#&num=%#&sap=%#", frcrat, lapper, _sna]stringByAddingPercentEscapesUsingEncoding : NSUTF8StringEncoding ];
NSXMLParser *parser = [[[NSXMLParser alloc] initWithContentsOfURL:[NSURL URLWithString:urlString]] autorelease];
[parser setDelegate:self];
[parser parse];
}
It was not even related to nsuser defaults. It was because of the string _sna. I instead saved that string in nsuserdefaults and reloaded it when I needed it as NSString *snameri. Thanks apple debugger for giving me an inappropriate error.

For-Loop to quick to present View Controller

i want to add multiple passbook passes by running through a array with URLs. The problem is that the loop counts faster than the view controller can present.
Here s my code:
NSArray *passURLArray = [NSArray new];
passURLArray = response;
for (int i = 0; passURLArray.count; i++) {
NSString *passURLString = [NSString stringWithFormat:#"http://test.de%#", [passURLArray objectAtIndex:i]];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:passURLString]];
NSError *error;
PKPass *pass = [[PKPass alloc] initWithData:data error:&error];
[[UIApplication sharedApplication] openURL:[pass passURL]];
PKAddPassesViewController *passVC = [[PKAddPassesViewController alloc] initWithPass:pass];
passVC.delegate = self;
[passVC setDelegate:(id)self];
[self presentViewController:passVC animated:YES completion:nil];
}
I get this error message:
Attempt to present PKAddPassesViewController: 0xca5f7d0 on
PaymentViewController: 0x14882290 which is waiting for a delayed
presention of PKAddPassesViewController: 0xb169470 to complete
Thanks in advance.
Check if you're on the last iteration of the loop. If you are, animate the display, if not, don't animate it.
That said, it's nasty from a user standpoint. You should probably think about a nicer way of presenting, like showing a list or animating between each display when addPassesViewControllerDidFinish: is called.

UiAlertView with UIProgressView for copying files locally

I've been trying to get this working for a day now and I'm still failing. I want to copy a number of files into the Documents folder of my app from the bundle when the app is installed, but this makes the user wait for a long time with the app showing the splash screen.
So I thought I'd make an initial UIAlertView with a UIProgressView as a subview that gets updated every time a file is copied into the documents folder. However the alert shows and the progress bar never gets updated. My logic was:
Set up the UIProgressView and UIAlertView as instance variables of my ViewController.
In ViewDidLoad, present the alert and set the delegate
In - (void)didPresentAlertView:(UIAlertView *)alertView perform a for loop that copies the files and updates the UI. the code was :
- (void)didPresentAlertView:(UIAlertView *)alertView{
NSString *src, *path;
src = // path to the Bundle folder where the docs are stored //
NSArray *docs = [[NSFileManager defaultManager]contentsOfDirectoryAtPath:src error:nil];
float total = (float)[docs count];
float index = 1;
for (NSString *filename in docs){
path = [src stringByAppendingPathComponent:filename];
if ([[NSFileManager defaultManager]fileExistsAtPath:path]) {
... // Copy files into documents folder
[self performSelectorOnMainThread:#selector(changeUI:) withObject:[NSNumber numberWithFloat:index/total] waitUntilDone:YES];
index++;
}
}
[alertView dismissWithClickedButtonIndex:-1 animated:YES];
}
And the code for ChangeUI is
- (void) changeUI: (NSNumber*)value{
NSLog(#"change ui %f", value.floatValue);
[progressBar setProgress:value.floatValue];
}
However this just updates the UI from 0 to 1, although the NSLog prints all the intermediate values. Does anyone here know what I'm doing wrong?
Thanks in advance.
The problem is that your loop is on the main thread, and thus the UI has no chance to update until the very end. Try doing the work on a background thread using GCD:
dispatch_async(DISPATCH_QUEUE_PRIORITY_DEFAULT, ^
{
NSString *src, *path;
src = // path to the Bundle folder where the docs are stored //
NSArray *docs = [[NSFileManager defaultManager]contentsOfDirectoryAtPath:src error:nil];
float total = (float)[docs count];
float index = 1;
for (NSString *filename in docs){
path = [src stringByAppendingPathComponent:filename];
if ([[NSFileManager defaultManager]fileExistsAtPath:path]) {
... // Copy files into documents folder
dispatch_async(dispatch_get_main_queue(), ^{ [self changeUI:[NSNumber numberWithFloat:index/total]]; } );
index++;
}
}
dispatch_async(dispatch_get_main_queue(), ^{ [alertView dismissWithClickedButtonIndex:-1 animated:YES]; } );
} );

ASIHTTPRequest Asynchronous Download not canceling

I am trying to cancel an Asynchronous Download using ASIHTTPRequest with no joy. I am downloading a movie to disk on the appearance of a ViewController. What I want is when the user click close to dismiss the view controller I want to cancel the download. Here is the code I have so far:
Making the request:
-(void)retrieveLatestFile{
NSURL *url = [NSURL URLWithString:[appDelegate.urlToLoad stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
ashiRequest = [[ASIHTTPRequest requestWithURL:url] retain];
[ashiRequest setUsername:#"Appidae"];
[ashiRequest setPassword:#"Dubstance1"];
[ashiRequest setDelegate:self];
[ashiRequest startAsynchronous];
[ashiRequest setDownloadProgressDelegate:progressView];
NSLog(#"Value: %f", [progressView progress]);
if ([progressView progress]==1) {
[self hideInfoPane];
}
//NSLog(#"Max: %f, Value: %f", [myProgressIndicator maxValue],[myProgressIndicator doubleValue]);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *tempPath = [NSString stringWithFormat:#"%#/download/%#/%#", documentsDirectory, appDelegate.languageFolder,appDelegate.filename];
NSLog(#"Path: %#", tempPath);
[ashiRequest setDownloadDestinationPath:tempPath];
}
Cancel the the downloading:
- (IBAction)closeDocDisplay:(id)sender {
// Cancels an asynchronous request
[ashiRequest clearDelegatesAndCancel];
[self dismissModalViewControllerAnimated:YES];
}
Everything is working, the download is fine and the movie plays properly but when I dismiss the View Controller the request is not canceled and my file is still downloading (network activity indicator spins on the status bar. Even the ASIHTTP delegate error doesn't get called
Try using
ashiRequest.delegate = nil;
[ashiRequest cancel];
This should work.
I figured out what was wrong. I was using Reachability to call my retrieveLatestFileMethod. That's fine if Reachability is being used just once in the app, maybe from the delegate. But I had a few instances of it so it keept calling the same functions and downloads.

Resources