I have a UIViewController with a UITableView in it. I add a UIView as a subview on top of that. When I press one of the UIButtons on the subview, there is a noticeable lag. How do I make it faster?
See video: http://www.youtube.com/watch?v=KWy6NrZUeqA&feature=youtu.be
- (IBAction)tweetThat:(id)sender {
[MBProgressHUD showHUDAddedTo:self.socialMediaView animated:YES];
dispatch_queue_t queueOne=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_sync(queueOne, ^{
NSString *tweetBody=#"BLABLABLATweet";
if ([TWTweetComposeViewController canSendTweet])
{
TWTweetComposeViewController *tweetSheet =
[[TWTweetComposeViewController alloc] init];
[tweetSheet setInitialText:tweetBody];
dispatch_async(dispatch_get_main_queue(), ^{
[MBProgressHUD hideHUDForView:self.controllerView animated:YES];
[self presentModalViewController:tweetSheet animated:YES];
});
}
});
}
I've used the dispatch method you tried above, but with a few changes. It has really made the experience a lot better. "loadingView" is as named, just a loading view that displays before the tweet view comes up.
loadingView.hidden = NO;
[loadingView setNeedsDisplay];
if ([TWTweetComposeViewController canSendTweet])
{
double delayInSeconds = 0.5;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
TWTweetComposeViewController *tweet = [[TWTweetComposeViewController alloc]init];
[tweet setInitialText:#"I'm using a new app called TickTalk to help my speaking cadence. Check it out!"];
[tweet addURL:[NSURL URLWithString:#"http://www.ticktalkapp.com"]];
TWTweetComposeViewControllerCompletionHandler
completionHandler =
^(TWTweetComposeViewControllerResult result) {
switch (result)
{
case TWTweetComposeViewControllerResultCancelled:
NSLog(#"Twitter Result: canceled");
break;
case TWTweetComposeViewControllerResultDone:
NSLog(#"Twitter Result: sent");
break;
default:
NSLog(#"Twitter Result: default");
break;
}
loadingView.hidden = YES;
[self dismissModalViewControllerAnimated:YES];
};
[tweet setCompletionHandler:completionHandler];
[self presentModalViewController:tweet animated:YES];
});
}
else
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Sorry" message:#"Your device is not setup to tweet" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
loadingView.hidden = YES;
}
change your dispatch_sync to dispatch_async. what is the point of dispatching to the background if you are going to lock up the UI until it returns.
The lag is from TWTweetComposeViewController. There is nothing you can do about it because its a system optimization. You'll probably notice the second and third times you hit the button the lag it gone.
Related
Ok so here is a picture of my basic setup
Now this may not be the best way to set it all up but I did what I could with the knowledge I had to get the effect I wanted. Now my problem is originates in view 1 but only happens if you do this: Start at the menu click view 2,3 or 4 to go to that view then go to view 1 using the tabbar button now at this screen you would click the get pictures button which has the code below in its viewcontroller to show the image picker. Now the problem comes is if you go back at this point it takes you to the tabbarview that you clicked from the menu whether that was 2,3,or 4. It goes back fine if you clicked view 1 from the menu
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.selectedPhotos = [NSMutableArray array];
__block AGViewController *blockSelf = self;
ipc = [[AGImagePickerController alloc] initWithDelegate:self];
ipc.didFailBlock = ^(NSError *error) {
NSLog(#"Fail. Error: %#", error);
if (error == nil) {
[blockSelf.selectedPhotos removeAllObjects];
NSLog(#"User has cancelled.");
[blockSelf dismissViewControllerAnimated:YES completion:nil];
} else {
// We need to wait for the view controller to appear first.
double delayInSeconds = 0.5;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[blockSelf dismissViewControllerAnimated:YES completion:nil];
});
}
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault animated:YES];
};
ipc.didFinishBlock = ^(NSArray *info) {
[blockSelf.selectedPhotos setArray:info];
NSLog(#"Info: %#", info);
//add all selected photos to the claim
[blockSelf setClaimPhotos:info];
[blockSelf dismissViewControllerAnimated:YES completion:nil];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault animated:YES];
};
}
- (void)openAction:(id)sender
{
// Show saved photos on top
ipc.shouldShowSavedPhotosOnTop = NO;
ipc.shouldChangeStatusBarStyle = YES;
ipc.selection = self.selectedPhotos;
ipc.maximumNumberOfPhotosToBeSelected = 5;
// Custom toolbar items
AGIPCToolbarItem *selectAll = [[AGIPCToolbarItem alloc] initWithBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:#"+ Select All" style:UIBarButtonItemStyleBordered target:nil action:nil] andSelectionBlock:^BOOL(NSUInteger index, ALAsset *asset) {
return YES;
}];
AGIPCToolbarItem *flexible = [[AGIPCToolbarItem alloc] initWithBarButtonItem:[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil] andSelectionBlock:nil];
AGIPCToolbarItem *deselectAll = [[AGIPCToolbarItem alloc] initWithBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:#"- Deselect All" style:UIBarButtonItemStyleBordered target:nil action:nil] andSelectionBlock:^BOOL(NSUInteger index, ALAsset *asset) {
return NO;
}];
ipc.toolbarItemsForManagingTheSelection = #[selectAll, flexible, flexible, deselectAll];
[self presentViewController:ipc animated:YES completion:nil];
}
(the open action is what is tied to the button on the vc)
I really need help on this one as Ive been stuck on this issue all week and have been trying all types of dissmiss view controller ect ect.
The problem was due a custom class on the TabBarController that was causing an unexpecting behavior with SelectedIndex property.
-(IBAction)addtocontacts:(id)sender
{
HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.labelText = NSLocalizedString(#"Saving_data", #"");
//added my validation here
[self performSelectorInBackground:#selector(insertDetails) withObject:nil];
}
-(void) insertDetails
{
//save contact details in database
[HUD hide:YES];
UIAlertView *alertview=[[UIAlertView alloc]initWithTitle:#"" message:#"Contact account details added" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alertview show];
}
I have added loading symbol on SaveButton click.I am not getting loading symbol.How do I make it appear until I get alert message.
Add HUD on top most layer. Example if you have tableview on top of view. Then add it on tableview. In my case I am adding HUD on tableviews and its working fine
it is because you are instantly hiding the HUD in insertDetails.
-(IBAction)addtocontacts:(id)sender
{
HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.labelText = NSLocalizedString(#"Saving_data", #"");
//added my validation here
[self performSelectorInBackground:#selector(insertDetails) withObject:nil];
}
-(void) insertDetails
{
//save contact details in database
// [HUD hide:YES]; remove it
UIAlertView *alertview=[[UIAlertView alloc]initWithTitle:#"" message:#"Contact account details added" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alertview show];
}
and instead download the newer version of MBProgressHUD and use the following Method
- (IBAction)addtocontacts:(id)sender {
// The hud will dispable all input on the view (use the higest view possible in the view hierarchy)
HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.view addSubview:HUD];
// Regiser for HUD callbacks so we can remove it from the window at the right time
HUD.delegate = self;
// Show the HUD while the provided method executes in a new thread
[HUD showWhileExecuting:#selector(myTask) onTarget:self withObject:nil animated:YES];
}
and implement the delegate method.
MBProgressHUDDelegate methods
- (void)hudWasHidden:(MBProgressHUD *)hud {
// Remove HUD from screen when the HUD was hidded
[HUD removeFromSuperview];
[HUD release];
HUD = nil;
}
I wan to to show a message using the MBProgressHUD during the uploading via NSURL string. So i code that:
MBProgressHUD *hud1 = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud1.labelText = #"sending info ...";
hud1.minShowTime =10.0;
NSURL *url =[NSURL URLWithString:self.urlToUpload];
the 10 second time is in order to wait some time i want user wait. It works, but I would show another message when the first desappear. Using another:
MBProgressHUD *hud2 = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud2.labelText = #"SENT!";
hud2.minShowTime =2.0;
it is not useful, because this message overlaps the first one.
Any tips about that?
I would remove the first HUD in your -connectionDidFinishLoading method or wherever you get notification that the string has been uploaded successfully.
[MBProgressHUD hideHUDForView:self.view animated:YES];
Then you can add your next HUD for 1-2 seconds. By just adding it via a specific time, there is no way to accurately remove the first HUD before the next one shows.
This was taken from the MBProgressHUD demo project. I would use this to display your timed completion HUD.
HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
// The sample image is based on the work by http://www.pixelpressicons.com, http://creativecommons.org/licenses/by/2.5/ca/
// Make the customViews 37 by 37 pixels for best results (those are the bounds of the build-in progress indicators)
HUD.customView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"37x-Checkmark.png"]] autorelease];
// Set custom view mode
HUD.mode = MBProgressHUDModeCustomView;
HUD.delegate = self;
HUD.labelText = #"Completed";
[HUD show:YES];
[HUD hide:YES afterDelay:3];
+(void)toast:(NSString*) str view:(UIView*)view delegate:(id)delegate type:(IconType)type{
[MBProgressHUD hideHUDForView:view animated:YES];
MBProgressHUD * HUD = [[MBProgressHUD alloc] initWithView:view];
[view addSubview:HUD];
NSString* strImage;
switch (type) {
case kNone:
strImage=nil;
break;
case kOK:
strImage=#"37x-Checkmark.png";//NSString stringWithFormat:#"%#",
break;
case kError:
strImage=#"ic_cancel_white_24dp.png";//NSString stringWithFormat:#"%#",
break;
default:
break;
}
HUD.customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:strImage] ];
// Set custom view mode
HUD.mode = MBProgressHUDModeCustomView;
HUD.delegate = delegate;
HUD.labelText = str;
HUD.userInteractionEnabled = NO;
[HUD show:YES];
[HUD hide:YES afterDelay:1.5f];
}
I'm trying to write code to select an image from the photo library on an iPad. The code that I'm using is below (taken from Apple's website), but it keeps giving me an error saying that On iPad, UIImagePickerController must be presented via UIPopoverController. I've tried changing this line: UIImagePickerController *mediaUI = [[UIImagePickerController alloc] init]; to use a UIPopoverController, but obviously I'm doing something wrong because its not working.
- (BOOL) selectImage: (UIViewController*) controller
usingDelegate: (id <UIImagePickerControllerDelegate,
UINavigationControllerDelegate>) delegate {
if (([UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeSavedPhotosAlbum] == NO)
|| (delegate == nil)
|| (controller == nil))
return NO;
UIImagePickerController *mediaUI = [[UIImagePickerController alloc] init];
mediaUI.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
// Displays saved pictures and movies, if both are available, from the
// Camera Roll album.
mediaUI.mediaTypes =
[UIImagePickerController availableMediaTypesForSourceType:
UIImagePickerControllerSourceTypeSavedPhotosAlbum];
// Hides the controls for moving & scaling pictures, or for
// trimming movies. To instead show the controls, use YES.
mediaUI.allowsEditing = NO;
mediaUI.delegate = delegate;
[controller presentModalViewController: mediaUI animated: YES];
return YES; }
The Apple Developer page also says: "On iPad, you can alternatively present the browser interface using a popover as described in initWithContentViewController: and “Presenting and Dismissing the Popover” in UIPopoverController Class Reference." I've read it but I still can't get it to work. Any help would be appreciated.
Something like this should work:
// create an image picker controller
UIImagePickerController *imagePickerController = [[[UIImagePickerController alloc] init] autorelease];
imagePickerController.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
imagePickerController.delegate = self;
// present it in a popover
self.popoverController = [[[UIPopoverController alloc] initWithContentViewController:imagePickerController] autorelease];
self.popoverController.delegate = self;
// I was presenting the popover from a button, but you would set the rect to whatever is appropriate for your app
[self.popoverController presentPopoverFromRect:((UIButton *)sender).bounds inView:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
Declare an ivar such as:
UIPopoverController *imagePopover;
Then:
imagePopover = [[UIPopoverController alloc] initWithContentViewController:mediaUI];
[imagePopover setDelegate:self];
[imagePopover presentPopoverFromRect:someRect
inView:someView
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
in place of
[controller presentModal...];
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
popover = [[UIPopoverController alloc] initWithContentViewController:imagePicker];
[popover presentPopoverFromRect:CGRectMake(0.0, 0.0, 400.0, 400.0)
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
refer below link
http://www.techotopia.com/index.php/An_Example_iOS_4_iPad_Camera_and_UIImagePickerController_Application_%28Xcode_4%29
I went through a lot of pain coming up with a solution which works on both iPad and iPhone, this is the final code which some of it comes from comments of other people:
the code has some bugs but it's a very good place to start :)
it covers permissions needed as well as how to manage viewcontrollers popoing up on ipad.
requires following imports :
#import <AVFoundation/AVFoundation.h>
#import <AssetsLibrary/AssetsLibrary.h>
and add this delegates :
UIActionSheetDelegate, UIImagePickerControllerDelegate
definitions :
__weak IBOutlet UIButton *attachButton;
UIImage *image;
button's action :
- (IBAction)doAttach:(id)sender {
UIActionSheet *action = [[UIActionSheet alloc] initWithTitle:#"Select image from" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"From library",#"From camera", nil] ;
[action showInView:self.view];
}
#pragma mark - ActionSheet delegates
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if( buttonIndex == 1 ) {
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if(authStatus == AVAuthorizationStatusAuthorized)
{
NSLog(#"%#", #"You have camera access");
}
else if(authStatus == AVAuthorizationStatusDenied)
{
NSLog(#"%#", #"Denied camera access");
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
if(granted){
NSLog(#"Granted access to %#", AVMediaTypeVideo);
} else {
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#“no camera access“
message: #“if you need to use camera in this application go to settings -> appName -> and turn on camera.”
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#“ok” style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
NSLog(#"Not granted access to %#", AVMediaTypeVideo);
return ;
}
}];
}
else if(authStatus == AVAuthorizationStatusRestricted)
{
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#“no camera access“
message: #“if you need to use camera in this application go to settings -> appName -> and turn on camera.”
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#“ok” style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
NSLog(#"%#", #"Restricted, normally won't happen");
}
else if(authStatus == AVAuthorizationStatusNotDetermined)
{
NSLog(#"%#", #"Camera access not determined. Ask for permission.");
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
if(granted){
NSLog(#"Granted access to %#", AVMediaTypeVideo);
} else {
NSLog(#"Not granted access to %#", AVMediaTypeVideo);
return ;
}
}];
}
else
{
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#“No camera access“
message: #“error accusing camera”
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#“ok” style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
return;
//NSLog(#"%#", #"Camera access unknown error.");
}
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
UIImagePickerController *pickerView =[[UIImagePickerController alloc]init];
pickerView.allowsEditing = YES;
pickerView.delegate = self;
pickerView.sourceType = UIImagePickerControllerSourceTypeCamera;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
[ self.presentedViewController dismissViewControllerAnimated:YES completion:nil ];
pickerView.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController *popPC = pickerView.popoverPresentationController;
popPC.sourceView = attachButton;
popPC.permittedArrowDirections = UIPopoverArrowDirectionAny;
[self presentViewController:pickerView animated:YES completion:nil];
} else {
[self presentModalViewController:pickerView animated:YES ];
}
}
}else if( buttonIndex == 0 ) {
ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus];
switch (status) {
case ALAuthorizationStatusRestricted:
case ALAuthorizationStatusDenied:
{
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#“no access to library”
message: #“if you wish to access photos in this app go to settings -> appName-> and turn on photos .”
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#“ok” style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
}
break;
default:
{
UIImagePickerController *pickerView = [[UIImagePickerController alloc] init];
pickerView.allowsEditing = YES;
pickerView.delegate = self;
[pickerView setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
[ self.presentedViewController dismissViewControllerAnimated:YES completion:nil ];
pickerView.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController *popup = pickerView.popoverPresentationController;
popup.sourceView = attachButton;
popup.permittedArrowDirections = UIPopoverArrowDirectionAny;
[self presentViewController:pickerView animated:YES completion:nil];
} else {
[self presentModalViewController:pickerView animated:YES ];
}
}
break;
}
}
}
#pragma mark - PickerDelegates
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
[self dismissModalViewControllerAnimated:true];
UIImage * img = [info valueForKey:UIImagePickerControllerEditedImage];
image = img;
}
i have a Problem with my Activity Indicators. I have an Button which reload a Website and Display between a Activity Indicator. The Problem is if the User hits more than 1 Times on the Button it will rebuild a new Indicator and this Indicator freezes on the Screen all the Time.
Button disabling is not working. Has anyone a Solution for this Problem. Please help.
Here is my Code:
-(IBAction) buttonReload {
Reachability *r = [Reachability reachabilityWithHostName:#"www.google.com"];
NetworkStatus internetStatus = [r currentReachabilityStatus];
if ((internetStatus != ReachableViaWiFi) && (internetStatus != ReachableViaWWAN)){
UIAlertView *myAlert = [[UIAlertView alloc]
initWithTitle:#"No Inet!" message:#"You need a Inet Connection..."
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[myAlert show];
[myAlert release];
}
else
{
//Website loading
[self performSelector: #selector(doLoadWebsite)
withObject: nil
afterDelay: 0];
return;
}
}
- (void) doLoadWebsite
{
//add activity indicator
NewsActivity = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(140.0f, 180.0f, 40.0f, 40.0f)];
[NewsActivity setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray];
[self.view addSubview: NewsActivity];
[NewsActivity startAnimating];
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(finishActivity) userInfo:nil repeats:YES];
//NewsActivity.backgroundColor = [UIColor grayColor];
NewsActivity.hidesWhenStopped = YES;
// Show Status Bar network indicator
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
//perform time-consuming tasks
//load News Website
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.google.com"]]];
}
-(void) finishActivity {
if (!webView.loading) {
[self.NewsActivity removeFromSuperview];
[NewsActivity stopAnimating];
//Hide network activity indicator
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
else {
[NewsActivity startAnimating];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}
}
You should perform stopAnimating , removeFromSuperView once the page is loaded. If the user refreshes the page again, you can again add it to the subView and startAnimating.