System hangs when showing a UIAllertView inside a SLRequestHandler - ios

I am using SLRequest to send user's video to twitter. After finishing the post request, I want to inform the user whether the upload is successful. But if I show a UIAlertView inside the SLRequestHandler, the system simply hangs and doesn't show the alert view at all. Is it a no-go to have a UIAlertView inside the SLRequestHandler? What is the better way to show a custom message based on the result of the post request?
Here is my sample code:
SLRequest *postRequest2 = [SLRequest
requestForServiceType:SLServiceTypeTwitter
requestMethod:SLRequestMethodPOST
URL:requestURL2 parameters:message2];
postRequest2.account = twitterAccount;
[postRequest2
performRequestWithHandler:^(NSData *responseData,
NSHTTPURLResponse *urlResponse, NSError *error)
{
if (error != nil) {
NSLog(#"error: %#", error);
}
else {
UIAlertView *theAlert = [[UIAlertView alloc] initWithTitle:#"Success!"
message:#"Your video is now available in your Twitter account"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[theAlert show];
}
}];

All UI related operations must be on the main thread.
Would you try to dispatch on the main thread your alert view?
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *theAlert = [[UIAlertView alloc] initWithTitle:#"Success!" message:#"Your video is now available in your Twitter account" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[theAlert show];
});
Please note that UIAlertView is deprecated since iOS 8, and the use of UIAlertViewController is recommended.

You are trying to show the alert message in a block.
Alerts are UI Thread (main thread) controls. So, modify else part and show your alert in dispatch_async, it will work.
dispatch_async(dispatch_get_main_queue(), ^{
[theAlert show];
});

Related

Why I am not getting UIAlertView [duplicate]

This question already has answers here:
Why isn't UIAlertView Showing?
(4 answers)
Closed 7 years ago.
I am using parse for sign-in/sign-up process.
Everything is working fine. Until user gives wrong details.
In else part of Parse Login I have written:
self.view.userInteractionEnabled = YES;
[SVProgressHUD dismiss];
// The login failed. Check error to see why.
NSString *message = [NSString stringWithFormat:#"%#",[error valueForKey:#"Error"]];
UIAlertView *myalert = [[UIAlertView alloc]initWithTitle:#"SO" message:message delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles: nil];
[myalert show];
I checked after putting breakpoints in every line.
After executing the 3rd Line i.e. NSSString *message the control doesn't go for alert it directly shows me UI without any alert box.
And In Log I am getting
[Error]: invalid login parameters (Code: 101, Version: 1.7.5)
I doesn't know what to do ? I have written only this code in else part.
I am using Parse Code :
[user signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error)
{
if (!error)
{
// Hooray! Let them use the app now.
}
else
{
NSString *errorString = [error userInfo][#"error"]; // Show the errorString somewhere and let the user try again.
}
}];
and In else part I want to show and alertView
Try this :
UIAlertView *myalert = [[UIAlertView alloc]initWithTitle:#"SO" message:message delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles: nil];
dispatch_async(dispatch_get_main_queue(), ^(void){
[myalert show];
});
Try this code
NSString *errorString;
UIAlertView *AV;
[user signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (!error) { // Hooray! Let them use the app now.
} else { errorString = [error userInfo][#"error"]; // Show the errorString somewhere and let the user try again.
AV = [[UIAlertView alloc]initWithTitle:#"SO" message:errorString delegate:nil cancelButtonTitle:#"Cancel" otherButtonTitles:nil, nil];
[AV show];
}
}];
try to call main thread first then create the UIAlert in it
coz mostly thats happen when you are not in the main thread
hope this solve your problem goodluck

How to show an alert in ios for paper out error from zebra printer?

I'm trying to show an alert from my app. When my app is successfully connected with zebra printer and then if the printer doesnot have paper at the time of printing.. i want to show an alert in my app about the paper out error... please sunbmit your answers if anybody knows...
What exactly you are looking for? Do you want to know the code for how to create and show an alert? or do you want to interact with printer and get the status so as to show alert?
If you are looking for code that shows an alert here you go..
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Printer Warning" message:#"Printer running out of paper" delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alertView show];
have u used this block?
void (^completionhandler)(UIPrintInteractionController *, BOOL, NSError *) = ^(UIPrintInteractionController *print, BOOL completed, NSError *error)
{
if (!completed && error)
{
NSLog(#"%#", error.localisedDescription);
}
};
if any error occurs, the error will be logged and u can also use it in AlertView.
if(!completed && error)
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:error.localisedDescription cancelButtonTitle:nil otherButtons:#"OK", nil];
[alertview show];
}

Parse - Sign Up and Login at the same time

Using Parse (iOS framework), I am able to sign up and login successfully using two API.
When user log in, it will cache the user and so accessing "currentUser" will return appropriate object. But sign up API is not caching.
Is there any way that sign up itself will cache the user and avoid separate log in functionality?
It should automatically log you in as well. For example, if in your completion block in signUpInBackground, you have a segue to your main screen and in your main screen, it is supposed to show information related to the user, then it will because [PFUser currentUser] is set to the user that registered.
here is an example
[user signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (error) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[[error userInfo] objectForKey:#"error"] message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:#"Ok", nil];
[alertView show];
// Bring the keyboard back up, because they'll probably need to change something.
[_usernameField becomeFirstResponder];
}
else{
// Success!
[self performSegueWithIdentifier:#"goToMain" sender:self];
}
}];

When should I renew an ACAccount? Or, how to check if the credential is expired. (Facebook)

Recently I was assigned to survey how to use iOS framework ACAccount and Social to implement facebook post function. It is quite simple to gain access of the account configured in setting.
if(!_accountStore)
_accountStore = [[ACAccountStore alloc] init];
ACAccountType *facebookTypeAccount = [_accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
// Check if there is any faceboook account
NSArray *accounts = [_accountStore accountsWithAccountType:facebookTypeAccount];
if (![accounts count]) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"alert" message:#"No facebook account configured in setting." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
return;
}
[_accountStore requestAccessToAccountsWithType:facebookTypeAccount
options:#{ACFacebookAppIdKey: #"FACEBOOK-APP-ID", ACFacebookPermissionsKey: #[#"email"]}
completion:^(BOOL granted, NSError *error) {
if(granted){
NSArray *accounts = [_accountStore accountsWithAccountType:facebookTypeAccount];
_facebookAccount = [accounts lastObject];
NSLog(#"Success");
}else{
// ouch
NSLog(#"Failed, Error: %#", error);
dispatch_async(dispatch_get_main_queue(), ^{
NSString *message = [NSString stringWithFormat:#"App access denied, please grant access in Setting->Facebook. Error message::%#", error];
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Alert" message:message delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
});
}
}];
Once the app gain access to facebook, it can post message by using SLComposeViewController:
- (IBAction)postButtonPressed:(id)sender {
if (!_facebookAccount) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"alert" message:#"login first" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
return;
}
SLComposeViewController *fbController = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
if([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {
SLComposeViewControllerCompletionHandler __block completionHandler=^(SLComposeViewControllerResult result){
[fbController dismissViewControllerAnimated:YES completion:nil];
switch(result){
case SLComposeViewControllerResultCancelled:
default:
{
NSLog(#"Cancelled.....");
}
break;
case SLComposeViewControllerResultDone:
{
NSLog(#"Posted....");
}
break;
}};
[fbController setInitialText:#"Test message"];
[fbController setCompletionHandler:completionHandler];
[self presentViewController:fbController animated:YES completion:nil];
} else {
NSLog(#"no facebook setup");
}
Here comes my question. I found that there is a method in ACAccountStore which is used to renew expired credential of an ACAccount:
- (void)renewCredentialsForAccount:(ACAccount *)account completion:(ACAccountStoreCredentialRenewalHandler)completionHandler;
But I don't even know how to check whether the credential is expired so that I can renew it. Anyone got an idea about this?
Oh, by the way, we just want to use the native Social framework to do simple work such as post some message or picture. So, if not needed, we are not going to use the facebook SDK.
If you know anything about how to check the credential is valid or not, please leave a comment or submit an answer, thank you:)
Updates 2013.11.20 11:10 AM
I learn something from my experiments to this issue..
One is not able to get certain type of accounts from account store before he gains access to them, so I should not check account count before request for access.
Renew notification called when the app using ACAccount is in background after facebook account changed. Currently, I only saw changes of access right triggers the notification.
If the user changes password, the system will pop out an alert when the user attempt to post something, which ask the user to change password.
I think monitor notifications of account change is enough to handle the changes. I'll accept the first answer.
You should renew the user acc everytime it is out of sync. This may happen if the user has changed his password or when the acc session has expired.
Yo can know you are in that scenario using the following notification:
ACAccountStoreDidChangeNotification
I don't think there is active way , best is to write renew function and call
renewCredentialsForAccount of the framework

Adding event to calendar very slow

I am simply wanting to add an event to the device's calendar.
I'm using:
__weak ProgramViewController *weakSelf = self;
EKEventStore *store = [[EKEventStore alloc] init];
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error)
{
if (error)
NSLog(#"EKEventStore error = %#", error);
if (granted)
{
NSLog(#"EKEvent *event ");
EKEvent *event = [EKEvent eventWithEventStore:store];
event.title = weakSelf.program.title;
event.location = weakSelf.program.locationPublic;
event.startDate = weakSelf.program.startTime;
event.endDate = weakSelf.program.endTime;
[event setCalendar:[store defaultCalendarForNewEvents]];
NSError *err = nil;
[store saveEvent:event span:EKSpanThisEvent commit:YES error:&err];
if (err)
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Calendar Error" message:err.localizedDescription delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
else
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Added" message:#"Calendar event added." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
}
}];
and in iOS 6 it can take 6/7 seconds (iPhone 4) and on iOS 7 (on an iPhone 5S) it takes ~10 seconds. Is this normal behaviour? If not what am I doing wrong?
I had the same issue. Thanks to Jasper's answer, I got thinking about queues. Try this:
if (!err)
{
dispatch_async(dispatch_get_main_queue(),
^{
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(#"event added", nil) message:nil delegate:nil cancelButtonTitle:NSLocalizedString(#"ok", nil) otherButtonTitles:nil] show];
});
}
Here's why this is needed (see emphasis)
Discussion
In iOS 6 and later, requesting access to an event store
asynchronously prompts your users for permission to use their data.
The user is only prompted the first time your app requests access to
an entity type; any subsequent instantiations of EKEventStore uses
existing permissions. When the user taps to grant or deny access, the
completion handler will be called on an arbitrary queue. Your app is
not blocked while the user decides to grant or deny permission.
Since UIAlertView is UIKit, and UIKit always requires the main thread, any other arbitrary thread will crash or lead to unpredictable behaviour.
https://developer.apple.com/library/ios/documentation/EventKit/Reference/EKEventStoreClassRef/Reference/Reference.html
According to the docs: "An EKEventStore object requires a relatively large amount of time to initialize and release." . . so you should dispatch this on a background queue.
Also, oddly, it takes longer on the main queue than the background queue - not sure why this is!

Resources