Hi My problem is that i am getting a response from a web service and when i parse it and add to table and reload the table view it is not refreshing . Although if i call the [table reload] in keyboard is shown it gets updated there. Could someone tell me if im missing anything
This is what i am trying to do
- (void) longPoll {
//create an autorelease pool for the thread
#autoreleasepool {
NSLog(#"polling");
VSAppDelegate *var = (VSAppDelegate*)[[UIApplication sharedApplication] delegate];
//compose the request
NSError* error = nil;
NSHTTPURLResponse* response = nil;
//send the request (will block until a response comes back)
NSData* responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"polling response is %d",response.statusCode);
//pass the response on to the handler (can also check for errors here, if you want)
[self performSelectorOnMainThread:#selector(dataReceived:) withObject:responseData waitUntilDone:YES];
}
[self performSelectorInBackground:#selector(longPoll) withObject: nil];
}
- (void) startPoll {
[self performSelectorInBackground:#selector(longPoll) withObject: nil];
}
- (void) dataReceived: (NSData*) theData
{
//process the response here
NSError *error = nil;
NSLog(#"polling data is %#",[[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding]);
NSLog(#"polling data is %#",[[theData base64EncodedString]base64DecodedString]);
NSDictionary *notifDic= [NSJSONSerialization JSONObjectWithData:theData options:kNilOptions error:&error];
//VSViewControllerSplit *split = [[VSViewControllerSplit alloc]init];
[self RecieveFunction:notifDic];
}
try it
dispatch_async(dispatch_get_main_queue(), ^{
[tablrView reloaddata];
});
The dataReceived method doesn't appear to be calling reloadData. I'll assume that RecieveFunction method does, though, but you should confirm that. It's hard to say without seeing RecieveFunction.
The more fundamental issue would appear to be that dataReceived method is creating a new instance of VSViewControllerSplit, calling its RecieveFunction method, and then letting this new VSViewControllerSplit instance fall out of scope (and if using ARC, get deallocated unless you pushed to it, presented it, etc.). You presumably don't want to create a new VSViewControllerSplit every time longPoll calls dataReceived, but rather just reference the existing instance.
Related
Since 2 yrs I have been trying different ways to find the solution of app crash while click back button.
My application scenario:
In a tableview contoller I have to load list of users, On view did load I call getData(Asyncronous download) API method to load data. At the time of data download, If user press back button my application gets crash due to null value objects. That says all of my variable memory deallocated.
To overcome this problem, I used some loading indicator which lock UIScreen untill data download.
Questions:
Is there any alternatives to prevent crash, UIScreen Lock
Other applications use Activity Indicator in Menu bar without UIScreen Lock. How they are doing?
Need help to recover this issue
Here is my sample code to download data :
Below code doesnt crash app. But it download data even I cancel operations on dealloc
viewDidLoad:
ShowNetworkActivityIndicator();
_processQueue = [[NSOperationQueue alloc] init];
_processQueue.maxConcurrentOperationCount = 4;
_processQueue.name = #"Events Processing";
[self loadData];
loadData:
-(void)loadData
{
[_processQueue addOperationWithBlock: ^ {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[[NSURL alloc] initWithString:#"https://restcountries.eu/rest/v1/all"]];
NSURLResponse *response;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
NSString *data=[[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
NSDictionary *search = [NSJSONSerialization JSONObjectWithData:[data dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:nil];
[[NSOperationQueue mainQueue] addOperationWithBlock: ^ {
_countryListArray=[search mutableCopy];
[self.tableViewSample reloadData];
HideNetworkActivityIndicator();
}];
}];
}
I tried cancelAllOperations in dealloc:
[_processQueue setSuspended:YES];
[_processQueue cancelAllOperations];
Can you try inserting the reload data is dispatch_async(dispatch_get_main(),void (^){}); callback , main thread , I think the reload happening in the background thread is crashing the app.
[[NSOperationQueue mainQueue] addOperationWithBlock: ^ { _countryListArray=[search mutableCopy]; dispatch_async(dispatch_get_main_queue(), ^{
[self.tableViewSample reloadData];
HideNetworkActivityIndicator();
});}];
I think I'm missing something pretty fundamental about programming in objective-c.
The callstack is as follows:
MyViewController calls a block to setup a request to my server.
[_myClient storePhoto:photo withCompletion: ^(KNPhotoInfo *retPhoto, NSError *error) { // do stuff }];
This call sets up a request to my server to save the photo and then tries to handle the response:
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if(error) //handle it
#try
{
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
KNPhotoInfo *photoInfo = [[KNPhotoInfo alloc] initWithPhotoDictionary:json[#"data"]];
[_storage setObject:[photoInfo toDictionary] forKey:PhotoInfoKey];
completionHandler(photoInfo, nil);
}
#catch (NSException *exception)
{
NSLog(#"Error parsing user info: %#", exception);
}
}];
However if I inspect the photoInfo variable before its init function is called I can see some data (not just garbage) in it. If I step into the init function, when something is assigned I can see the self object flash but then it just says "0 objects" again. After the call to the init funciton has returned, everything seems fine, I can see my object with all it's properties initialized with json["data"], but as soon as I step photoInfo says "0 objects" again.
Can anyone help me out here? I think this has something to do with "self" of the calling class vs self of where the objected is initialized, but I'm confused. :s
EDIT: To add a little more context. The init function looks something like this:
- (instancetype) initWithPhotoDictionary:(NSDictionary *)dict{
self = [super init];
self.url = dict[#"photo"][#"url"];
self.challenge = dict[#"photo"][#"challenge"];
self.user = dict[#"photo"][#"user"];
self.pubDate = dict[#"photo"][#"pub_date"];
return self;
}
However when debugging inside of this call, self has no children (even though it obviously does) and just says "0 objects". What's frustrating about this is when the call to
[_storage setObject:[photoInfo toDictionary] forKey:PhotoInfoKey];
happens I'm getting complaints about null values. However if I "print description" of photoInfo I can see all of my fields, filled out correctly.
use this methode
- (KNPhotoInfo) initWithPhotoDictionary:(NSDictionary *)dict
{
KNPhotoInfo *photoInfo = [[KNPhotoInfo alloc] init
photoinfo.url = dict[#"photo"][#"url"];
photoinfo.challenge = dict[#"photo"][#"challenge"];
photoinfo.user = dict[#"photo"][#"user"];
photoinfo.pubDate = dict[#"photo"][#"pub_date"];
return photoInfo;
}
I am learning How to parse JSON and load it in tableview while my internet is working the data is get parsed and loaded in table correctly but when i turn off my internet and refresh my table view my UI get stuck on same screen with previous JSON data and crashes after some time
following is how i implemented it..
on my table view controller i define this method which is getting called on refresh button click.
- (IBAction) reloadJasonData:(id)sender
{
NSMutableArray * jsonArray= [DownloadJsonData getJsonArray];
if(! jsonArray)
{
UIAlertView * errorAlert = [[UIAlertView alloc]initWithTitle:#"Error!!" message:#" Please Check the Internet connection" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[errorAlert show];
}
else
{
NSSortDescriptor * sortDescripter = [[NSSortDescriptor alloc]initWithKey:#"location" ascending:YES];
NSArray * discriptorArray = #[sortDescripter];
self.sortedJsonArray = [jsonArray sortedArrayUsingDescriptors:discriptorArray];
self.arrayOfLinks = [self.sortedJsonArray valueForKey:#"link"];
self.arrayOfLocations = [self.sortedJsonArray valueForKey:#"location"];
self.arrayOfDates = [self.sortedJsonArray valueForKey:#"date_time"];
NSLog(#"Count of cities in fetch data: %d",[self.sortedJsonArray count]);
[self.tableView reloadData];
}
}
in other class i have define class method to download JSON data
+(NSMutableArray *) getJsonArray
{
NSError * error;
NSData * data = [NSData dataWithContentsOfURL:httpURL];
NSMutableArray * json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
return json;
}
the error message shows only when my internet connection is not active and i click on refresh button, but once the data is displayed into table and i shout down my internet and click on refresh button again my UI get stuck..
I hope i have explained my problem in well manner so can any body help me to figure it out where did i messed it up. Thanks in advance.
I think you are accessing your data from internet using main thread that's why your UI get stuck. You should access any remote data using secondary thread.
Write this code inside your getJsonArray class
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:httpURL];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
if (!error && data!=nil)
//call a delegate to send the data to your page from where it was called
else
//show alert that an error has occurred during downloading data from net.
}];
Then use delegate to tell the main page that the data has been downloaded and then there on delegate method reload your tableView in main thread.
I have a lot of classes which are sending requests and finally it all comes to SplitViewController. In the SplitUIviewclass I have to long poll and write the data in a table view. The long polling is done in the background thread, so I have declared a variable in app delegate, but when it comes to that it is nil. And the problem is whenever I try to access the NSMutablearray through the appdelegate, its coming as nil and the array is being released. My code for long polling is
- (void) longPoll {
#autoreleasePool
{
//compose the request
NSError* error = nil;
NSURLResponse* response = nil;
NSURL* requestUrl = [NSURL URLWithString:#"http://www.example.com/pollUrl"];
NSURLRequest* request = [NSURLRequest requestWithURL:requestUrl];
//send the request (will block until a response comes back)
NSData* responseData = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response error:&error];
//pass the response on to the handler (can also check for errors here, if you want)
[self performSelectorOnMainThread:#selector(dataReceived:)
withObject:responseData waitUntilDone:YES];
}
//send the next poll request
[self performSelectorInBackground:#selector(longPoll) withObject: nil];
}
- (void) startPoll {
[self performSelectorInBackground:#selector(longPoll) withObject: nil];
}
- (void) dataReceived: (NSData*) theData {
//i write data received here to app delegate table
}
If I call any other method in my SplitView class from data received, I'm losing control, also I cannot print my app delegate values in data received or the variables being released, I cannot call reload table or any other method from here.
Cant you set your properties in your ViewControllers as strong/retain like so
property (strong,retain) NSMutableArray *myData;
BTW, I learned a moment ago that it is bad practise to use your AppDelegate as a storage place for global containers. The ApplicationDelegate is a place for application delegate methods and for the initial setup of the foundation of your app; such as setting up the navigationController.
So consider storing your data in the appropriate place, perhaps core data or something else.
I get this warning in Xcode
warning: Attempting to create USE_BLOCK_IN_FRAME variable with block
that isn't in the frame.
Xcode redirect me to my NSStream
_naturStream = [[NSInputStream alloc] initWithData:natur];
It is random when it does this error, and my application crashes when it is triggered. Anyone tried similar problem ?
thanks
EDIT
in the appDelegate.h
#property (nonatomic, strong) NSInputStream *naturStream;
In the appDelegate.m:
NSData *natur = [NSData dataWithContentsOfURL:[NSURL URLWithString:_locString]];
_naturStream = [[NSInputStream alloc] initWithData:natur];
[_naturStream open];
if (_naturStream) {
NSError *parseError = nil;
id jsonObject = [NSJSONSerialization JSONObjectWithStream:_naturStream options:NSJSONReadingAllowFragments error:&parseError];
if ([jsonObject respondsToSelector:#selector(objectForKey:)]) {
for (NSDictionary *natur in [jsonObject objectForKey:#"results"]) {
_poi = [[POI alloc]init];
[_poi setTitle:[natur objectForKey:#"title"]];
[_poi setLat:[[natur objectForKey:#"lat"]floatValue]];
[_poi setLon:[[natur objectForKey:#"lng"]floatValue]];
[_poi setDistance:[natur objectForKey:#"distance"]];
[_poi setWebUrl:[natur objectForKey:#"webpage"]];
[_naturArray addObject:_poi];
}
}
}
else {
NSLog(#"Failed to open stream.");
}
[_naturStream close];
}
I realized that i forgot [_naturStream close] i don't know if it has solved the problem or not ?
EDIT
Another thing,.... I use a Thread for fetching the JSON data:
dispatch_queue_t jsonParsingQueue = dispatch_queue_create("jsonParsingQueue", NULL);
// execute a task on that queue asynchronously
dispatch_async(jsonParsingQueue, ^{
[self parseJSON];
dispatch_async(dispatch_get_main_queue(), ^{
[_kortvisning updateAnno];
[visListe updateList];
});
});
// release the dispatch queue
dispatch_release(jsonParsingQueue);
Sounds like you're using ARC - if _naturStream is an instance variable for an objective C class, you might need to pull it out and add a __block reference so that ARC knows the scope correctly - but I'm guessing because I don't see how the block is used with the NSInputStream (if you post that part we might know). A good bit is here: http://nachbaur.com/blog/using-gcd-and-blocks-effectively
-- edit --
Ok, now that you posted the rest, I bet it has to do with the _kortvisning and visListe variables. I think you want to pull those out right after you create your queue something like
__block KortVisning *localKortVisning = _kortvisning;
__block NSMutableArray *localVisListe = visListe;
Then access those directly from your final completion handler you're sending back to the main queue.