I'm using a collection view and trying to transition from loading the data synchronously to loading it asynchronously.
I know that the following currently works (it takes a while to load, but all the cells appear correctly when it's done):
// load projectData in main thread
NSData * projectData = [NSData dataWithContentsOfURL:userUrl];
[self performSelectorOnMainThread:#selector(fetchProjects:)withObject:projectData waitUntilDone:YES];
I rewrote it to do everything asynchronously:
// load project data asynchronously
dispatch_async(bgQueue, ^{
UIView *loadingAnimation = loadingCircle;
loadingAnimation.tag = 15;
[self.collectionView addSubview:loadingAnimation];
[loadingCircle startAnimating];
NSData * projectData = [NSData dataWithContentsOfURL:userUrl];
[self performSelector:#selector(fetchProjects:) withObject:projectData];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"finished with loading projects");
UIView *viewToRemove = [self.view viewWithTag:15];
[viewToRemove removeFromSuperview];
[self.collectionView reloadData];
});
});
When I run the app after loading the data asynchronously, the view appears empty (the cells have no content), but when I scroll, some of the cells begin to appear.
Is there anything else I need to call besides reloadData to get my collection cells to appear properly?
Here is my fetchProjects:
// get JSON data of projects
- (void)fetchProjects:(NSData *)responseData {
NSError * error;
NSDictionary * json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error]; // get dictionary from json data
NSDictionary * data = [json objectForKey:#"data"]; // get data in array
NSArray * projects = [data objectForKey:#"projects"];
NSDictionary * mostRecentProject = [projects objectAtIndex:0];
mostRecentProjectID = [mostRecentProject objectForKey:#"id"];
for (NSDictionary *currentProject in projects)
{
[projectIDs addObject: [currentProject objectForKey:#"id"]];
NSString *projectTitle = [currentProject objectForKey:#"title"];
NSString *trimmedProjectTitle = [projectTitle stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
id delegate = [[UIApplication sharedApplication] delegate];
self.managedObjectContext = [delegate managedObjectContext];
Project *newProject = (Project *) [NSEntityDescription insertNewObjectForEntityForName:#"Project" inManagedObjectContext:[self managedObjectContext]];
CustomLabel *cellLabel=[[CustomLabel alloc]init];
cellLabel.text = trimmedProjectTitle;
NSLog(#"fetchprojects:%#",projectTitle);
[titles addObject:projectTitle];
CGSize maxLabelSize = CGSizeMake(screenWidth/2 - 30,100);
CustomLabel *titleLabel = [[CustomLabel alloc]init];
[titleLabel setNumberOfLines:0];
titleLabel.text = projectTitle;
CGSize expectedLabelSize = [titleLabel.text sizeWithFont:titleLabel.font constrainedToSize:maxLabelSize lineBreakMode:NSLineBreakByWordWrapping];
CGRect labelFrame = (CGRectMake(0, 0, screenWidth/2 - 30, 0));
labelFrame.origin.x = 0;
labelFrame.origin.y = screenWidth/2 - 70 - expectedLabelSize.height;
labelFrame.size.height = expectedLabelSize.height;
titleLabel.frame = labelFrame;
titleLabel.backgroundColor = [[UIColor blackColor]colorWithAlphaComponent:0.5f];
titleLabel.textColor =[UIColor whiteColor];
[titleLabel setFont: [UIFont fontWithName: #"HelveticaNeue" size:12]];
//NSLog(#"%#", titleLabel.text);
UIImageView *imagePreview = [[UIImageView alloc] initWithFrame:CGRectMake(7.5, 10, screenWidth/2 -30, screenWidth/2 -70)];
imagePreview.contentMode= UIViewContentModeScaleAspectFill;
imagePreview.clipsToBounds = YES;
[imagePreview setImage:[UIImage imageNamed:#"blank.png"]];
[imagePreview addSubview:titleLabel];
[imagePreview.subviews[0] setClipsToBounds:YES];
[projectContainers addObject: imagePreview];
}
}
You're doing a lot of UI work on a background thread which you really shouldn't do. From what I can see, the only line that really needs to be run on a background thread is this one:
NSData * projectData = [NSData dataWithContentsOfURL:userUrl];
The rest looks like it deals with setting up and displaying your UI and some CoreData stuff; all of that needs to be run on the main thread. The easiest way to do that and keep everything running in the right order would be something like this:
// NOTE: If you're sure you're already on the main thread here, you don't need the dispatch, but it's not going to hurt to leave it in.
dispatch_async(dispatch_get_main_queue(), ^{
UIView *loadingAnimation = loadingCircle;
loadingAnimation.tag = 15;
[self.collectionView addSubview:loadingAnimation];
[loadingCircle startAnimating];
});
dispatch_async(bgQueue, ^{
NSData * projectData = [NSData dataWithContentsOfURL:userUrl];
dispatch_async(dispatch_get_main_queue(), ^{
[self fetchProjects:projectData];
NSLog(#"finished with loading projects");
UIView *viewToRemove = [self.view viewWithTag:15];
[viewToRemove removeFromSuperview];
[self.collectionView reloadData];
});
});
Note: I also changed [self performSelector:#selector(fetchProjects:) withObject:projectData] to [self fetchProjects:projectData]; you don't really need to go through performSelector: there.
Related
I have the following code that render scroll view inside table view with three pages, I want the pages to be changed each 5 seconds , how can I do that ?
UITableViewCell *cell;
cell = [tableView dequeueReusableCellWithIdentifier: sliderIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:sliderIdentifier];
}
if (sliderItems != nil && sliderItems.count > 0) {
UIScrollView *scroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0,self.view.frame.size.width, 200)];
scroll.scrollEnabled = YES;
for (int i = 0; i < sliderItems.count ; i++) {
CGFloat xOrigin = i * self.view.frame.size.width;
UIImageView *awesomeView = [[UIImageView alloc] initWithFrame:CGRectMake(xOrigin, 0, self.view.frame.size.width, 200)];
ItemResponse *test = [ItemResponse new];
test = sliderItems[i];
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//this will start the image loading in bg
dispatch_async(concurrentQueue, ^{
NSString *urlStr = test.listingImage;
NSURL *imageUrl = [NSURL URLWithString:urlStr];
NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
//this will set the image when loading is finished
dispatch_async(dispatch_get_main_queue(), ^{
awesomeView.image = [UIImage imageWithData:imageData];
[scroll addSubview:awesomeView];
UILabel *iconAdLabel = [[UILabel alloc]init];
iconAdLabel.frame = CGRectMake(0 + (i * self.view.frame.size.width),130,self.view.frame.size.width,70);
iconAdLabel.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
NSString *titleStr = [NSString stringWithFormat:#" %# ", test.listingTitle];
iconAdLabel.text = titleStr;
UIColor *color = [self getUIColorObjectFromHexString:#"#000000" alpha:0.6];
iconAdLabel.backgroundColor = color;
UIColor *textcolor = [self getUIColorObjectFromHexString:#"#ffffff" alpha:1.0];
iconAdLabel.textColor = textcolor;
iconAdLabel.textAlignment = NSTextAlignmentRight;
UIFont *font=[UIFont fontWithName:#"NotoKufiArabic" size:14.0f];
iconAdLabel.font = font;
iconAdLabel.numberOfLines = 2;
[scroll addSubview:iconAdLabel];
});
});
}
scroll.contentSize = CGSizeMake(self.view.frame.size.width * sliderItems.count , 200);
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//this will start the image loading in bg
dispatch_async(concurrentQueue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
[self.view addSubview:scroll];
});
});
}
return cell;
You can use a NSTimer object
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:#selector(timerAction) userInfo:nil repeats:YES];
with action
-(void)timerAction
{
[scroll scrollRectToVisible:CGRectMake(x, y, width, height) animated:YES];
}
Also you need to invalidate the timer Object when the ViewController Disappears. So if you have multiple cells , use an NSArray to keep track of the timer objects and invalidate when no longer needed [timer invalidate]
In my iOS app, I want to show the network activity indicator in the top status bar.
I've added the following:
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
But the activity indicator never appears.
Does anyone know what might be wrong?
Here is the full code:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
// load sets
[self loadSets];
}
-(void)loadSets{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"in loadSets");
// show loading animation
UIView *loadingView = loadingIndicator;
loadingView.center = CGPointMake(screenWidth/2, screenHeight/2);
[self.view addSubview:loadingView];
[loadingIndicator startAnimating];
self.userSets = [[NSMutableArray alloc]init]; // re-initialize userSets
dispatch_async(bgQueue, ^{
NSString *userURLString = [userBaseUrl stringByAppendingFormat:#"/%#.json?auth_token=%#", username, auth_token];
NSLog(#"userURLString %#", userURLString);
NSURL *userURL = [NSURL URLWithString:userURLString];
NSData * userData = [NSData dataWithContentsOfURL:userURL];
dispatch_async(dispatch_get_main_queue(), ^{
if(userData){
[self fetchSets:userData];
// remove loading animation
[loadingView removeFromSuperview];
}else{
// error with authentication - should log out and require relogin
// [self logoutClick];
}
});
});
});
}
-(void)fetchSets:(NSData *)responseData{
NSError * error;
NSDictionary * json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
if(json){
NSArray *sets = [json objectForKey:#"sets"];
for (NSDictionary *currentSet in sets){
Set *userSet = [[Set alloc] init];
userSet.name = [currentSet objectForKey:#"name"];
userSet.videoURL = [[currentSet objectForKey:#"media"] objectForKey:#"mp4"];
userSet.gifURL = [[currentSet objectForKey:#"media"] objectForKey:#"gif"];
userSet.imgURL = [[currentSet objectForKeyedSubscript:#"media"] objectForKey:#"img"];
userSet.setID = [currentSet objectForKey:#"id"];
[self.userSets addObject: userSet];
}
NSLog(#"trying to reload table data with userSets length %d", [self.userSets count]);
[self.collectionView reloadData];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"done loading table data");
});
}
}
I want to load some "image" (In remote server) in a UIScrollView with NSOperatoinQueue. Because If I load it with normal NSURL, NSData or with NSMutableURLRequest it takes too much time to load for all the images. After that I show those images in UIButton. Here is my code:
- (void)viewDidLoad
{
[super viewDidLoad];
[self startAnimation:nil];
self.imageDownloadingQueue = [[NSOperationQueue alloc] init];
self.imageDownloadingQueue.maxConcurrentOperationCount = 4; // many servers limit how many concurrent requests they'll accept from a device, so make sure to set this accordingly
self.imageCache = [[NSCache alloc] init];
[self performSelector:#selector(loadData) withObject:nil afterDelay:0.5];
}
-(void) loadData
{
adParser = [[AdParser alloc] loadXMLByURL:getXMLURL];
adsListArray = [adParser ads];
displayArray = [[NSMutableArray alloc] init];
for (AdInfo *adInfo1 in adsListArray)
{
AdInfo *adInfo2 = [[AdInfo alloc] init];
[adInfo2 setBannerIconURL:adInfo1.bannerIconURL];
[adInfo2 setBannerIconLink:adInfo1.bannerIconLink];
[displayArray addObject:adInfo2];
}
[self loadScrollView];
[activityIndicator stopAnimating];
}
-(void) loadScrollView
{
[self.scrollView setScrollEnabled:YES];
[self.scrollView setContentSize:CGSizeMake([displayArray count] * ScrollerWidth, ScrollerHight)];
for (int i = 0; i < [displayArray count]; i++)
{
adButtonOutLet = [[UIButton alloc] initWithFrame:CGRectMake(i*320, 0, ButtonWidth, ButtonHight)];
currentAd = [displayArray objectAtIndex:i];
NSString *imageUrlString = [currentAd bannerIconURL];
UIImage *cachedImage = [self.imageCache objectForKey:imageUrlString];
if (cachedImage)
{
[adButtonOutLet setImage:cachedImage forState:UIControlStateNormal];
}
else
{
[self.imageDownloadingQueue addOperationWithBlock:^
{
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageUrlString]];
UIImage *image = nil;
image = [UIImage imageWithData:imageData];
// add the image to your cache
[self.imageCache setObject:image forKey:imageUrlString];
// finally, update the user interface in the main queue
[[NSOperationQueue mainQueue] addOperationWithBlock:^
{
[adButtonOutLet setImage:image forState:UIControlStateNormal];
}];
}];
}
adButtonOutLet.userInteractionEnabled= YES;
[adButtonOutLet setTag:i];
[adButtonOutLet addTarget:self action:#selector(goToURL:) forControlEvents:UIControlEventTouchUpInside];
[self.scrollView addSubview:adButtonOutLet];
}
}
Can anyone tell me what's wrong with the above code? There is no problem of parsing or retrieving data from Remote server. I check it by NSLog. I think the NSOperationQueue have some problem, which I can't manage properly. Thanks in advance. If you needed more information, I will attach here.
Have a nice day.
Not sure if this is your problem or your solution, its hard to tell without testing myself.
Taken from RayWenderlich
addOperationWithBlock: if you have a simple operation that does not
need to be subclassed, you can create an operation using the block
API. If you want to reference any object from outside in the block,
remember that you should pass in a weak reference. Also, if you want
to do something that is related to the UI in the block, you must do it
on the main thread:
// Create a weak reference
__weak MyViewController *weakSelf = self;
// Add an operation as a block to a queue
[myQueue addOperationWithBlock: ^ {
NSURL *aURL = [NSURL URLWithString:#"http://www.somewhere.com/image.png"];
NSError *error = nil;
NSData *data = [NSData dataWithContentsOfURL:aURL options:nil error:&error];
UIImage *image = nil;
If (data)
image = [UIImage imageWithData:data];
// Update UI on the main thread.
[[NSOperationQueue mainQueue] addOperationWithBlock: ^ {
weakSelf.imageView.image = image;
}];
}];
I am having a table view with custom cells. Each custom cell is having scroll view in which images are added in series. Images are of quite large size. Other than images, some other datas are also present in each cell. I am saving the images to db before reloading table view.The issue is as the tableview reloaddata is calling continuously and my scroll view inside the cell is not working properly. What is the efficient method for reloading table view without affecting the scroll inside.Images should also load in a proper manner.
this is how i m calling those methods:
-(void)viewWillAppear:(BOOL)animated{
[self performSelectorInBackground:#selector(getPacksdetails) withObject:nil];}
-(void) getPacksdetails
{
//NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
ForcePackRequest *request = [[ForcePackRequest alloc] init];
User *userObj = (User *)[request getActiveUser];
NSString *emailString =[NSString stringWithFormat:#"%#", userObj.Email ];
BOOL isPackList= [request getPurchasedPacksOfUser:emailString toArray:packsListArray excerciseArray:excercisesArray recommendedGearsArray:recommendedGears];
// NSMutableArray *namesArray=[[NSMutableArray alloc]init];
for(int packscounter=0;packscounter<[packsListArray count];packscounter++){
if([[[packsListArray objectAtIndex:packscounter]objectForKey:#"name"] isEqualToString: passedPackName]){
//nslog(#"passedPackName%#",passedPackName);
////nslog(#"%#",data.exName);
reservedIndexPath=nil;
reservedIndexPath= [NSIndexPath indexPathForRow:0 inSection:packscounter];
//nslog(#"%#",reservedIndexPath);;
break;
}
// reservedIndexPath=[NSIndexPath indexPathWithIndex:i];
}
if(isPackList)
[self performSelectorInBackground:#selector(loadExerthumbThread:) withObject:nil];
}
- (void) loadExerthumbThread:(id)sender{
//if (FP_DEBUG) //nslog(#"%#",excercisesArray);
for(int i=0;i<[excercisesArray count];i++){
NSMutableArray *exforAsection=[[NSMutableArray alloc]init];
// exerciseArrayForeachSection=[excercisesArray objectAtIndex:i];
exforAsection=[excercisesArray objectAtIndex:i];
for (int intConter = 0; intConter <[exforAsection count]; intConter++)
{
Exercise *data = [exforAsection objectAtIndex:intConter];
// NSString *imageName = [[data.exImage ] intValue];
int intExerId = [data.exImage intValue];
NSString *imagestr = [NSString stringWithFormat:#"hires_%d",intExerId];
FileManager *objFileManager = [[FileManager alloc] init];
NSData *imageData = nil;
if ([objFileManager isFileExistsInDocDir:imagestr])
{
imageData = [objFileManager getFileFormDocDirWithName:imagestr];
}
else
{
NSString *imageUrlString = [NSString stringWithFormat:#"http://www.forcetherex.com/force_uploads/exercise/exercise_hires/%#.png",data.exId];
NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:imageUrlString]];
if (data != nil)
{
if ([data length] > 100)
imageData = [data copy];
}
if (imageData != nil){
[objFileManager writeFileToAppDirectoryWithFileName:imagestr andFileData:imageData];
//Mark as dont back up
NSURL *fileUrl = [NSURL fileURLWithPath:imagestr];
[self addSkipBackupAttributeToItemAtURL:fileUrl];
fileUrl=nil;
data = nil;
}
}
if (imageData != nil)
data.exThumbImage = imageData;
objFileManager = nil;
}
[self reloadTableView];
}
and my cellforrow atindexpath code is:
{
NSString *CellIdentifier = [NSString stringWithFormat:#"%d_%d",indexPath.section,indexPath.row];
//static NSString *CellIdentifier = #"CustomCellFor_Dashboard";
_customCell = (CustomCellFor_Dashboard *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (_customCell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CustomCellFor_Dashboard" owner:self options:nil];
for (id currentObject in topLevelObjects){
if ([currentObject isKindOfClass:[UITableViewCell class]]){
_customCell = (CustomCellFor_Dashboard *) currentObject;
_customCell.delegate=self;
break;
}
}
}
_customCell.exNameDictArray=[[packsListArray objectAtIndex:indexPath.section]objectForKey:#"exerciseList"];
_customCell.indexPath=indexPath;
NSLog(#"%d",sng.showingPath.section);
if(indexPath.section ==sng.showingPath.section)
_customCell.exnameTable.hidden=FALSE;
sectionInt=indexPath.section;
exerciseArrayForeachSection=[[NSMutableArray alloc]init];
//[exerciseArrayForeachSection removeAllObjects];
exerciseArrayForeachSection=[excercisesArray objectAtIndex:indexPath.section];
//next btn
UIButton *accessoryView = [[UIButton alloc] initWithFrame: _customCell.nextBtn.frame];
accessoryView.tag = indexPath.section;
[accessoryView setImage:[imageasArr objectAtIndex:0]forState:UIControlStateNormal];
[accessoryView addTarget:self action:#selector(nextButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[_customCell addSubview:accessoryView];
//_customCell.accessoryView = accessoryView;
//prev btn
UIButton *prevBtn = [[UIButton alloc] initWithFrame: _customCell.prevBtn.frame];
prevBtn.tag = indexPath.section;
[prevBtn setImage:[imageasArr objectAtIndex:2]forState:UIControlStateNormal];
[prevBtn addTarget:self action:#selector(previousButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[_customCell addSubview:prevBtn];
_customCell.selectionStyle = UITableViewCellSelectionStyleNone;
[_customCell addSubview:_customCell.buttonView];
_customCell.nameLabel.text=[[packsListArray objectAtIndex:indexPath.section]objectForKey:#"name"];
_customCell.exCountLbl.text=[NSString stringWithFormat:#"%#", [[packsListArray objectAtIndex:indexPath.section]objectForKey:#"exercises"]];
_customCell.scroll.delegate = self;
// [_customCell.scroll setBackgroundColor:[UIColor blackColor]];
[_customCell.scroll setCanCancelContentTouches:NO];
_customCell.scroll.indicatorStyle = UIScrollViewIndicatorStyleWhite;
_customCell.scroll.clipsToBounds = YES;
[_customCell.scroll setContentOffset:CGPointMake(0, 20)];
if([exerciseArrayForeachSection count]>0){
_customCell. scroll.frame = CGRectMake(0,40, 320, _customCell.scroll.frame.size.height-10);
_customCell. scroll.contentSize = CGSizeMake(320*[exerciseArrayForeachSection count],_customCell .scroll.frame.size.height);
int cx = 30;
for(int i=0;i<[exerciseArrayForeachSection count];i++){
Exercise *data = [exerciseArrayForeachSection objectAtIndex:i];
UIView *detailView=[[UIView alloc]initWithFrame:_customCell.excerciseDetailsView.frame];
UILabel *titleLbl=[[UILabel alloc]initWithFrame:_customCell.exTitleLabel.frame];
titleLbl.font=[UIFont systemFontOfSize:12];
UIImageView *exerciseImg=[[UIImageView alloc]initWithFrame: _customCell.exThumbImageView.frame];
UIButton *playBtn=[[UIButton alloc]initWithFrame:_customCell.exThumbButton.frame];
playBtn.showsTouchWhenHighlighted=YES;
[playBtn setImage:[imageasArr objectAtIndex:1]forState:UIControlStateNormal];
// playBtn.frame =_customCell.exThumbButton.frame;
playBtn.tag=i;
[playBtn addTarget:self action:#selector(videoPlayActn:) forControlEvents:UIControlEventTouchUpInside];
[titleLbl setText:data.exName];
if ([data.exThumbImage length] > 0)
[exerciseImg setImage:[UIImage imageWithData:data.exThumbImage]];
[detailView addSubview:titleLbl];
[exerciseImg addSubview: playBtn];
[detailView addSubview:exerciseImg];
// _customCell.exThumbButton= playBtn;
[exerciseImg bringSubviewToFront:playBtn];
exerciseImg.userInteractionEnabled=TRUE;
[detailView bringSubviewToFront:playBtn];
//if (FP_DEBUG) //nslog(#"%f",_customCell.scroll.frame.origin.x);
detailView.frame=CGRectMake(cx, 30, 320, _customCell.scroll.contentSize.height);
//_customCell.exThumbImageView=exerciseImg;
[_customCell.scroll addSubview:detailView];
detailView=nil;
exerciseImg=nil;
titleLbl=nil;
_customCell.scroll.contentSize = CGSizeMake( cx,_customCell.scroll.contentSize.height);
cx = cx+_customCell.scroll.frame.size.width;
//if (FP_DEBUG) //nslog(#"%i",cx);
}
}
// [_customCell.scroll setContentOffset:CGPointMake(0, 20)];
//if (FP_DEBUG) //nslog(#"%f",_customCell.scroll.contentOffset.x);
[_customCell.howyoulfeelBtn addTarget:self action:#selector(buttonclicked:) forControlEvents:UIControlEventTouchUpInside];
[_customCell.expertAdviceBtn addTarget:self action:#selector(expertbuttonclicked:) forControlEvents:UIControlEventTouchUpInside];
[_customCell.recoverTrackerBtn addTarget:self action:#selector(recoverytrackerBtnclicked:) forControlEvents:UIControlEventTouchUpInside];
[_customCell.recommendedGearsBtn addTarget:self action:#selector(recommendedGearsBtnClicked:) forControlEvents:UIControlEventTouchUpInside];
////nslog(#"ewfewr************ewr");
if(indexPath.section== expandViewclickedSection&&_isexpanded==TRUE){
_customCell.scroll.frame = CGRectMake(-160, 22, self.view.frame.size.width, self.view.frame.size.height);
_customCell.shareView.hidden=FALSE;
// _customCell.nextBtn.hidden=TRUE;
accessoryView.hidden=TRUE;
//_isexpanded=TRUE;
}
else if(indexPath.section== expandViewCollapsedSection&&_isexpanded==FALSE) {
_customCell.scroll.frame = CGRectMake(-0, 22, self.view.frame.size.width, self.view.frame.size.height);
_customCell.shareView.hidden=TRUE;
// _isexpanded=FALSE;
}
if(_isExListingTablePresented==TRUE&&indexPath.section==exlistTableAddedSection){
_customCell.exListingTable.hidden=FALSE;
}
else if(_isExListingTablePresented==FALSE&&indexPath.section==_exlistTableremovedSection){
_customCell.exListingTable.hidden=TRUE;
}
return _customCell;
}
First of all shift all the code related to the DB/IO calls to another controller and make async calls to that and return the result by means to delegate methods (or anything else you deem fit). That would improve the overall performance of your code, and the scroll view would work fine.
In case that does not make things perfect, place the DB/IO calls inside a new thread, that'll ensure that your scroll view (and your app overall) performs fine.
You should update UI in the main thread.
[self performSelectorOnMainThread:reloadTableView withObject:nil waitUntilDone:NO];
You shouldn't reload table in such high Frequency, this will slow down your app if there are too much contents in the cells. Try reload table after all data updated. Of source, data updating should run in background threads.
I see you set the cell indentifier with row and section number, so you can do some tricks with it. Like comparing the image urls to decide whether setImage (this will cost lots of performance) or not.
I'm a noobie in the Objective-C language, and I have a little problem.
In fact, I have 2 TableViews, and when I go from one to the other I parse some XML from the internet. The parsing is doing well, but I wanted to add an UIActivityIndicatorView between those 2 views to tell to the user that something is loading.
So, to do that, I wanted to do the parsing in another thread and show the UIActivityIndicatorView in the main thread. So here's my code :
- (void)viewDidLoad
{
[super viewDidLoad];
UIActivityIndicatorView *activityIndicator;
activityIndicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityIndicator.frame = CGRectMake(0.0, 0.0, 40.0, 40.0);
activityIndicator.center = self.view.center;
[self.view addSubview: activityIndicator];
activityIndicator.startAnimating;
dispatch_queue_t queue = dispatch_get_global_queue(0,0);
dispatch_async(queue, ^{
NSError *error = nil;
// we will put parsed data in an a array
titles = [[NSMutableArray alloc] init];
urls = [[NSMutableArray alloc] init];
CXMLDocument *rssParser = [[CXMLDocument alloc] initWithContentsOfURL:[NSURL URLWithString:_emissionSelectionnee] options:0 error:&error];
NSArray *nodes = NULL;
nodes = [rssParser nodesForXPath:#"//rss/channel/item/title" error:nil];
for (CXMLElement *title in nodes) {
[titles addObject:[title stringValue]];
}
nodes = NULL;
nodes = [rssParser nodesForXPath:#"//rss/channel/item/enclosure" error:nil];
for (CXMLElement *url in nodes) {
[urls addObject:[[url attributeForName:#"url"] stringValue]];
}
dispatch_sync(dispatch_get_main_queue(), ^{
activityIndicator.stopAnimating;
});
}
}
So now, the UIActivityIndicator shows up, but the cells are empty.. When I do not use the dispatch_queue_t, it works well..
Does someone have an idea?
Thank you in advance!
You need to reload your Table view (in the same block where you hide the activity indicator):
[self.tableView reloadData]