I am getting a crash on a iOS 7 app with the following error:
-[NSError release]: message sent to deallocated instance 0x3c443fe0
The error is initiated when I add a call to the following method:
-(void)loadMessages:(NSString*)customerUID {
NSString *formatUID = [NSString stringWithFormat:#"%s%#%s", "'", customerUID, "'"];
formatUID = [formatUID stringByReplacingOccurrencesOfString:#"'" withString:#"%27"];
NSString *servicePath = [NSString stringWithFormat:#"/api/messagerecipient?messageid=null&customeruid=%#", formatUID];
[[RKObjectManager sharedManager] getObjectsAtPath:servicePath parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *messagesResult)
{
NSArray *messageResults = messagesResult.array;
if (messageResults != nil || [messageResults count] != 0)
{
//Add some code here
}
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"An Error Has Occurred" message:[error localizedDescription] delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}];
}
I added multiple breakpoints into the code at various points, and it's not returning any error details. Also, nothing in the console log indicates what the problem is (I have added full RestKit logging), just the above NSError release message.
I have also run a Zombie scan in Instruments. It shows the following.
I'm confused because this shows that the zombie is being created by a GSEventRunModal call. When I go to Extended Detail and select the call, it shows the following:
Any pointers would be gratefully appreciated, thanks.
Update: Instrument Extended Details stack trace
I've seen this a lot as well and the root of the problem appears to be in Core Data. I use the MagicalRecord database library (so does RestKit) and we thought the error was there. You can see a discussion here. After all of our investigation it seemed like MagicalRecord was right and Core Data was at fault.
This had actually been filed as a bug that Apple claimed to have fixed, but we are still seeing it. The only way I've been able to work around this is by preventing every instance where I might not be able to save data so no error is reported. You can see some of those tips in the discussion thread linked to above.
Could it be that you are trying to display an AlertView from inside a block? Interaction with the UI has to be on the main thread?
How do display a UIAlertView from a block on iOS?
Can you try to replace:
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"An Error Has Occurred" message:[error localizedDescription] delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
With:
NSString * message = [error localizedDescription];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"An Error Has Occurred" message:message delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
Although I guess that the init method is getting a string anyway.
i think your problem is not with the method it self.
the error message says that you are sending a release call to an object of the type NSERROR.
please check the instance of the class which contains the method you are calling and make sure it's not deallocated.
or add the calling method to the question in order for us to check it.
In my case threading the database to a separate context helped. I used the following constructor on the class that was receiving the message:
-(id)init {
self = [super init];
if (self) {
self.managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
self.managedObjectContext.parentContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
self.managedObjectContext.retainsRegisteredObjects = YES;
}
return self;
}
Related
I have started use Parse (which I downloaded using Cocoapods) in a practice iOS application and I having a little bit of trouble understanding certain concepts.
I have written this code so far:
- (IBAction)saveUserButtonClicked:(id)sender {
PFObject *loginCredentials = [PFObject objectWithClassName:#"LoginCredentials"];
loginCredentials[#"name"] = self.usernameTextField.text;
loginCredentials[#"password"] = self.passwordTextField.text;
[loginCredentials saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if(error.code == kPFErrorConnectionFailed){
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Please check you connection" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alertView show];
}else if(succeeded && !error){
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Save" message:#"Your object saved" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alertView show];
}else if(error){
NSLog(#"%#", error);
}
}];
}
My main question I have is what is the purpose of using saveInBackGroundWithBlock. Could I do the same logic by doing:
[loginCredentials saveInBackground];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Save" message:#"Your object saved" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alertView show];
Is the block only helpful if we want to have access to the succeeded and error variables?
in saveInBackgroundWithBlock the save operation is executed in a background thread not in the main thread(thread used by UI ), once it ends executing it calls back the block to execute it. Not using the main thread for this save-operation makes the user-interface responsive while executing the save in another thread.
you can make the save operation in the main thread by using save method and then show alert based on success, but you will completely block the user interface and its not a best practice unless its necessarily to continue on the app.
bool succeeded = [loginCredentials save];
Synchronous calls will execute code on the main thread (UI thread), which will prevent the UI from responding to user events. This is generally considered bad practice because it gives the user the impression that your app has frozen when in fact one thread can't do two things at once. Therefore, you typically use asynchronous calls (blocks) to execute complex code on background threads, freeing the UI to continue performing some operation so the user isn't confused or just left hanging waiting on the operation to finish.
Looking at the PFObject spec, the – saveInBackground and – saveInBackgroundWithBlock: methods are the asynchronous options. In this case, the callback block is just reporting whether or not the operation was successful, and includes an NSError object for reporting in case it failed.
That all being said, I think you can save the object using your code, but you will not get the opportunity to respond to any errors that arise in the process. Meaning, you are making an assumption that your object saved successfully when you are creating and presenting the alert view.
I'm basing this opinion on the saveInBackground method implementation, which is just returning a BFTask object:
- (BFTask *)saveInBackground {
return [self.taskQueue enqueue:^BFTask *(BFTask *toAwait) {
return [self saveAsync:toAwait];
}];
}
Here's the object documentation on the two methods from Parse:
– saveInBackground
Saves the PFObject asynchronously.
(BFTask PF_GENERIC ( NSNumber *) *)saveInBackground
Return Value
The task that encapsulates the work being done.
Declared In PFObject.h
– saveInBackgroundWithBlock:
Saves the PFObject asynchronously and executes the given callback block.
(void)saveInBackgroundWithBlock:(PF_NULLABLE PFBooleanResultBlock)block
Parameters
block
The block to execute.
It should have the following argument signature: ^(BOOL succeeded, NSError *error).
Declared In PFObject.h
If you aren't interested in handling the errors, and your objects are sufficiently simple to save, have you considered just using one of the synchronous save methods, like - (BOOL)save or - (BOOL)save:(NSError **)error? You could immediately respond to the BOOL value that is returned, in similar fashion to the Parse example you posted above (inside the completion block).
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
I have an app where the user can authenticate with Instapaper. They need an Instapaper subscription to be able to do this, however, so if they try to log in with an account that isn't subscribed to Instapaper, I want to display an error to them.
But when they try to log in, AFNetworking sees it as successful, then displays this error to the console:
Error: Error Domain=AFNetworkingErrorDomain Code=-1011 "Expected
status code in (200-299), got 400" UserInfo=0x8374840
{NSLocalizedRecoverySuggestion=[{"error_code": 1041, "message":
"Subscription account required", "type": "error"}],
AFNetworkingOperationFailingURLRequestErrorKey=https://www.instapaper.com/api/1/bookmarks/list>,
NSErrorFailingURLKey=https://www.instapaper.com/api/1/bookmarks/list,
NSLocalizedDescription=Expected status code in (200-299), got 400,
AFNetworkingOperationFailingURLResponseErrorKey=}
All I'm using is AFXAuthClient which is a modification of AFNetworking. I subclassed it to create a custom Instapaper API client that looks like this:
#import "AFInstapaperClient.h"
#import "AFJSONRequestOperation.h"
#implementation AFInstapaperClient
+ (AFInstapaperClient *)sharedClient {
static AFInstapaperClient *sharedClient = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedClient = [[AFInstapaperClient alloc] initWithBaseURL:[NSURL URLWithString:#"https://www.instapaper.com/"]
key:#"..."
secret:#"..."];
});
return sharedClient;
}
- (id)initWithBaseURL:(NSURL *)url {
if (self = [super initWithBaseURL:url]) {
[self registerHTTPOperationClass:[AFJSONRequestOperation class]];
[self setDefaultHeader:#"Accept" value:#"application/json"];
}
return self;
}
#end
And when they log in, the following code is executed:
- (IBAction)doneButtonPressed:(UIBarButtonItem *)sender {
[[AFInstapaperClient sharedClient] authorizeUsingXAuthWithAccessTokenPath:#"/api/1/oauth/access_token"
accessMethod:#"POST"
username:self.loginBox.text
password:self.passwordBox.text
success:^(AFXAuthToken *accessToken) {
// Save the token information into the Keychain
[UICKeyChainStore setString:accessToken.key forKey:#"InstapaperKey"];
[UICKeyChainStore setString:accessToken.secret forKey:#"InstapaperSecret"];
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Login Successful"
message:#"Your articles are being downloaded now and will appear in your queue."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[alert show];
[[NSUserDefaults standardUserDefaults] setObject:#"YES" forKey:#"IsLoggedInToInstapaper"];
[self dismissViewControllerAnimated:YES completion:nil];
}
failure:^(NSError *error) {
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Login Failed."
message:#"Are you connected to the internet? Instapaper may also be down. Try again later."
delegate:nil
cancelButtonTitle:#"Okay"
otherButtonTitles: nil];
[alert show];
}];
}
But the code never goes into the failure block. How could I modify my code so that it would allow me to tell them they need an Instapaper subscription account?
Based on your situation, I don't think you will ever trigger the failure block because your request isn't failing. You are getting a response from the web service. In my experience the failure block only executes if you fail to get a response because of something like network availability or something like it.
Therefore, you need to handle the account error in the success block. One way you could do it is to read the status code that is returned in the response. If the status code is 400 like your console is showing then alert the user.
You can follow the method used here "https://stackoverflow.com/q/8469492/2670912"
It seems with this implementation, as WeekendCodeWarrior said, it will deem it successful even though they won't be able to make further requests. The code that spat out the error was actually an NSLog that I did (whoops, didn't realize it was my code outputting that) after making a request as I assumed all was fine.
My solution was just to make a request to the API in that success block, check the result of that request (which does have a response object returned) and then act accordingly on the response object.
I'm trying to post userid and password and retrieve user information using HttpRequest. I'm getting expected result, but client had reported the app is crashing after authentication. He had sent a video which shows how the app crashes. From that i concluded the app is crashing after displaying nserror message in uialertview from
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
The error message i'm getting is "The operation couldn't be completed. (NSXMLParserErrorDomain error 39.)"
After showing this message in alert view the app is crashing suddenly. I'm not facing this crash anyhow. Can anyone help me to sort out this. Thanks in advance.
The code i have used in parseErrorOccured is
NSString *errorMessage = [error localizedDescription];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Connection Error!" message:errorMessage
delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
[alertView release];
From experience, [error localizedDescription] or [error localizedFailureReason] may return a nil NSString.
In your code, you should check to see if errorMessage is nil, if it is try setting errorMessage to [error localizedFailureReason]. I'd check for a NULL value again.
Got a problem with the new Twitter.framework that I haven't been able to find a solution for yet.
Here is my code:
if ([TWTweetComposeViewController canSendTweet]){
TWTweetComposeViewController *twitter = [[TWTweetComposeViewController alloc] init];
[twitter addImage:tweetImage];
[twitter setInitialText:initalString];
[twitter addURL:url];
twitter.completionHandler = ^(TWTweetComposeViewControllerResult result) {
if (result == TWTweetComposeViewControllerResultDone) {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:#"Tweeted"
message:#"You successfully tweeted"
delegate:self cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
[alertView release];
});
} else if (result == TWTweetComposeViewControllerResultCancelled) {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:#"Twitter"
message:#"Tweet has been canceled"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
[alertView release];
});
}
dispatch_async(dispatch_get_main_queue(), ^{
[self dismissModalViewControllerAnimated:YES];
});
};
[self presentViewController:twitter animated:YES completion:nil];
[twitter release];
}
Seems to be the standard way of implementing this although I made the addition of queuing the UI stuff on the main thread. The addImage, setInitialText and addURL parameters are all good. In, fact this works most of the time. The problem I am having is that occasionally when the TWTweetComposeViewController is alloc'd init the app freezes and I can see "twitterd session interrupted, restarting... " in the console. The app will hang sometimes for only a few seconds but more often it will hang for unreasonable amount of time (20 - 30 secs or more), I will get numerous of these messages and then the twitter controller will finally slide up. Occasionally, as well, it will just hang and never come back.
Was wondering it anybody has see this problem before or has any ideas on a solution to this problem?
Thanks in advance.
I never add these problems with the twitter view controller. I used my code pasted in this post: https://stackoverflow.com/questions/9314308/can-twtweetcomposeviewcontroller-tweet-sheet-rotate-to-landscape
You can try it, just change it to "self" when you dismiss or present in modal view, as I'm using a different view controller.