When I am running my code, my code is stuck and gives log as:
void _WebThreadLockFromAnyThread(bool), 0x904db10: Obtaining the web lock from a thread other than the main thread or the web thread. UIKit should not be called from a secondary thread.
What is the reason, and what is the solution for this?
My Code:
-(IBAction)action:(id)sender{
NSLog(#"HI");
[self performSelectorInBackground:#selector(parse) withObject:nil];
}
-(void)parse{
rssOutputData = [[NSMutableArray alloc]init];
//[self performSelectorOnMainThread:#selector() withObject:nil waitUntilDone:NO];
[NSThread detachNewThreadSelector: #selector(startIndicator) toTarget: self withObject: self];
url=[[NSURL alloc]initWithString:[NSString stringWithFormat:#"http://service.technologyorg.com/service1/AuthenticateStudent=%#,%#,1",t1.text,t2.text]];
NSLog(#"A%#",url);
NSURLRequest *lRequest = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:30.0];
NSURLResponse *response;
NSError * error;
//[NSURLConnection connectionWithRequest:lRequest delegate:self];
[NSURLConnection sendSynchronousRequest:lRequest returningResponse:&response error:&error];
NSLog(#"AB%#",response);
if (nil == response) {
NSLog(#"%#",error);
[self performSelectorOnMainThread:#selector(updateTable) withObject:nil waitUntilDone:NO];
UIAlertView * alert=[[UIAlertView alloc]initWithTitle:#"Connection failed!" message:nil delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
}
xmlData=[[NSMutableData alloc]initWithContentsOfURL:url];
NSLog(#"B%#",xmlData);
xmltitle=nil;
xmlParserObject =[[NSXMLParser alloc]initWithData:xmlData];
[xmlParserObject setDelegate:self];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[xmlParserObject parse];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"XML:%#",xmllink);
if ([xmltitle isEqualToString:#"true"]) {
HomeViewController *lv=[[HomeViewController alloc]init];
lv.s1=[[NSString alloc]initWithFormat:#"%#",xmllink];
lv.s2=[[NSString alloc]initWithFormat:#"%#",xm1];
myStaticPassword=[[NSString alloc]initWithFormat:#"%#",xm2];
[self presentModalViewController:lv animated: YES];
[self performSelectorOnMainThread:#selector(updateTable) withObject:nil waitUntilDone:NO];
}else{
[self performSelectorOnMainThread:#selector(updateTable) withObject:nil waitUntilDone:NO];
UIAlertView * alert=[[UIAlertView alloc]initWithTitle:#"Incorrect Username/Password" message:#"Please check your Username or Password" delegate:nil cancelButtonTitle:#"Cancel" otherButtonTitles:nil, nil];
[alert show];
}
});
});
}
Related
This question already has answers here:
UIAlertView fails to show and results in “EXC_BAD_ACCESS” error
(6 answers)
Closed 8 years ago.
I'm using AFNetworking to make a web request. After the web request completes. I want a UIAlertView to be shown. I'm using ARC and the code seems to work on devices. If I use a simulator I get an error: EXC_BAD_ACCESS
What am I doing wrong?
UIAlertView* postSubmitAlertView = [[UIAlertView alloc] init];
postSubmitAlertView.delegate = self;
[postSubmitAlertView addButtonWithTitle:#"Ok"];
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc]
initWithRequest:request];
[op setCompletionBlock:^(void) {
if(op.response.statusCode == 200) {
postSubmitAlertView.title = #"Submission Good";
postSubmitAlertView.message = #"GOOD";
} else {
postSubmitAlertView.title = #"Submission Failed.";
postSubmitAlertView.message = #"FAIL";
}
[postSubmitAlertView show];
}];
[op start];
The key problem is that UIKit stuff should be called on the main thread.
Note: For the most part, UIKit classes should be used only from an application’s main thread. This is particularly true for classes derived from UIResponder or that involve manipulating your application’s user interface in any way.
UIKit Framework Reference
Looking at the docs for NSOperation under setCompletionBlock:
Discussion
The exact execution context for your completion block is not guaranteed but is typically a secondary thread. Therefore, you should not use this block to do any work that requires a very specific execution context. Instead, you should shunt that work to your application’s main thread or to the specific thread that is capable of doing it.
The simplest solution to modify your code is to call the UIKit stuff on the main thread
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *URL = [NSURL URLWithString:#"http://www.google.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc]
initWithRequest:request];
[op setCompletionBlock:^(void) {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView* postSubmitAlertView = [[UIAlertView alloc] init];
postSubmitAlertView.delegate = self;
[postSubmitAlertView addButtonWithTitle:#"Ok"];
if(op.response.statusCode == 200) {
postSubmitAlertView.title = #"Submission Good";
postSubmitAlertView.message = #"GOOD";
} else {
postSubmitAlertView.title = #"Submission Failed.";
postSubmitAlertView.message = #"FAIL";
}
[postSubmitAlertView show];
});
}];
[op start];
}
The EXC_BAD_ACCESS is caused by accessing a released object. To avoid this make your call to UIAlertView kind of modal:
//Function body:
-(void)checkSaving
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Do you want to add these results to your database?"
message:#"\n\n"
delegate:self
cancelButtonTitle:#"No"
otherButtonTitles:#"Save", nil];
alert.alertViewStyle = UIAlertViewStyleDefault;
[alert show];
//this prevent the ARC to clean up :
NSRunLoop *rl = [NSRunLoop currentRunLoop];
NSDate *d;
d = (NSDate*)[d init];
while ([alert isVisible]) {
[rl runUntilDate:d];
}
}
//Your choice result:
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
// the user clicked one of the OK/Cancel buttons
if (buttonIndex == 1)//Save
{
//do something
}
if (buttonIndex == 0)//NO
{
//do something
}
}
//Register the functions in the interface declaration:
#interface yourViewController ()
-(void)checkSaving
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
//...
#end
//To call:
[self checkSaving];
I wish this will help you.
UIAlertView* postSubmitAlertView = [[UIAlertView alloc] init];
postSubmitAlertView.delegate = self;
[postSubmitAlertView addButtonWithTitle:#"Ok"];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"success: %#", operation.responseString);
postSubmitAlertView.title = #"Submission Good";
postSubmitAlertView.message = #"GOOD";
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error: %#", operation.responseString);
postSubmitAlertView.title = #"Submission Failed.";
postSubmitAlertView.message = #"FAIL";
}
];
[postSubmitAlertView show];
Hope this will solve your problem.
I want to create two connections in a single view controller class. I am using NSOperationQueue for this purpose. The two connections are created in two functions and push inside the queue .The problem is delegates are not called. Please help me out. Thanks you in advance
- (void)viewDidLoad {
[super viewDidLoad];
NSOperationQueue *queue=[[NSOperationQueue alloc] init];
NSInvocationOperation *invOperation1 = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(createConnection1) object:nil];
NSInvocationOperation *invOperation2 = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(createConnection2) object:nil];
NSArray *ops=[[NSArray alloc] initWithObjects:invOperation1,invOperation2,nil];
[queue addOperations:ops waitUntilFinished:YES];
}
-(void) createConnection1{
//create connection
NSLog(#"Create Connection 1");
url1 =[[NSMutableString alloc] initWithFormat:#"http://www.google.com/ig/api?weather=New Delhi"];
NSURLRequest *theRequest1=[NSURLRequest requestWithURL:[NSURL URLWithString:url1]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
theConnection1=[[NSURLConnection alloc] initWithRequest:theRequest1 delegate:self];
if (theConnection1) {
connectionCreated1=YES;
receivedData1 = [[NSMutableData data] retain];
NSLog(#"received data 1 %#",receivedData1);
//[theConnection1 setDelegate:self];
}
}
-(void) createConnection2{
//create connection
NSLog(#"Create Connection 2");
url2 =[[NSMutableString alloc] initWithFormat:#"http://www.google.com/ig/api?weather=Chennai"];
NSURLRequest *theRequest2=[NSURLRequest requestWithURL:[NSURL URLWithString:url2]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
theConnection2=[[NSURLConnection alloc] initWithRequest:theRequest2 delegate:self];
if (theConnection2) {
connectionCreated2=YES;
receivedData2 = [[NSMutableData data] retain];
//[theConnection2 setDelegate:self];
NSLog(#"received data 2 %#",receivedData2);
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
if (connectionCreated1==YES) {
[receivedData1 setLength:0];
}
else if (connectionCreated2==YES) {
[receivedData2 setLength:0];
}
else {
NSLog(#"did not receive response");
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
if (connectionCreated1==YES) {
[theConnection1 release];
xmlParser1 = [[NSXMLParser alloc] initWithData:receivedData1];
[xmlParser1 setDelegate:self];
[xmlParser1 parse];
}
else if(connectionCreated2==YES){
[theConnection2 release];
xmlParser2 = [[NSXMLParser alloc] initWithData:receivedData2];
[xmlParser2 setDelegate:self];
[xmlParser2 parse];
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"connection failed" message:#"" delegate:self cancelButtonTitle:#"ok" otherButtonTitles:nil];
[alert show];
[alert release];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
if (connectionCreated1==YES) {
[receivedData1 appendData:data];
}
else if(connectionCreated2==YES) {
[receivedData2 appendData:data];
}
else {
NSLog(#"data not received");
}
}
The URL you have given in the first link seems to be borken ... look at this "http://www.google.com/ig/api?weather=New Delhi".. there is space between new delhi. try this instead http://www.google.com/ig/api?weather=New+Delhi
"Informazioni.h file"
#interface Informazioni : UIViewController{
.....
ASIHTTRequest *mASIHTTPRequest;
}
#property (nonatomic, retain) ASIHTTRequest *mASIHTTPRequest;
----------------------------
#import "Informazioni.h"
#import "Globals.h"
#implementation Informazioni
#synthesize mImageViewImmagine;
....
#synthesize mASIHTTPRequest;
- (void)viewDidLoad {
[super viewDidLoad];
//start fetching based on id_prodotti
[self startFetch:mId_prodotto];
}
- (void) startFetch:(NSString *) pId_prodotto{
//activate ASIHTTPDownloadCache
NSURL *url = [NSURL URLWithString:[JSON_DESCRIZIONE stringByAppendingString:mId_prodotto]];//JSON_DATA
mASIHTTPRequest = [ASIHTTPRequest requestWithURL:url];
[mASIHTTPRequest setDelegate:self];
[mASIHTTPRequest startAsynchronous];
}
- (void)loadDataWithOperation: (NSString *) responseString{
NSLog(#"load data with operation");
NSDictionary *tempDict = [[responseString JSONValue] objectForKey:#"descrizione_prodotto"];
NSLog(#"descrizione_prodotto: %#",tempDict);
[self.mTableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
NSLog(#"reloadData called");
}
//start
- (void)requestFinished:(ASIHTTPRequest *)request{
NSLog(#"SUCCESS Http fetching");
// Operation Queue init (autorelease)
NSOperationQueue *queue = [NSOperationQueue new];
// Create our NSInvocationOperation to call loadDataWithOperation, passing in nil
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:#selector(loadDataWithOperation:)
object:[request responseString]];
// Add the operation to the queue
[queue addOperation:operation];
[operation release];
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
NSLog(#"%#",[error localizedDescription]);
/*
NSLog(#"Error: %#",[error localizedDescription]);
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"DIUNAMAISHOP"
message:[error localizedDescription]
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
*/
/*
//remove activity indicator
if (self.mActivityIndicator.mFlag == YES) {
[self.mActivityIndicator.view
performSelectorOnMainThread:#selector(removeFromSuperview)
withObject:nil waitUntilDone:YES];
}
*/
}
-(void) queueFinished:(ASIHTTPRequest *) queue{
//You could release the queue here if you wanted
NSLog(#"Queue finished");
}
// end
........
- (void)dealloc {
//safely dealllocate
[mASIHTTPRequest clearDelegatesAndCancel];
[mASIHTTPRequest release];
.....
[super dealloc];
NSLog(#"Informazioni deallocated");
}
#end
I simply pushed this view then pressing back will dealloc/release the viewcontroller..
- the problem is it crashes when i press back while it is fetching
- how can i overcome this any suggestion would do tnx
mASIHTTPRequest = [ASIHTTPRequest requestWithURL:url];
You're not retaining this request. You need to retain it to have a valid reference reference to then be able to cancel and release it. Either add a retain, or use self.mASIHTTPRequest.
My app is calling the rqst_run method below in didViewLoad method but I've an error. Debugger reports the following error:
[NSMutableURLRequest released]: message sent to deallocated instance
I don't know where this variable get released
Declared in header file (interface section):
NSMutableString *rqst_error;
NSMutableData *rqst_data;
NSMutableDictionary *listing_items;
and I defined this method in implementation:
- (void)rqst_run
{
rqst_data = [[NSMutableData data] retain];
NSMutableURLRequest *http_request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://www.feedserver.com/request/"]];
[http_request setHTTPMethod:#"POST"];
NSString *post_data = [[NSString alloc] initwithFormat:#"param1=%#¶m2=%#¶m3=%#",rqst_param1,rqst_param2,rqst_param3];
[http_request setHTTPBody:[post_data dataUsingEncoding:NSUTF8StringEncoding]];
rqst_finished = NO;
[post_data release];
NSURLConnection *http_connection = [[NSURLConnection alloc] initWithRequest:http_request];
[http_request release];
if(http_connection)
{
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
if([rqst_data length]>0)
{
NSString *rqst_data_str = [[NSString alloc] rqst_data encoding:NSUTF8StringEncoding];
SBJsonParser *json_parser = [[SBJsonParse alloc] init];
id feed = [json_parser objectWithString:rqst_data_str error:nil];
listing_items = (NSMutableDictionary *)feed;
[json_parser release];
[rqst_data_str release];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Feed" message:#"No data returned" delegate:self cancemButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Connection Problem" message:#"Connection to server failed" delegate:self cancemButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[rqst_data setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[rqst_data appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[rqst_data release];
[connection release];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[rqst_data release];
[connection release];
rqst_finished = YES;
}
Your initialization
NSMutableURLRequest *http_request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://www.feedserver.com/request/"]];
is a convenience constructor that has a built-in autorelease for the object you are initializing using the constructor. So by calling
[http_request release];
you are trying to release something that is auto-released. In other words, you are over-releasing.
You should only call release on objects that you allocate using the keywords,
"New", "Alloc", "Copy". or use "retain"
Line [http_request release]; is unnecessary as your object is autoreleased.
For creation of your NSMutableURLRequest you used method which returns aurora eased instance and you not responsible for it's release. If you use methods which require you perform -alloc, -copy, -retain than you responsible for releasing this instance.
I am using a private MBProgressHUD
Now I am using the indicator view on my add button in which I am calling my addrecord service .
UIWindow *window = [UIApplication sharedApplication].keyWindow;
HUD = [[MBProgressHUD alloc] initWithWindow:window];
// Add HUD to screen
[window addSubview:HUD];
// Regisete 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(addingToFavorites) onTarget:self withObject:nil animated:YES];
the adding to favorites method :
NSURL *url = [NSURL URLWithString:urlstring];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0];
[request setHTTPMethod:#"GET"];
//[request setTimeoutInterval:10];
//NSURLResponse *response = nil;
// NSError *error = nil;
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
[[NSURLCache sharedURLCache] setDiskCapacity:0];
NSData *data1= [NSURLConnection sendSynchronousRequest:request
returningResponse:nil error:nil];
if(data1 == nil)
{
doneFlag = NO;
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Alert"
message:#"The network is not available.\n Please check the Internet connection."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
else
{
doneFlag = YES;
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Confirmation"
message:#"Added To favorites"
delegate:nil
cancelButtonTitle:#"OKAY"
otherButtonTitles:nil];
[alert show];
alert = nil;
[alert release];
}
[request release];
This is all running fine except the instruments gives leak of the uialertview may be it is conflicting with the mbprogreshud.
So I thought to remove the alert from the calling method and put it in the caller the method like this:
the caller method now :
UIWindow *window = [UIApplication sharedApplication].keyWindow;
HUD = [[MBProgressHUD alloc] initWithWindow:window];
// Add HUD to screen
[window addSubview:HUD];
// Regisete 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(addingToFavorites) onTarget:self withObject:nil animated:YES];
//it should wait for the above line to be executing ******* then to exexute the be //below condition but how ?
if (doneFlag == NO) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Alert"
message:#"The network is not available.\n Please check the Internet connection."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
} else {
[favoritesButton setTitle:#"Remove" forState:UIControlStateNormal];
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Confirmation"
message:#"Added To favorites"
delegate:nil
cancelButtonTitle:#"OKAY"
otherButtonTitles:nil];
[alert show];
alert = nil;
[alert release];
}
the adding to favorites method :
NSURL *url = [NSURL URLWithString:urlstring];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0];
[request setHTTPMethod:#"GET"];
//[request setTimeoutInterval:10];
//NSURLResponse *response = nil;
// NSError *error = nil;
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
[[NSURLCache sharedURLCache] setDiskCapacity:0];
NSData *data1= [NSURLConnection sendSynchronousRequest:request
returningResponse:nil error:nil];
if(data1 == nil)
{
doneFlag = NO;
}
else
{
doneFlag = YES;
}
[request release];
In the launching of the progresshud thread is detaching something like this :
[NSThread detachNewThreadSelector:#selector(launchExecution) toTarget:self withObject:nil]
Now My question is that If I follow the first scenario . How can I assure the the alertview leak will not come
Or If I am following the second scenario How can I assure the if condition will be executed after completing this line executed :
[HUD showWhileExecuting:#selector(addingToFavorites) onTarget:self withObject:nil animated:YES];
Regarding the first scenario, it is in general a bad idea to do UI updates from threads other than the applications main thread. UIKit is NOT thread safe and doing threaded UI updates can cause all sorts of strange things to happen. Now, I'm not sure if this is the cause for the leak but I would avoid showing an UIAlertView in addingToFavorites. Use performSelectorOnMainThread or the second scenario described below.
Regarding the second scenario, move everything below the showWhileExecuting call to the hudWasHidden delegate method. At this point you can be sure that your code was fully executed and the doneFlag was set.
To use performSelectorOnMainThread, define a new method, put your code in it and than call performSelectorOnMainThread.
I.e.,
- (void)showAlert {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Alert" message:#"The network is not available.\n Please check the Internet connection." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
}
Call with,
[self performSelectorOnMainThread:#selector(showAlert) withObject:nil waitUntilDone:NO];
I would go with the second scenario though.
Other answers notwithstanding, you were creating the UIAlertView leak with this sequence:
[alert show];
alert = nil;
[alert release];
The last two lines should be swapped:
[alert show];
[alert release];
alert = nil;