Request body stream exhausted when using Parse's saveInBackgroundWithBlock: - ios

The problem only happens when I have using mobile data to upload photo to Parse that I will get "Upload Failure - Request Body Stream exhausted" error. That means if my phone is using WiFi mode, everything goes smooth.
Anyone could help me to solve the problem?
Thanks,
Kenny
My code for saving image is attached below:
self.pfProfile[#"logo"] = imageFile;
// Upload Profile to Parse
[self.pfProfile saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
[indicator stopAnimating];
if (succeeded) {
NSLog(#"Update Profile Successfully");
// Notify table view to reload the recipes from Parse cloud
//[[NSNotificationCenter defaultCenter] postNotificationName:#"refreshTable" object:self];
} else {
UIAlertController *alertController = [UIAlertController
alertControllerWithTitle:#"Upload Failure" message:[error localizedDescription]
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okayAction = [UIAlertAction actionWithTitle:#"OK"
style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:okayAction];
[self presentViewController:alertController animated:YES completion:nil];
}
}];

Related

how to prevent later code getting executed first in UIAlertController

i am working in shouldPrepareForSegue method but i am stuck in a problem
__block BOOL Stat;
if([identifier isEqualToString:#"SignOut"]){
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#"Are You Sure?" message:#"" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *can = [UIAlertAction actionWithTitle:#"CANCEL" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action){
Stat = NO;
[alert dismissViewControllerAnimated:YES completion:^{}];
}];
UIAlertAction *sign = [UIAlertAction actionWithTitle:#"SIGN OUT" style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action){
Stat = YES;
NSLog(#"%d",Stat);
}];
[alert addAction:can];
[alert addAction:sign];
[self presentViewController:alert animated:YES completion:^{}];
NSLog(#"%d",Stat);
return Stat;
}else{
return YES;
}
value of Stat always returns 0 as it is getting executed before i respond to UIAlertController as the later code are getting executed first how to prevent it.
you can create a function with completion block like below and call this where you need and just check flag
- (void)signOutWithcompletionHandler:(void (^)(BOOL flag))completionHandler
if([identifier isEqualToString:#"SignOut"]){
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#"Are You Sure?" message:#"" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *can = [UIAlertAction actionWithTitle:#"CANCEL" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action){
completionHandler(NO);
[alert dismissViewControllerAnimated:YES completion:^{}];
}];
UIAlertAction *sign = [UIAlertAction actionWithTitle:#"SIGN OUT" style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action){
completionHandler(YES);
NSLog(#"%d",Stat);
}];
[alert addAction:can];
[alert addAction:sign];
[self presentViewController:alert animated:YES completion:^{}];
}else{
completionHandler(YES);
}
If you're running code that is essentially asynchronous, returning a value from the calling method is not going to work well (unless you set up some fairly complicated blocking).
Your best bet is to have the caller provide a delegate or listen for a notification instead of depending on the returned value. That way, you can trigger whatever you need to have happen in your completion handlers.

How can I restore iOS in app purchase when an error occurred while purchasing?

I'm having a trouble with in app purchase things when an error is occurred.
I might be misunderstood in app purchase transaction, so let me know if there is something wrong.
In the payment queue observer is same.
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
for(SKPaymentTransaction *transaction in transactions){
switch(transaction.transactionState)
{
case SKPaymentTransactionStatePurchased:
[self purchasedTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
[self failedTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
[self restoreTransaction:transaction];
break;
default:
break;
}
}
and in the restoreTransaction is
-(void)restoreTransaction:(SKPaymentTransaction *)transaction{
NSLog(#"restore");
[app hideIndicatorView];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
});
[self verifyReceipt];
}
I charge the in app currency, in the verifyReceipt method which looks like
- (void)verifyReceipt
{
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
if (!receipt) { /* No local receipt -- handle the error. */
if ([UIAlertController class]) {
UIAlertController *alert = [UIAlertController
alertControllerWithTitle:nil
message:#"verify fail"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction
actionWithTitle:#"OK"
style:UIAlertActionStyleDefault
handler:nil];
[alert addAction:ok];
[self presentViewController:alert animated:YES completion:nil];
}else{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:nil message:#"verify fail" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
}else{
//server confirmation with [receipt base64EncodedStringWithOptions:0]
}
It doesn't work when a user takes restore transaction.
(Normally, it occurred when the user has some network problem or etc...)
So, please tell me, my work flow is wrong? or I missed something?
Is there any way to test restore transaction?

WKWebView completionHandler called before dismissal

I am using WKUIDelegate this function to handle javascript alert
-(void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
{
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Test Alert", nil)
message:message
delegate:self
cancelButtonTitle:nil
otherButtonTitles:#"OK", nil] autorelease];
[alert show];
completionHandler();
}
According to Apple documentation we should call compeletionHandler() of an alert after OK button is pressed on alert as mentioned here
How to call completionHandler() after press OK button is pressed? If I don't call completionHandler() expection is thrown
**[WKWebViewController webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:
completionHandler:]:
***** Terminating app due to uncaught exception 'NSInternalInconsistencyException',
reason: 'Completion handler passed to -[WKWebViewController
webView:runJavaScriptAlertPanelWithMessage:
initiatedByFrame:completionHandler:] was not called'****
UPDATE:
The solution mentioned below by Stefan is working fine with JS Alert but not with JS Confirm. Following is the code I get same exception even if the completionHandler() is called in ok and cancel button.
-(void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler
{
MKCLOG_DEBUG(#"%#", frame.request.URL);
UIAlertController* alert = [UIAlertController alertControllerWithTitle:
NSLocalizedString(#"Test", nil) message: message
preferredStyle: UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction
actionWithTitle:NSLocalizedString(#"Cancel", #"")
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action)
{
MKCLOG_DEBUG(#"Cancel action");
completionHandler(NO);
}];
UIAlertAction *okAction = [UIAlertAction
actionWithTitle:NSLocalizedString(#"OK", #"OK action")
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action)
{
MKCLOG_DEBUG(#"OK action");
completionHandler(YES);
}];
[alert addAction:cancelAction];
[alert addAction:okAction];
}
The way your code is setup now, you display the UIAlertView and immediately run the completionHandler(). Both happen at the same time.
What you should do instead is something like this:
UIAlertController* alert = [UIAlertController alertControllerWithTitle:
NSLocalizedString(#"Test Alert", nil) message: message
preferredStyle: UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle: #"OK"
style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
completionHandler();
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
This will present the alert and call the completionHandler when the user dismisses it.
Note that I am using the UIAlertController, which is only available on iOS 8 and up, but that should be fine since you depend on WKWebView.

Objective-C open links in Safari and Alert Dialog

I have a UIwebView, it has a few links within the webpage. I want a certain link to open an alert modal like in image #1
Also, how can use the code below to make something like this - (IMAGE #1) http://screenshot.it.sftcdn.net/blog/it/2014/01/Block-user-03-Tasto-Block-378x568.png in objective-c
- (IBAction)showAlert:(id)sender
{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:#"Open In..."
message:#"Which app would you like to open?"
preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *mapsAction = [UIAlertAction actionWithTitle:#"Maps"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
if (![self openURLForString:#"maps://"]) {
NSLog(#"Couldn't Open Maps");
}
}];
UIAlertAction *youtubeAction = [UIAlertAction actionWithTitle:#"YouTube"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
if (![self openURLForString:#"http://www.youtube.com/watch?v=dQw4w9WgXcQ"]) {
NSLog(#"Couldn't Open YouTube");
}
}];
UIAlertAction *messagesAction = [UIAlertAction actionWithTitle:#"Messages"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
if (![self openURLForString:#"sms://"]) {
NSLog(#"Couldn't Open Messages");
}
}];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:#"Cancel"
style:UIAlertActionStyleCancel
handler:nil];
[alertController addAction:mapsAction];
[alertController addAction:youtubeAction];
[alertController addAction:messagesAction];
[alertController addAction:cancelAction];
[self presentViewController:alertController animated:YES completion:nil];
}
- (BOOL)openURLForString:(NSString *)urlString {
NSURL *url = [NSURL URLWithString:urlString];
if ([[UIApplication sharedApplication] canOpenURL:url]) {
[[UIApplication sharedApplication] openURL:url];
return YES;
}
return NO;
}
Where the "report inappropriate" being a link opening in a second UIwebView that opens up OVER the parent webview and the "share" opens up in Safari.
(Disregard the "copy link/URL")
You would need to first register your view controller for the web view protocol.
And then in your view controller implement the delegate method for web view did start loading and check the URL being called and do your tasks accordingly using an if else check
Here's the delegate reference:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIWebViewDelegate_Protocol/
Answered from my phone. Pardon syntax.
Hope this helps.

App stops after calling performSegue inside Touch ID block

Hi I’m experiencing a strange behavior I really don’t understand.
I present a touch ID identification to the user and if he’s authorized I
call a [self performSegueWithIdentifier: #"callCustomSegue" sender:self];
inside the block in this way:
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL success, NSError *error) {
if (success) {
[self performSegueWithIdentifier: #"callCustomSegue" sender:self];
Then the app stops for several seconds (at least 3-4) then next ViewController is presented.
The perform called by “callCustomSegue” does this:
- (void) perform {
src = (UIViewController *) self.sourceViewController;
dst = (UIViewController *) self.destinationViewController;
[src.view addSubview:dst.view];
}
I don’t understand what’s happening between the identification on touch ID and the performSegueWithIdentifier
and why the app stops.
If I bypass the touch ID and just call the performSegueWithIdentifier works immediately as I would expect.
If I put in the touch ID block:
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL success, NSError *error) {
if (success) {
authenticated = YES;
[self showMessage:#"Authentication is successful" withTitle:#"Success"];
}
where showMessage does this:
UIAlertController * alert= [UIAlertController
alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* cancel = [UIAlertAction
actionWithTitle:#"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
[alert dismissViewControllerAnimated:YES completion:nil];
if (authenticated) {
[self performSegueWithIdentifier: #"callCustomSegue" sender:self];
}
if (!authenticated) {
[self touchID];
}
}];
after tapping OK the next ViewController is called immediately.
So the question is: why I can’t call performSegue within the touch ID block and get an immediate response?
Any idea where I’m wrong?
Thank you so much.
You should perform all UI related activities on the main queue. The reply block for the touchID process is not guaranteed to be executing on the main queue. In fact you can almost guarantee that it won't be.
You should have -
if (success) {
authenticated = YES;
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier: #"callCustomSegue" sender:self];
});

Resources