I've to play A video from server and it takes some time. So I've Written an activityIndicator and started animating it. but the activity indicator is not showing up until the video is playing. Firs I've hidden activity indicator later unhidden it and started animating but its shown when the video is started playing.
Here is my code:
for info indicatorView is a UIView and I've indView is an UIIndicatorView inside of UIView; And I'm using AV Player for playing;
Please Read Clearly that indicator view is showing up in the view, but the problem is not showing up when i Said start animating but after some time when video is started.
indicatorView.hidden = NO;
[indView startAnimating];
//Here Indicator view must shown in VIEW but it's not showing up;
MediaItem *item = [allVideos objectAtIndex:indexPath.row];
[playerModel playMyVideo:item];
// now here after 5 sec when video is ready to play it's showing up
What is the problem.
I've used dispach asynch in both the places but no use
Just add one method like,
-(void) videoPrepareToPlay {
MediaItem *item = [allVideos objectAtIndex:indexPath.row];
[playerModel playMyVideo:item];
}
and call that method like,
indicatorView.hidden = NO;
[indView startAnimating];
[self performSelector:#selector(videoPrepareToPlay) withObject:nil afterDelay:0.2];
It may be work for you..
I've used dispach asynch in both the places but no use
But is this code being run on the main thread? UI updates should be executed on the main thread.
dispatch_async(dispatch_get_main_queue(), ^{
//UI code
});
Change [playerModel playMyVideo:item]; to
[playerModel performSelector:#selector(playMyVideo:) withObject:item afterDelay:0.0001f inModes:#[NSRunLoopCommonModes]];
Execute the ActivityIndicator code using performSelectorOnMainThread and retrieve the video using background thread.
ELSE
Easy Fix:
Use this https://github.com/jdg/MBProgressHUD
Related
I have an UITableView with some UITableViewCells and when I click on a specific cell the application will download some information from my server. The question is: "How can I show IMMEDIATELY* a view with only an UIActivityIndicator which is animated during all the time of the download and stops its animation when the download is complete?"
*Note: It should not be after other strange operations from the app, it must be the first thing after the click on the cell.
You can use the below method which starts and stops the activity indicator on main thread in a single method
- (void)showIndicatorAndStartWork
{
// start the activity indicator (you are now on the main queue)
[activityIndicator startAnimating];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// do your background code here
dispatch_sync(dispatch_get_main_queue(), ^{
// stop the activity indicator (you are now on the main queue again)
[activityIndicator stopAnimating];
});
});
}
Note:
I am doing some background stuff so I have used dispatch_async, if you also want to download something in background you can also use dispatch_async else you can also download the stuff on main thread.
I have a method in my main viewcontroller:
- (void)playMusic:(NSString*)songTitle :(NSString*)songArtist :(NSString*)songDuration :(NSString*)songUrl{
[songPlayer pause];
songPlayer = [[AVPlayer alloc]initWithURL:[NSURL URLWithString:songUrl]];
[songPlayer play];
self.songSlider.maximumValue = 100;
self.songSlider.value = 0;
}
I call it from a view inside a containerview like this (from a button click)
[mainController playMusic:songTitle:songArtist :songDuration :songUrl];
songPlayer (it s an AVPlayer) is doing his job well, the song start without problem.
But the songSlider (it s an UISlider) is not updated.
If I call the exam same instructions:
self.songSlider.maximumValue = 100;
self.songSlider.value = 0;
inside viewDidLoad method of my main cotroller, songSlider is updated without problem.
That makes me think the problem is that I call the function from the containerview? in this case how can I fix this? Thank you
I answered a similar question about an hour ago.
I suspect the problem to be that your button click action is not being called on the main thread. I didn't find any resources to indicate if UIControl always fires events on the main thread and thus there is a possibility that your code is running on a background thread. This is important because you cannot make UI modifications on any other thread than the main thread.
Try the following in your button callback
dispatch_sync(dispatch_get_main_queue(), ^{
[mainController playMusic:songTitle:songArtist :songDuration :songUrl];
});
I'm using the MBProgressHUD library in my app, but there are times that the progress hud doesn't even show when i query extensive amount of data, or show right after the processing of data is finished (by that time i don't need the hud to be displayed anymore).
In another post i found out that sometimes UI run cycles are so busy that they don't get to refresh completely, so i used a solution that partially solved my problem: Now every request rises the HUD but pretty much half the times the app crashes. Why? That's where I need some help.
I have a table view, in the delegate method didSelectRowAtIndexPath i have this code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[NSThread detachNewThreadSelector:#selector(showHUD) toTarget:self withObject:nil];
...
}
Then, I have this method:
- (void)showHUD {
#autoreleasepool {
[HUD show:YES];
}
}
At some other point I just call:
[HUD hide:YES];
And well, when it works it works, hud shows, stays and then disappear as expected, and sometimes it just crashes the application. The error: EXC_BAD_ACCESS . Why?
By the way, the HUD object is already allocated in the viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
...
// Allocating HUD
HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.labelText = #"Checking";
HUD.detailsLabelText = #"Products";
HUD.dimBackground = YES;
}
You need to perform your processing on another thread, otherwise the processing is blocking MBProgressHud drawing until it completes, at which point MBProgressHud is hidden again.
NSThread is a bit too low-level for just offloading processing. I'd suggest either Grand Central Dispatch or NSOperationQueue.
http://jeffreysambells.com/2013/03/01/asynchronous-operations-in-ios-with-grand-central-dispatch
http://www.raywenderlich.com/19788/how-to-use-nsoperations-and-nsoperationqueues
/* Prepare the UI before the processing starts (i.e. show MBProgressHud) */
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
/* Processing here */
dispatch_async(dispatch_get_main_queue(), ^{
/* Update the UI here (i.e. hide MBProgressHud, etc..) */
});
});
This snippet will let you do any UI work on the main thread, before dispatching the processing to another thread. It then returns to the main thread once the processing is done, to allow you to update the UI.
Currently, I'm downloading data from a web server by calling a method fetchProducts. This is done in another separate thread. As I successfully download fifty items inside the method stated above, I post a notification to the [NSNotification defaultCenter] through the method call postNotificationName: object: which is being listened to by the Observer. Take note that this Observer is another ViewController with the selector updateProductsBeingDownloadedCount:. Now as the Observer gets the notification, I set the property of my progressView and a label that tells the progress. Below is the code I do this change in UI.
dispatch_async(dispatch_get_main_queue(), ^{
if ([notif.name isEqualToString:#"DownloadingProducts"]) {
[self.progressBar setProgress:self.progress animated:YES];
NSLog(#"SetupStore: progress bar value is %.0f", self.progressBar.progress);
self.progressLabel.text = [NSString stringWithFormat:#"Downloading %.0f%% done...", self.progress * 100];
NSLog(#"SetupStore: progress label value is %#", self.progressLabel.text);
[self.view reloadInputViews];
}
});
The idea is to move the progressView simultaneously as more items were being downloaded until it is finished. In my case, the progressView's animation will just start right after the items were already downloaded, hence a delay. Kindly enlighten me on this.
I have a button on the currently navigated to viewcontroller, connected to an IBAction.
In the IBAction I create a UIActivityIndicatorView as usual, with [self.view addSubView], then load some pictures.
I've tried setNeedsDisplay on the indicator view, the view controller, and the window, but it still loads the pictures before showing the indicator, which of course is quite useless to me.
So I'm looking for a way to either force an instant redraw (which when I think a little more about it is unlikely to make work), or a way to load the pictures after the indicator has appeared, or a way to launch a separate thread or similar to start animating / show the indicator, or put the indicator in a separate viewcontroller and somehow force it to add/show itself before going on to the picture-loading.
Recommendations?
What I do in this situation is spawn a new thread, which frees up the main thread to handle UI interaction while stuff is loading in the background.
First show the UIActivityIndicatorView, then spawn a new thread that loads the images, then on the last line of the method that is executed in the new thread, hide the UIActivityIndicatorView.
Here's an example:
//do stuff...
[activityIndicatorView startAnimating];
[NSThread detachNewThreadSelector:#selector(loadImages) toTarget:self withObject:nil];
In your loadImages method:
- (void) loadImages {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//load images...
[activityIndicatorView performSelectorOnMainThread:#selector(stopAnimating)];
[pool drain];
}