I've this piece of code that try to feed an array from a web-service. If it fails, an error message appears, with the possibility to tap on it to retry. But when I tap on it, the error message doesn't disappear, and the spinner doesn't re-appear.
-(void)Load_Commandes{
if(LIB_Error)
{
[LIB_Error removeFromSuperview];
LIB_Error = nil;
}
TABLE_Commandes.hidden = YES;
LIB_Chargement.hidden = NO;
spinner.hidden = NO;
[spinner startAnimating];
tab_Cdes = [self Init_Tableau];
spinner.hidden = YES;
LIB_Chargement.hidden = YES;
if(tab_Cdes != nil)
{
TABLE_Commandes.hidden = NO;
[TABLE_Commandes reloadData];
}
else
{
LIB_Error = [[UILabel alloc] initWithFrame:self.view.frame];
[LIB_Error setTextColor:[UIColor grayColor]];
[LIB_Error setBackgroundColor:[UIColor clearColor]];
[LIB_Error setTextAlignment:NSTextAlignmentCenter];
[LIB_Error setText:#"Erreur de chargement. \nToucher pour réessayer."];
[LIB_Error setNumberOfLines:2];
UITapGestureRecognizer* gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(Load_Commandes)];
[LIB_Error addGestureRecognizer:gesture];
LIB_Error.userInteractionEnabled = YES;
[self.view addSubview:LIB_Error];
}
}
Here is the code I use to call the web-service, in [self Init_Tableau].
NSString *str=[NSString stringWithFormat:URL_ORDERS];
NSURL *url=[NSURL URLWithString:str];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0];
NSData *returnData = [NSURLConnection sendSynchronousRequest: request returningResponse:&response error: &error];
Thanks you for your help, because I'll become crazy! ^^
UPDATE : I tried by a lot of different ways. But it seems to be impossible to do. Whatever I do, the visual changes are applied only when all treatments are done.
Here is the code of Init_Tableau.
-(NSArray*)Init_Tableau
{
NSMutableArray* a = [NSMutableArray array];
Reachability *networkReachability = [Reachability reachabilityForInternetConnection];
NetworkStatus networkStatus = [networkReachability currentReachabilityStatus];
if (networkStatus == NotReachable) {
NSLog(#"Erreur de chargement 1");
//return nil;
}
NSURLResponse* response;
NSError* error;
NSString *str=[NSString stringWithFormat:URL_ORDERS];
NSURL *url=[NSURL URLWithString:str];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0];
NSData *returnData = [NSURLConnection sendSynchronousRequest: request returningResponse:&response error: &error];
NSString *responseBody = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
if(error)
{
NSLog(#"Erreur de chargement 2");
return nil;
}
NSError *e = nil;
NSArray* resultList = [NSJSONSerialization JSONObjectWithData:returnData options:NSJSONReadingMutableContainers error:&e];
for(NSDictionary* dico in resultList){
Entete* cde = [[Entete alloc] init];
cde.ncde = [dico objectForKey:NCDE];
cde.nomf = [dico objectForKey:NOMF];
cde.noml = [dico objectForKey:NOML];
cde.prenomf = [dico objectForKey:PRENOMF];
cde.prenoml = [dico objectForKey:PRENOML];
cde.adresse1f = [dico objectForKey:ADRESSE1F];
cde.adresse1l = [dico objectForKey:ADRESSE1L];
cde.adresse2f = [dico objectForKey:ADRESSE2F];
cde.adresse2l = [dico objectForKey:ADRESSE2L];
cde.cpf = [dico objectForKey:CPF];
cde.cpl = [dico objectForKey:CPL];
cde.villef = [dico objectForKey:VILLEF];
cde.villel = [dico objectForKey:VILLEL];
cde.phonef = [dico objectForKey:PHONEF];
cde.phonel = [dico objectForKey:PHONEL];
cde.societef = [dico objectForKey:SOCIETEF];
cde.societel = [dico objectForKey:SOCIETEL];
cde.etatCde = [dico objectForKey:ETATCDE];
cde.moyenPaiement = [dico objectForKey:MOYENPAIEMENT];
cde.fdp = [dico objectForKey:FDP];
cde.mnt = [[dico objectForKey:MNTCDE] floatValue];
[a addObject:cde];
}
return [NSArray arrayWithArray:a];
}
Related
I have a function that gets called recursively to get new data from the database depending on the latest date. My problem is that this recursive call made causes memory usage to increase. I have commented out code to see what line is cause 300kb to be Allocated every time, so whats happening is that every time the NSURLConnection is hit i get memory usage to be increased by 300kb every 10 seconds.
This is the method that gets called recursively:
-(NSString*)setupPhpCall:(NSString*)requestString :(NSString*)sciptPage{
#autoreleasepool {
//NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:0];
//[NSURLCache setSharedURLCache:sharedCache];
NSHTTPURLResponse *urlresponse = nil;
NSError *error = nil;
NSString *response = #"";
NSData *myRequestData = nil;
NSMutableURLRequest *request = nil;
NSData *returnData = nil;
myRequestData = [NSData dataWithBytes: [requestString UTF8String] length: [requestString length]];
//Create your request string with parameter name as defined in PHP file
request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: [NSString stringWithFormat: #"http://www.hugt.co.uk/%#", sciptPage]]];
// set Request Type
[request setHTTPMethod: #"POST"];
// Set content-type
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"content-type"];
// Set Request Body
[request setHTTPBody: myRequestData];
// Now send a request and get Response
//NSHTTPURLResponse* urlResponse = nil;
//NSError *error = nil;
//if(tmpArray.count == 0){
returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlresponse error: &error]; //THIS LINE CAUSES THE MEMORY USAGE TO INCREASE
response = [[NSString alloc] initWithBytes:[returnData bytes] length:[returnData length] encoding:NSUTF8StringEncoding];
//}
// Log Response
urlresponse = nil;
error = nil;
myRequestData = nil;
request = nil;
returnData = nil;
//NSLog(#"%#",response);/****/
//[sharedCache removeAllCachedResponses];
if(response != nil){
return response;
}
}
return nil;
}
This is what i do with the response:
-(void)recurseForumActivity{
#autoreleasepool {
__block __weak dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
myRequestStringForum = [NSString stringWithFormat:#"lastDate=%#&threadTitle=%#&threadCountry=%#&threadCategory=%#&threadSubCategory=%#&getData=0",lastDateForumActivity,searchThreadTitle, searchThreadCountry, searchThreadCategory, searchThreadSubCategory];
responseForum = [self setupPhpCall:myRequestStringForum :#"xxx.php"];
[NSThread sleepForTimeInterval:2.0f];
dispatch_async(dispatch_get_main_queue(), ^{
if(responseForum.length > 0 && ![responseForum isEqualToString:#"[]"]){
labelNewForumThreads.text = [NSString stringWithFormat:#"%# new threads...", responseForum];
if(imageviewForumAlert == NULL){
UIImage *image = [UIImage imageNamed:#"alert.png"];
imageviewForumAlert = [UIImageView new];
[viewNav1 addSubview:imageviewForumAlert];
imageviewForumAlert.translatesAutoresizingMaskIntoConstraints = NO;
imageviewForumAlert.image = image;
NSDictionary *viewsDictionary = #{#"imageviewForumAlert":imageviewForumAlert};
NSArray *constraint_H = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-19-[imageviewForumAlert(12)]-19-|"
options:0
metrics:nil
views:viewsDictionary];
NSArray *constraint_V = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-19-[imageviewForumAlert(12)]-19-|"
options:0
metrics:nil
views:viewsDictionary];
[self.view addConstraints:constraint_H];
[self.view addConstraints:constraint_V];
}else{
imageviewForumAlert.hidden = NO;
}
/**NSDictionary *dic = [response JSONValue];
if((NSNull*)dic != [NSNull null]){
labelNewForumThreads.text = [NSString stringWithFormat:#"%d new threads...", dic.count];
}**/
}else{
imageviewForumAlert.hidden = YES;
labelNewForumThreads.text = [NSString stringWithFormat:#"%d new threads...", 0];
}
/**else{
labelNewForumThreads.text = [NSString stringWithFormat:#"%d new threads...", 0];
}**/
myRequestStringForum = #"";
responseForum = #"";
concurrentQueue = nil;
[self recurseForumActivity];
});
});
}
}
This is the code in my detail view it can delete event in when u come to detail view press the switch to add event and then press it again to delete it. However, when u come to detail view and then press back (using navigation) and then come o the same page again it cannot delete the event please help
there are more function but I delete just focus on Switch and EVENTKIT
//
// DetailScheduleViewController.m
// Register
//
// Created by junejubu on 3/10/2558 BE.
// Copyright (c) 2558 Thananont Aunsiripant. All rights reserved.
//
- (void)viewDidLoad {
[super viewDidLoad];
//NSLog(#"check show id sch ::%#",self.Show_ID);
self.Switch.on = NO;
self.lblNotification.text = #"Notification OFF";
[self getUserNotification];
[self getUserFollow];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)getUserNotification
{
NSString *urlStr2 = #"http://ptvshowthai.com/getNotification.php";
NSURL *url2 = [NSURL URLWithString:urlStr2];
self.getnoti = [ASIFormDataRequest requestWithURL:url2];
self.getnoti.requestMethod = #"POST"; //DELETE, PUT
self.getnoti.delegate = self;
self.getnoti.timeOutSeconds = 30;
[self.getnoti setPostValue: self.FK_User_ID forKey:#"sMemberID"];
[self.getnoti setValidatesSecureCertificate:NO];
[self.getnoti startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
NSLog(#"requestFinished");
if (request == self.getnoti) {
self.dictnoti = [NSJSONSerialization JSONObjectWithData:[request responseData] options:NSJSONReadingAllowFragments error:nil];
self.NOTI = [[NSMutableArray alloc] init];
for (NSDictionary *dataDic in self.dictnoti )
{
// unsigned long count2 = [self.dict2 count];
NSString *ShowID2 = [dataDic objectForKey:#"Show_ID"];
self.str2 = [dataDic objectForKey:#"Event_Store"];
// NSLog(#"check str2 :: %#",self.str2);
[self.NOTI addObject:ShowID2];
}
NSLog(#"Show who noti ::%#",self.NOTI);
// NSLog(#"check str2 :: %#",self.str2);
}
if(request ==self.getFollow){
self.dict2 = [NSJSONSerialization JSONObjectWithData:[request responseData] options:NSJSONReadingAllowFragments error:nil];
NSLog(#"Dict getFollow :: %#",self.dict2);
//unsigned long count2 = [self.dict2 count];
//NSLog(#"show count ::%lu",count2);
_Show = [[NSMutableArray alloc] init];
// NSDictionary *dict;
for (NSDictionary *dataDic in self.dict2 )
{
// unsigned long count2 = [self.dict2 count];
NSString *ShowID = [dataDic objectForKey:#"Show_ID"];
[self.Show addObject:ShowID];
}
if ([self.Show containsObject: self.Show_ID]) {
_lblFollow.text = #"Following";
_lblFollow.textColor = [UIColor greenColor];
_i = #"0";
NSLog(#"check i green :: %#",_i);
self.Switch.hidden = NO;
NSLog(#"check self.noti : %#",self.NOTI);
if ([self.NOTI containsObject: self.Show_ID]){
self.Switch.on = YES;
}
self.lblNotification.hidden = NO;
[self.Switch addTarget:self action:#selector(Onoff) forControlEvents:UIControlEventValueChanged];
}
else{
_lblFollow.text = #"Follow";
_lblFollow.textColor = [UIColor redColor];
_i = #"1";
NSLog(#"check i red :: %#",_i);
self.Switch.hidden = YES;
self.Switch.on = NO;
self.lblNotification.hidden = YES;
[self.Switch addTarget:self action:#selector(Onoff) forControlEvents:UIControlEventValueChanged];
}
}
}
-(void)addevent{
_eventStore = [[EKEventStore alloc] init];
if ([_eventStore respondsToSelector:#selector(requestAccessToEntityType:completion:)])
{
[_eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (granted){
addEventgranted = 1;
EKEvent *event = [EKEvent eventWithEventStore:_eventStore];
[event setTitle:self.showNameTitle];
[event setStartDate: self.today];
[event setEndDate:[[NSDate alloc]initWithTimeInterval:self.duration sinceDate:event.startDate]];
NSTimeInterval alarmOffset = -300;
EKAlarm *alarm = [EKAlarm alarmWithRelativeOffset:alarmOffset];
[event addAlarm:alarm];
[event setCalendar:[_eventStore defaultCalendarForNewEvents]];
NSError *err;
[_eventStore saveEvent:event span:EKSpanThisEvent error:&err];
self.str = [[NSString alloc] initWithFormat:#"%#", event.eventIdentifier];
NSLog(#"check self.str :: %#",self.str);
NSString *url = #"http://ptvshowthai.com/insertNotification.php";
NSURL *urls = [NSURL URLWithString:url];
self.formData = [ASIFormDataRequest requestWithURL:urls];
self.formData.requestMethod = #"POST";
self.formData.delegate = self;
self.formData.timeOutSeconds = 30;
[self.formData setPostValue: self.FK_User_ID forKey:#"sMemberID"];
[self.formData setPostValue: self.Show_ID forKey:#"showID"];
NSLog(#"check str::: %#",self.str);
[self.formData setPostValue: self.str forKey:#"event"];
[self.formData setValidatesSecureCertificate:NO];
[self.formData startAsynchronous];
_lblFollow.text = #"Following";
_lblFollow.textColor = [UIColor greenColor];
NSLog(#"Follow");
[self getUserNotification];
}
}];
}
}
-(void)alert
{
if (addEventgranted == 1) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Success" message:#"Event Successfully added" delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
}
}
-(void)Onoff
{
if (self.Switch.on) {
[self addevent];
[self performSelector:#selector(alert) withObject:nil afterDelay:0.3];
self.lblNotification.text =#"Notification On";
}
else
{
NSLog(#"check str22::%#",self.str2);
EKEvent* event2 = [_eventStore eventWithIdentifier:self.str2];
if (event2 != nil) {
NSError* error = nil;
[_eventStore removeEvent:event2 span:EKSpanThisEvent error:&error];
}
self.lblNotification.text =#"Notification OFF";
NSString *url = #"http://ptvshowthai.com/deleteNotification.php";
NSURL *urls = [NSURL URLWithString:url];
self.formData = [ASIFormDataRequest requestWithURL:urls];
self.formData.requestMethod = #"POST";
self.formData.delegate = self;
self.formData.timeOutSeconds = 30;
[self.formData setPostValue: self.FK_User_ID forKey:#"sMemberID"];
[self.formData setPostValue: self.Show_ID forKey:#"showID"];
[self.formData setValidatesSecureCertificate:NO];
[self.formData startAsynchronous];
_lblFollow.text = #"Following";
_lblFollow.textColor = [UIColor greenColor];
NSLog(#"Follow");
[self getUserNotification];
}
}
Add below line of code at switch off condition also
Its better to add below line at ViewDidLoad instead of addEvent method..
_eventStore = [[EKEventStore alloc] init];
Hope it fixes..!
I'm trying to progressHUD in the Asynchronous request, but it does not seem to work probably. What i want is it to show the progessHUD until the Asynchronous request is done. at the moment it is not showing in the beginning, but after 3 sec it is showing for 0.1 second or something and after that the Asynchronous request is completed. What am i doing wrong, to achieve that the progessHUD is shown when the viewisloaded to the Asynchronous request is done?
As you can see below i've added progressHUD show and dismiss in the viewDidLoad and in the firstRequest method.
Viewdidload:
- (void)viewDidLoad
{
[super viewDidLoad];
[ProgressHUD show:#"Please Wait..."];
buttonLogin = [[UIBarButtonItem alloc] initWithTitle:#"Login" style:UIBarButtonItemStyleBordered target:self action:#selector(actionLogin)];
buttonLogout = [[UIBarButtonItem alloc] initWithTitle:#"Logout" style:UIBarButtonItemStyleBordered target:self action:#selector(actionLogout)];
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;
self.theTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, screenWidth, screenHeight-160) style:UITableViewStylePlain];
self.theTableView.dataSource = self;
self.theTableView.delegate = self;
[self.view addSubview:self.theTableView];
self.navigationController.navigationBar.tintColor = [UIColor whiteColor];
self.navigationController.navigationBar.titleTextAttributes = #{NSForegroundColorAttributeName : [UIColor whiteColor]};
fixtures = [[NSMutableArray alloc] init];
sections = [[NSMutableArray alloc] init];
sortedArray = [[NSMutableArray alloc] init];
[self firstRequest];
self.bannerView = [[GADBannerView alloc] initWithFrame:CGRectMake(0.0, self.view.frame.size.height-100, GAD_SIZE_320x50.width, GAD_SIZE_320x50.height)];
self.theTableView.backgroundColor = [UIColor colorWithRed:243/255.0f green:243/255.0f blue:247/255.0f alpha:1.0f];
self.view.backgroundColor = [UIColor colorWithRed:243/255.0f green:243/255.0f blue:247/255.0f alpha:1.0f];
[self checkAuthStatus];
[ProgressHUD dismiss];
}
the request:
-(void)firstRequest
{
NSURL *url = [NSURL URLWithString:#"URL"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response,
NSData *data, NSError *connectionError)
{
[ProgressHUD show:#"Please Wait..."];
jsonResult = [NSJSONSerialization JSONObjectWithData:data
options:0
error:NULL];
int subObjects = ((NSArray *)jsonResult[#"match"]).count;
for (int i = 0; i <= subObjects-1; i++) {
NSString *date = [NSString stringWithFormat:#"%# %#",[[[jsonResult valueForKey:#"match"] valueForKey:#"playdate"] objectAtIndex:i], [[[jsonResult valueForKey:#"match"] valueForKey:#"time"] objectAtIndex:i]];
NSString *identifier = [[NSLocale currentLocale] localeIdentifier];
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setTimeZone: [NSTimeZone timeZoneWithName:#"US/Arizona"]];
[df setLocale:[NSLocale localeWithLocaleIdentifier:identifier]];
[df setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSDate *myDate = [df dateFromString:[NSString stringWithFormat:#"%#", date]];
NSArray *items = [[NSString stringWithFormat:#"%#", myDate] componentsSeparatedByString:#" "];
NSString *home = [[[jsonResult valueForKey:#"match"] valueForKey:#"hometeam"] objectAtIndex:i];
NSString *away = [[[jsonResult valueForKey:#"match"] valueForKey:#"awayteam"] objectAtIndex:i];
NSString *league = [[[jsonResult valueForKey:#"match"] valueForKey:#"league"] objectAtIndex:i];
[fixtures addObject:
[[NSMutableDictionary alloc] initWithObjectsAndKeys:
items[0], #"date",
items[1], #"time",
home, #"home",
away, #"away",
league, #"league",
nil]];
[sections addObject:
[[NSMutableDictionary alloc] initWithObjectsAndKeys:
items[0], #"date",
nil]];
}
NSArray *copy = [sections copy];
NSInteger index = [copy count] - 1;
for (id object in [copy reverseObjectEnumerator]) {
if ([sections indexOfObject: object inRange: NSMakeRange(0, index)] != NSNotFound) {
[sections removeObjectAtIndex: index];
}
index--;
}
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"self" ascending:NO];
NSArray *descriptors = [NSArray arrayWithObject: descriptor];
NSArray* reverseTheArray = [[sections valueForKey:#"date"] sortedArrayUsingDescriptors:descriptors];
reversedArray = [[reverseTheArray reverseObjectEnumerator] allObjects];
[self.theTableView reloadData];
[ProgressHUD dismiss];
}
];
}
You should show ProgressHUD before sending a request.
Your code should look like this.
-(void)firstRequest
{
[ProgressHUD show:#"Please Wait..."];
NSURL *url = [NSURL URLWithString:#"URL"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response,
NSData *data, NSError *connectionError)
{
// request processing stuff
...
[ProgressHUD dismiss];
}
];
Explanation. When you call sendAsynchronousRequest... the request itself performed somewhere in background thread. The network operation may take some time, 1-5-10 seconds. Your completionHandler will be executed once the request completes (after the delay). So you should show ProgressHUD before sending a request. Then start the request. And dismiss ProgressHUD at the end of your completionHandler block after everything is processed.
Update
There is one more issue I noticed in your code. viewDidLoad method is called only once on view controller when its view is loaded but at this point the view itself is not presented on screen. So you will not actually see ProgressHUD called from viewDidLoad. You may be interested in viewWillAppear and viewDidAppear methods if you want to handle when view is presented on screen.
I assume your view controller is designed to show data retrieved from web api. I believe the best option is to call your api in viewWillAppear.
- (void)viewDidLoad
{
[super viewDidLoad];
buttonLogin = [[UIBarButtonItem alloc] initWithTitle:#"Login" style:UIBarButtonItemStyleBordered target:self action:#selector(actionLogin)];
buttonLogout = [[UIBarButtonItem alloc] initWithTitle:#"Logout" style:UIBarButtonItemStyleBordered target:self action:#selector(actionLogout)];
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;
self.theTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, screenWidth, screenHeight-160) style:UITableViewStylePlain];
self.theTableView.dataSource = self;
self.theTableView.delegate = self;
[self.view addSubview:self.theTableView];
self.navigationController.navigationBar.tintColor = [UIColor whiteColor];
self.navigationController.navigationBar.titleTextAttributes = #{NSForegroundColorAttributeName : [UIColor whiteColor]};
fixtures = [[NSMutableArray alloc] init];
sections = [[NSMutableArray alloc] init];
sortedArray = [[NSMutableArray alloc] init];
self.bannerView = [[GADBannerView alloc] initWithFrame:CGRectMake(0.0, self.view.frame.size.height-100, GAD_SIZE_320x50.width, GAD_SIZE_320x50.height)];
self.theTableView.backgroundColor = [UIColor colorWithRed:243/255.0f green:243/255.0f blue:247/255.0f alpha:1.0f];
self.view.backgroundColor = [UIColor colorWithRed:243/255.0f green:243/255.0f blue:247/255.0f alpha:1.0f];
[self checkAuthStatus];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self firstRequest];
}
-(void)firstRequest
{
[ProgressHUD show:#"Please Wait..."];
NSURL *url = [NSURL URLWithString:#"URL"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response,
NSData *data, NSError *connectionError)
{
// request processing stuff
...
[ProgressHUD dismiss];
}
];
}
I'm trying to create a simple rss reader. The code works okay, except the UI hangs when the feeds are being updated. I thought I cobbled together the code to get the feed and parse it on a background queue while updating the UI on the mainQueue, but the table hangs pretty badly. Code below:
-(void)refreshFeed2
{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
for (NSString *feed in _feeds) {
// iterate over all feeds
NSLog(#"feed=%#", feed);
NSURL *url = [NSURL URLWithString:feed];
// Create url connection and fire request
NSURLConnection *conn = [[NSURLConnection alloc] init];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
(void)[conn initWithRequest:request delegate:self];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if ([data length] == 0 && error == nil) {
// handle empty response
} else if (error != nil) {
// handle error
NSLog(#"Error %#", [error localizedDescription]);
} else if ([httpResponse statusCode] == 200) {
// data present and no errors
[queue addOperationWithBlock:^{
// parse feed on queue
RXMLElement *rss = [RXMLElement elementFromXMLData:data];
RXMLElement *rssChild = [rss child:#"channel"];
RXMLElement* title = [rssChild child:#"title"];
NSArray* items = [[rss child:#"channel"] children:#"item"];
NSMutableArray* result=[NSMutableArray array];
for (RXMLElement *e in items) {
// iterate over the articles
RSSArticle* article = [[RSSArticle alloc] init];
article.sourceTitle = [title text];
article.articleTitle = [[e child:#"title"] text];
article.articleDescription = [[e child:#"description"] text];
article.articleUrl = [NSURL URLWithString: [[e child:#"link"] text]];
NSString *articleDateString = [[e child:#"pubDate"] text];
article.articleDate = [NSDate dateFromInternetDateTimeString:articleDateString formatHint:DateFormatHintRFC822];
if (article.articleUrl != NULL) {
[result addObject:article];
}
}
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// update table on mainQueue
for (RSSArticle *article in result) {
// iterate over articles
int insertIdx = [_allEntries indexForInsertingObject:article sortedUsingBlock:^(id a, id b) {
RSSArticle *entry1 = (RSSArticle *) a;
RSSArticle *entry2 = (RSSArticle *) b;
return [entry1.articleDate compare:entry2.articleDate];
}];
[_allEntries insertObject:article atIndex:insertIdx];
[self.LeftTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:insertIdx inSection:0]]
withRowAnimation:UITableViewRowAnimationFade];
}
}];
}];
}
}];
// Stop refresh control
[refreshControl endRefreshing];
}
}
Code that calls refreshFeed2:
- (void)viewDidLoad {
[super viewDidLoad];
self.allEntries = [NSMutableArray array];
self.feeds = [NSArray arrayWithObjects:
#"http://feeds.washingtonpost.com/rss/politics",
#"http://rss.cnn.com/rss/cnn_allpolitics.rss",
#"http://www.npr.org/rss/rss.php?id=1012",
#"http://www.slatedigital.com/support/feeds/rss_kb.php?s=fd5aa35e773dc3177b85a2126583f002",
nil];
}
//add refresh control to the table view
refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self
action:#selector(refreshInvoked:forState:)
forControlEvents:UIControlEventValueChanged];
NSString* fetchMessage = [NSString stringWithFormat:#"Fetching Articles"];
refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:fetchMessage
attributes:#{NSFontAttributeName:[UIFont fontWithName:#"Helvetica" size:11.0]}];
[self.LeftTableView addSubview: refreshControl];
[self refreshInvoked:self forState:UIControlStateNormal];
}
-(void) refreshInvoked:(id)sender forState:(UIControlState)state {
NSOperationQueue *refreshQueue = [[NSOperationQueue alloc] init];
[refreshQueue addOperationWithBlock:^{
[self refreshFeed2];
}];
}
Any help?
Thanks!
Can you try this? replace
[self refreshInvoked:self forState:UIControlStateNormal];
by
[self performSelectorOnBackground:#selector(refreshFeed2) withObject:nil];
and replace the same instead of
-(void) refreshInvoked:(id)sender forState:(UIControlState)state {
[self performSelectorOnBackground:#selector(refreshFeed2) withObject:nil ];
}
May be my question looks strange, but... (hope somebody help me)
There are two methods in which I load some data from FTP. Sometimes application hung on these methods.
Checking internet connection.
If internet avail:
#interface Download : NSObject {
NSOperationQueue *operationQueue;
}
...
if (!operationQueue) {
operationQueue = [NSOperationQueue new];
}
NSInvocationOperation *operation1;
operation1 = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(loadIngredientsFromJSON) object:nil];
[operationQueue addOperation:operation1];
NSInvocationOperation *operation2;
operation2 = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(loadRecipesFromJSON) object:nil];
[operation2 addDependency:operation1];
[operationQueue addOperation:operation2];
[operationQueue addObserver:self forKeyPath:#"operations" options:0 context:NULL];
Methods loadIngredientsFromJSON & loadRecipesFromJSON
-(void) loadIngredientsFromJSON
{
NSInteger countInBase = [self dataCountInEntity:#"Ingredients"];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"ftp://...Ingredients.json"]];
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSError *error = nil;
if (!responseData) {
return;
}
NSDictionary *ingredientsDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];
if (!ingredientsDictionary) {
return;
}
//NSLog(#"%#", [ingredientsDictionary description]);
NSArray *keys = [ingredientsDictionary allKeys];
if (!countInBase && [ingredientsDictionary count]>0) {
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
for (int i=0; i<[ingredientsDictionary count]; i++) {
id aKey = [keys objectAtIndex:i];
NSArray *ingrData = [ingredientsDictionary objectForKey:[NSString stringWithFormat:#"%#", aKey]];
NSArray *tmpArray = [NSArray arrayWithObjects:aKey, [ingrData objectAtIndex:0], [ingrData objectAtIndex:1], nil];
Ingredients *ingredient = [NSEntityDescription insertNewObjectForEntityForName:#"Ingredients" inManagedObjectContext:appDelegate.managedObjectContext];
ingredient.code = [NSNumber numberWithInteger:[[tmpArray objectAtIndex:0] integerValue]];
ingredient.name = [tmpArray objectAtIndex:1];
ingredient.units = [tmpArray objectAtIndex:2];
ingredient.type = [NSNumber numberWithInt:1];
[appDelegate.managedObjectContext save:nil];
}
}
}
...
- (void) loadRecipesFromJSON
{
NSInteger missedCount = 0;
NSInteger recipeCode = 0;
NSString *recipesPath = #"ftp://...";
do {
recipeCode ++;
NSString *recipeFileName = [NSString stringWithFormat:#"recipes/%05d.json", recipeCode];
NSString *recipeFileFullPath = [recipesPath stringByAppendingString:recipeFileName];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:recipeFileFullPath]];
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSError *error = nil;
if (!responseData) {
missedCount ++;
continue;
}
NSDictionary *recipeDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];
if (!recipeDictionary) {
missedCount ++;
continue;
}
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSInteger recipeCount = [self isDataExistInEntity:#"Recipes" withCode:[[recipeDictionary objectForKey:#"recipeCode"] integerValue]];
if (recipeCount == 0) {
Recipes *recipe = [NSEntityDescription insertNewObjectForEntityForName:#"Recipes" inManagedObjectContext:appDelegate.managedObjectContext];
recipe.code = [recipeDictionary objectForKey:#"recipeCode"];
recipe.dateUpdated = [recipeDictionary objectForKey:#"dateEdited"];
recipe.inCategory = [recipeDictionary objectForKey:#"inCategory"];
recipe.name = [recipeDictionary objectForKey:#"recipe"];
recipe.difficulty = [recipeDictionary objectForKey:#"difficulty"];
recipe.personCount = [recipeDictionary objectForKey:#"personCount"];
recipe.prepHour = [recipeDictionary objectForKey:#"prepHour"];
recipe.prepMin = [recipeDictionary objectForKey:#"prepMin"];
int seconds = ([recipe.prepMin intValue]*60)+([recipe.prepHour intValue] * 60 * 60);
recipe.prepTime = [NSNumber numberWithInt: seconds];
recipe.isPaid = [recipeDictionary objectForKey:#"isPaid"];
recipe.comment = [recipeDictionary objectForKey:#"comments"];
NSDictionary *ingredients = [recipeDictionary objectForKey:#"ingredients"];
NSArray *keys = [ingredients allKeys];
if ([keys count] > 0) {
for (int i=0; i<[keys count]; i++) {
Join *join = [NSEntityDescription insertNewObjectForEntityForName:#"Join" inManagedObjectContext:appDelegate.managedObjectContext];
join.recipeCode = [recipeDictionary objectForKey:#"recipeCode"];
id aKey = [keys objectAtIndex:i];
join.ingredientCode = [NSNumber numberWithInteger:[aKey integerValue]];
NSString *str = [ingredients objectForKey:aKey];
double num = [str doubleValue];
join.count = [NSNumber numberWithDouble:num];
join.inCart = [NSNumber numberWithInt:0];
}
}
NSDictionary *prepStages = [recipeDictionary objectForKey:#"prepStage"];
keys = [prepStages allKeys];
if ([keys count] > 0) {
for (int i=0; i<[keys count]; i++) {
PrepStages *prepStage = [NSEntityDescription insertNewObjectForEntityForName:#"PrepStages" inManagedObjectContext:appDelegate.managedObjectContext];
prepStage.recipeCode = [recipeDictionary objectForKey:#"recipeCode"];
id aKey = [keys objectAtIndex:i];
prepStage.order = [NSNumber numberWithInteger:[aKey integerValue]];
prepStage.descriptions = [prepStages objectForKey:aKey];
//загрузка картинки
NSString *recipeImageName = [NSString stringWithFormat:#"recipeImages/%05d-%#.jpg", recipeCode, [NSNumber numberWithInteger:[aKey integerValue]]];
NSString *recipeImageFullPath = [recipesPath stringByAppendingString:recipeImageName];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:recipeImageFullPath]];
if (request) {
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
if (responseData) {
UIImage *image = [UIImage imageWithData:responseData];
prepStage.image = image;
}
}
}
}
[appDelegate.managedObjectContext save:nil];
}
else {
missedCount ++;
continue;
}
} while (missedCount < 10);
}
Sometimes in one of these two methods application hung and control freeze.
Can anybody give me some advice in which line there may be the bug.
I confused...
EDITED
I noticed interesting thing:
Download process starts when app run. It downloads Recipes from server and inserts them to CoreData. If I tap to see recipe list I use appDelegate.managedObjectContext to fetch data. Download also uses appDelegate.managedObjectContext when it want to insert data.
Can this contain problem?