How to set activity indicator view in iOS - iphone

In .h file:
UIActivityIndicatorView *mySpinner;
In viewDidLoad:
mySpinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
mySpinner.center = CGPointMake(160, 240);
mySpinner.hidesWhenStopped = YES;
[self.view addSubview:mySpinner];
and finally I am calling it on button click as:
[mySpinner startAnimating];
The problem is that when I called it in viewDidLoad it showed and start animating but didn't animate on button click not even show. Help me on this issue.
Thanks in advance

I'm guessing your 'mySpinner" ivar isn't being properly retained or declared.
In your .h file, declare it as a property. That is:
#property (strong) UIActivityIndicatorView *mySpinner;
then, when you create it:
self.mySpinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
and when you reference it in your button click method:
[self.mySpinner startAnimating];

Thanks to everyOne who helped me ….
I have resolved the issue and here i am posting the answer for some one who is in search of this… actually the issue is "i am Downloading some records on synchronous request. So thats why UI Updation is blocked for a while.
so this is creating problem here….
On Button click i just make a new thread that call a method 'start'
[NSThread detachNewThreadSelector: #selector(Start) toTarget:self withObject:nil];
and the 'start' method is
- (void) Start
{
Spinner.hidden = NO;
[mySpinner startAnimating];
}

Related

UIActivityIndicatorView not spinning

I have this problem where I am adding an UIActivityIndicatorView to a UIScrollView; Everything is working fine, except it does not start spinning unless the UIScrollView is scrolled.
Can anyone help me with this issue?
Thank you.
here is some code:
UIActivityIndicatorView *loaderActivity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
loaderActivity.center = CGPointMake(87/2,y+56/2);
loaderActivity.tag=tag;
[mainScrollView addSubview:loaderActivity];
[loaderActivity startAnimating];
[loaderActivity release];
You need to call startAnimating on the activity indicator to have it animate. Alternatively in interface builder you can tick the "animating" tickbox.
The fact that it's not animating until you scroll in the scroll view is a symptom that your call to startAnimating is happening in a background thread. UIKit calls should be made in the main thread.
You can verify that it's happening in a background thread by adding code like this:
if ([NSThread isMainThread]) {
NSLog(#"Running on main thread.");
} else {
NSLog(#"Running on background thread.");
}
You'll want to make sure all of the code you showed in your question is running on the main thread. To do this, you can change your code to look something like this:
// this code would be wherever your existing code was
[self performSelectorOnMainThread:#selector(addActivityIndicatorToView:) withObject:mainScrollView waitUntilDone:YES];
// this would be a new method in the same class that your existing code is in
- (void) addActivityIndicatorToView:(UIView*) view {
UIActivityIndicatorView *loaderActivity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
loaderActivity.center = CGPointMake(87/2,y+56/2);
loaderActivity.tag=tag;
[view addSubview:loaderActivity];
[loaderActivity startAnimating];
[loaderActivity release];
}
activityIndicator = [[UIActivityIndicatorView alloc]
initWithFrame:CGRectMake(87/2,y+56/2);
[activityIndicator setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhite];
activityIndicator.tag=tag;
[mainScrollView addSubview:loaderActivity];
[activityIndicator startAnimating];
[activityIndicator release];
Had an issue where I made the startAnimating call in the viewDidLoad and didn't work. I moved the call in the viewWillAppear and it worked!
Try running the animator in a different thread.
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:#selector(showProgress) object:nil];
[thread start];
//do whatever your want here
//call this when you want it stop animating
[activityIndicator stopAnimating];
[thread release];
- (void)showProgress{
[activityIndicator startAnimating];
}

Adding a UIActivityIndicator to a modal view (ELCimagepicker)

I've added the ELCimagepicker (https://github.com/Fingertips/ELCImagePickerController) to my project and it works perfectly, allowing the user to select multiple images for a slideshow. But when you click 'Save', there can be a lengthy delay depending on how many photos were added.
I've been trying to add a UIActivityIndicator when the user clicks 'Save', but having trouble due to the modal view that is presented. I can call a method from the activity that ELCimagepicker presents (ELCImagePickerController) and this gets actioned by the activity handling the presenting of the image picker. But whenever I try to add to the view, it isn't shown as the modal is on top of the activity indicator.
I've tried using bringSubviewToFront, I've tried adding the code directly to the imagepicker method file with [[self parentViewController] addSubView], but no luck.
Here's the latest code I tried: (indicator is declared in the .h file as UIActivityIndicator *indicator)
indicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
indicator.hidden=false;
[self.navigationController.view addSubview:self.indicator];
[self.navigationController.view bringSubviewToFront:self.indicator];
[indicator startAnimating];
if([delegate respondsToSelector:#selector(elcImagePickerController:showIndicator:)]) {
[delegate performSelector:#selector(elcImagePickerController:showIndicator:) withObject:self withObject:#"test"];
}
Has anyone had any success with adding a UIActivityIndicator on top of the ELCimagepicker, or another modal view handled by another class?
I've tried MBProgressHUD but couldn't get that working quite right either - it would show up when I used it in the ELCimagepicker class, but crashed on removal with:
bool _WebTryThreadLock(bool), 0x42368e0: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
Any help would be fantastic.
Thanks.
I have figure out your problem. You can do this as below..
-(void)selectedAssets:(NSArray*)_assets {
UIActivityIndicatorView * activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
UIViewController * topView = [self.viewControllers objectAtIndex:[self.viewControllers count]-1];
activityIndicator.center = CGPointMake(topView.view.frame.size.width/2, topView.view.frame.size.height/2);
[activityIndicator setHidden:NO];
[topView.view addSubview:activityIndicator];
[topView.view bringSubviewToFront:activityIndicator];
[activityIndicator startAnimating];
[self performSelector:#selector(doProcess:) withObject:_assets afterDelay:2.1];
}
- (void) doProcess:(NSArray *)_assets {
NSMutableArray *returnArray = [[[NSMutableArray alloc] init] autorelease];
for(ALAsset *asset in _assets) {
NSMutableDictionary *workingDictionary = [[NSMutableDictionary alloc] init];
[workingDictionary setObject:[asset valueForProperty:ALAssetPropertyType] forKey:#"UIImagePickerControllerMediaType"];
[workingDictionary setObject:[UIImage imageWithCGImage:[[asset defaultRepresentation] fullScreenImage]] forKey:#"UIImagePickerControllerOriginalImage"];
[workingDictionary setObject:[[asset valueForProperty:ALAssetPropertyURLs] valueForKey:[[[asset valueForProperty:ALAssetPropertyURLs] allKeys] objectAtIndex:0]] forKey:#"UIImagePickerControllerReferenceURL"];
[returnArray addObject:workingDictionary];
[workingDictionary release];
}
[self popToRootViewControllerAnimated:NO];
[[self parentViewController] dismissModalViewControllerAnimated:YES];
if([delegate respondsToSelector:#selector(elcImagePickerController:didFinishPickingMediaWithInfo:)]) {
[delegate performSelector:#selector(elcImagePickerController:didFinishPickingMediaWithInfo:) withObject:self withObject:[NSArray arrayWithArray:returnArray]];
}
}
Let me know if this answer help you ...
Thanks,
MinuMaster
It looks like you are updating UI on a background thread. All UIKit updates are to be done in the main thread. So I recommend you execute methods doing UI updates using performSelectorOnMainThread:withObject:.
I solved the issue like this
activityIndicatorObject = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
// Set Center Position for ActivityIndicator
activityIndicatorObject.center = CGPointMake(150, 250);
activityIndicatorObject.backgroundColor=[UIColor grayColor];
// Add ActivityIndicator to your view
[self.view addSubview:activityIndicatorObject];
activityIndicatorObject.hidesWhenStopped=NO;
[activityIndicatorObject startAnimating];

Update UILabel from applicationDidBecomeActive?

I want to update UILabel by clicking a reload button. Additionally, I want to update the label in background, because it is fetching the new data via XML from my website. Of course it would be nice to auto-update the label when the application is opened. And there is my problem:
I was able to make it work well when user were clicking the button manually. But I don't understand how to do the same by calling my method via "applicationDidBecomeActive". I tried to do it the same way, but it obviously doesn't work because my label is returned nil.
I suppose there is a problem of my understanding and the solution should be quite easy. Thanks for your input! Note: I am a beginner with Objective-C and have sometimes problems with "easy" things. ;-)
Below is a summary of the important code parts:
AppDelegate
- (void)applicationDidBecomeActive:(UIApplication *)application {
[[MyViewController alloc] reloadButtonAction];
}
MyViewController
#synthesize label
- (void)reloadButtonAction {
[self performSelectorInBackground:#selector(updateData) withObject:nil];
}
- (void)updateData {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Parse the XML File and save the data via NSUserDefaults
[[XMLParser alloc] parseXMLFileAtURL];
// Update the labels
[self performSelectorOnMainThread:#selector(updateLabels) withObject:nil waitUntilDone:NO];
[pool release];
}
- (void)updateLabels {
NSUserDefaults *variable = [NSUserDefaults standardUserDefaults];
myLabel.text = [variable stringForKey:#"myLabelText"];
// myLabel is nil when calling all of this via AppDelegate
// so no changes to the myLabel are done in that case
// but: it works perfectly when called via button selector (see below)
NSLog(#"%#",myLabel.text);
}
-(void)viewDidLoad {
// Reload button in the center
UIButton *reloadButton = [UIButton buttonWithType:UIBarButtonSystemItemRefresh];
reloadButton.frame = CGRectMake(145,75,30,30);
[reloadButton setTitle:#"" forState:UIControlStateNormal];
[reloadButton addTarget:self action:#selector(reloadButtonAction) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:reloadButton];
}
First:
[[MyViewController alloc] reloadButtonAction];
Doesn't make sense. You allocate memory, without initializing an object. And then you want to call a method on it. Doesn't work
Use an instance for it:
[myViewControllerInstance reloadButtonAction];
In your app delegate you should have an reference to your rootcontroller instance if that is the object contains the reload method, use that instance.
Note:
Alloc only reserves space in the memory for an object which size the size of MyViewController instance. An init method will fill it.

Can't programmatically hide UIButton created with IB

My iOS UIButton is correctly linked from IB to an IBOutlet in my view controller, as I can change its title from my code. Ie:
[self.myButton setTitle:#"new title" forState:UIControlStateNormal]; //works
However,
[self.myButton setHidden:YES]; //doesn't work
//or
self.myButton.hidden = YES; //doesn't work
What's going on? How can I make myButton disappear?
Update: some additional info
Here's the code related in to my UIButton:
in my .h file
IBOutlet UIButton *myButton;
-(IBAction)pushedMyButton:(id)sender;
#property (nonatomic,retain) UIButton *myButton;
in my .m file
#synthesize myButton;
- (void)pushedMyButton:(id)sender{
self.myButton.hidden = YES;
}
- (void)dealloc{
[self.myButton release];
}
Ok I found a workaround that works but I still don't know why my original code wasn't working in the first place. I used Grand Central Dispatch to dispatch a block containing the hide call on the main queue, like this:
dispatch_async(dispatch_get_main_queue(), ^{
self.myButton.hidden = YES; //works
});
Interesting. None of the initial code in my IBOutlet was wrapped in GCD blocks though. Any ideas?
That should work, try rename it and hide it just to check that there aren't two buttons on top of each other.
I had this same problem and found the solution was to put the hidden in the right place, in my case in the viewDidLoad function.
User Interface (UI) API (UIKit ...) methods have to be run on Main Thread!
So this will run on Main thread (as *dispatch_get_main_queue*):
dispatch_async(dispatch_get_main_queue(), ^{
self.myButton.hidden = YES; //works
});
BUT usually we do something like this:
[self performSelectorOnMainThread:#selector(showButton) withObject:nil waitUntilDone:NO];
[self performSelectorOnMainThread:#selector(hideButton) withObject:nil waitUntilDone:NO];
-(void)showButton
{
myButton.hidden = NO;
}
-(void)hideButton
{
myButton.hidden = YES;
}
As per Apple's documentation: http://developer.apple.com/library/ios/#documentation/uikit/reference/uiview_class/uiview/uiview.html
"
Threading Considerations
Manipulations to your application’s user interface must occur on the main thread. Thus, you should always call the methods of the UIView class from code running in the main thread of your application. The only time this may not be strictly necessary is when creating the view object itself but all other manipulations should occur on the main thread.
"
What worked for me is putting the manipulating code in viewDidLoad instead of initWithNibName, like this:
- (void)viewDidLoad
{
btnRestart.enabled = false;
}
Had the same problem: button.hidden = YES didn't hide.
Solved it when I defined it in the .h file using #property and #synthesize in the .m file thus making it self.button.
Now self.button.hidden = YES works

Proper use of UIImagePickerController for both taking pictures with camera or selecting them from the iphone library

What I want to do is to always use the same instance of UIImagePickerController in my whole app, since i don't want to alloc and destroy my picker every time the user takes a picture. The app uses a picker and an UIImageView named pictureA to show the picture choossen from the iPhone album or taken with the camera.
At start I allock my picker view controller like this:
imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.delegate = self;
[self addSubview:imagePickerController.view];
When I take picture from the picker and place it in my UIImageView:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
// newImage is a UIImage do not try to use a UIImageView
UIImage *newImage = [info objectForKey:#"UIImagePickerControllerEditedImage"];
[pictureA removeFromSuperview];
CGRect myImageRect = CGRectMake(30.0f, 38.0f, 125.0f, 125.0f);
pictureA = [[UIImageView alloc] initWithFrame:myImageRect];
pictureA.contentMode= UIViewContentModeScaleAspectFit;
[pictureA setImage:newImage];
pictureA.opaque = YES;
[self addSubview:pictureA];
[newImage release];
[picker dismissModalViewControllerAnimated:YES];
[picker.view setHidden:YES];
}
When chooses a picture from the iphone's library:
- (void) chooseImageFromLibrary {
[imagePickerController.view setHidden:NO];
imagePickerController.allowsEditing = YES;
[imagePickerController viewWillAppear:YES];
[imagePickerController viewDidAppear:YES];
}
Cancel:
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
[picker.view setHidden:YES];
}
- (void) takePicture {
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
[(MainScene*)[melonGame actualScene] setCameraDissabled:YES];
return;
}
[imagePickerController.view setHidden:NO];
imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePickerController.allowsEditing = YES;
[imagePickerController takePicture];
[imagePickerController viewWillAppear:YES];
[imagePickerController viewDidAppear:YES];
}
The app will work properly when i take the first picture, but when i try to take another picture or choose another picture from my library it looks exactly as the last time i selected a picture ( with the picture in all the screen and an inactive menu to choose and cancel at the bottom). My app only works correctly if i remove the controller from my view and alloc it every time the user takes a picture. Is there any way to "clean" or "restart" the picker without releasing it and removing it from my view ?
I'm also not sure if i can instance once the UIImageView ( pictureA) where I store the image taken by the imagePickerController and modify it every time the user takes a picture or chooses one from the album, i suspect that it's incorrect to destroy it and realloc it every time the user takes a picture. Any suggestions ?, any thing i'm doing wrong regarding memory management or the use of the UIImagePickerController and the UIImageView ?
thanks !
I don't think UIImagePickerControllers are meant to be re-used. Either way, they use a TON of memory (especially the camera), so you don't want to keep them around any longer than you have to. So yes, you should release the image picker when you're done with it, and create a new one when you want to add another image.
You should probably be presenting your imagepicker modally:
[self presentModalViewController:imagePickerController animated:YES];
You don't need to release your pictureA image view every time you want to change the image. Just change the image property.
pictureA.image = newImage;
If you want to instantiate the image view the first time you use it, do something like
if (!pictureA) {
pictureA = [[UIImageView alloc] initWithFrame:aFrame];
}
pictureA.image = ...
Keep in mind that a call to alloc needs a matching call to either release or autorelease. When you allocated "pictureA" above, its retain count became 1. calling "[self addSubview:pictureA];" increased its retain count to 2. When you called "[pictureA removeFromSuperview];" next time around, the retain count was decreased to 1, and you created a new imageview. So every time imagePickerController:didFinishPickingMediaWithInfo: is called, you will leak memory. Instead, do
[pictureA removeFromSuperview];
[pictureA release];
when you remove it from superview. Or, better yet, make picture a property of the class:
#property (nonatomic, retain) UIImageView *pictureA;
which will release the old imageView when you assign a new one. Just make sure to release when you assign it :)
self.pictureA = [[[UIImageView alloc] init] autorelease];
or
UIImageView *imageView = [[UIImageView alloc] init];
self.pictureA = imageView;
[imageView release];
I would personally stick with the autorelease style because you'll always be able to tell at a glance if you're allocing/deallocing properly.
Also, you can always double-check your memory management using Product>Analyze in Xcode 4.