I have dropped my code into a situation where I need to call UITableView data source methods written in some UIViewController class before a particular view is presented so that the cells get prepopulated and I can set a BOOL that the data in the not present viewController class is valid or not. I may explain it in more detail if required, but I wanted to know if its possible to do that. If yes, then how to do it? .. as a particular set of my code written after [tableView reloadData] is dependent on running the dataSource methods of UITableView. Please throw some light on this, if needs to be handled in a specific thread?
Following is the case where I call reloadData. Note: This is happening in another class when basicFactsViewController's viewWillAppear method has not been called yet:
- (BOOL) isComplete {
dispatch_async(dispatch_get_main_queue(), ^{
[basicFactsViewController.tableView reloadData];
});
return basicFactsViewController.isComplete && selectedVehicleId && selectedMakeId && selectedModelId && selectedYearId && selectedTrimId;
}
Now basicFactsViewController.isComplete is checked in this method:
- (BOOL) isComplete {
[self collectKeyHighlights];
return _isComplete;
}
Now the dictionary "tableCells" in the method below uses the cells population to check whether all features have been completed or not:
- (NSDictionary *) collectKeyHighlights {
NSMutableDictionary *key_highlights_update = [NSMutableDictionary new];
NSMutableDictionary *cell_highlight_update = [NSMutableDictionary new];
if(visible_key_highlights.count == 0) _isComplete = YES;
_isComplete = YES;
__block NSMutableArray *reloadCellAtIndexPathSet = [[NSMutableArray alloc] init];
[visible_key_highlights enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSDictionary *feature = (NSDictionary *)obj;
UITableViewCell *cell = [self.tableCells objectForKey:[NSIndexPath indexPathForRow:idx inSection:0]];
if(cell) {
if([cell isKindOfClass:[DRColorSelectionTableViewCell class]]) {
NSInteger selectedIndex = ((DRColorSelectionTableViewCell *)cell).selectedIndex;
NSInteger numberOfSegments = ((DRColorSelectionTableViewCell *)cell).numberOfSegments;
if(selectedIndex > -1 ) {
NSArray *dataValues = [[visible_key_highlights objectAtIndex:idx] objectForKey:#"data_values"];
NSDictionary *colorData;
BOOL reloadCellForIndexPath = NO;
if (numberOfSegments == selectedIndex) {
colorData = #{ #"normalized" : #"user_defined", #"isother" : #YES, #"hexcode":#"#FFFFFF", #"actual":((DRColorSelectionTableViewCell *)cell).otherColorTextField.text};
reloadCellForIndexPath = YES;
}
else{
colorData = [dataValues objectAtIndex:selectedIndex];
}
[key_highlights_update setObject:colorData forKey:[feature objectForKey:#"name"]];
[cell_highlight_update setObject:colorData forKey:[feature objectForKey:#"name"]];
if (![colorData isEqual:[prevSelections objectForKey:[feature objectForKey:#"name"]]]) {
[reloadCellAtIndexPathSet addObject:((DRColorSelectionTableViewCell *)cell).indexPath];
}
//if (reloadCellForIndexPath) {
//}
} else {
_isComplete = NO;
}
} else if([cell isKindOfClass:[DRInputTableViewCell class]]) {
NSString *textInput = ((DRInputTableViewCell *)cell).inputTextField.text;
if([textInput length]) {
[key_highlights_update setObject:[NSString toSnakeCase:textInput] forKey:[feature objectForKey:#"name"]];
[cell_highlight_update setObject:textInput forKey:[feature objectForKey:#"name"]];
}else {
_isComplete = NO;
}
} else if([cell isKindOfClass:[DRPickerTableViewCell class]]) {
NSString *textInput = ((DRPickerTableViewCell *)cell).inputField.text;
if([textInput length]) {
[key_highlights_update setObject:[NSString toSnakeCase:textInput] forKey:[feature objectForKey:#"name"]];
[cell_highlight_update setObject:textInput forKey:[feature objectForKey:#"name"]];
} else {
_isComplete = NO;
}
} else if([cell isKindOfClass:[DRSwitchTableViewCell class]]) {
// send this everytime for now
BOOL isSelected = ((DRSwitchTableViewCell *)cell).toggleButton.selected;
[key_highlights_update setObject:[NSNumber numberWithBool:isSelected] forKey:[feature objectForKey:#"name"]];
[cell_highlight_update setObject:[NSNumber numberWithBool:isSelected] forKey:[feature objectForKey:#"name"]];
}
}
else{
_isComplete = NO;
}
}];
prevSelections = cell_highlight_update;
if ([reloadCellAtIndexPathSet count]) {
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:reloadCellAtIndexPathSet withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
}
return key_highlights_update;
}
Now here since
[tableView reloadData]
is not calling cellForRowAtIndePath:, hence, tableCells is not getting populated, hence, I am always getting _isComplete = NO.
If I understand correctly, there is processing being done when the tableview loads (calls it's dataSource methods) and you want to trigger that early to use its results. Calling [basicFactsViewController.tableView reloadData]; early won't work if the basicFactsViewController hasn't been displayed yet. If basicFactsViewController is a UIViewController and has the default view and the tableView property is a subview of that standard view, then (if I remember correctly) the tableView property will be nil until the basicFactsViewController has been displayed. A shortcut around that is to access the viewController's view property and cause it to initialize (viewDidLoad and all that). You can do that by simply messaging the viewController: [basicFactsViewController view].
If I've been right so far I'm fairly confident that will initialize the tableView property. But I'm not sure if it will cause the table view to load its data. And even if it does work, it's definitely not the best solution to the piece of code you're trying to architect. Apple's design for UIKit has been focused on the model/view/controller pattern and it's easier to go with the flow and do the same. I imagine that you could move the processing that is in the data source methods for the tableView out into another class (or maybe even the same class), and call that method to get everything ready for both the tableView and any other checks that you have, storing the data in dictionaries and arrays in such a way that you can easily load them by index into the tableView when cellForIndex is called.
Related
What is the correct way of using NSDiffableDataSourceSnapshot and - (void)tableView:(nonnull UITableView *)tableView prefetchRowsAtIndexPaths:(nonnull NSArray<NSIndexPath *> *)indexPaths.
It seems that every time prefetch reloads table view, table view asks for more prefetching, after calling apply snapshot, creating infinite loop.
- (void)reloadViews {
//[self.tableView reloadData];
NSMutableArray *items = [NSMutableArray new];
for (TCHChannel* channel in self.channels) {
[items addObject:channel.sid];
}
if ([items count] == 0) {
return;
}
NSDiffableDataSourceSnapshot<ConversationSectionType*, NSString*> *snapshot =
[[NSDiffableDataSourceSnapshot<ConversationSectionType*, NSString*> alloc] init];
ConversationSectionType *main = [ConversationSectionType new];
main.section = kMain;
[snapshot appendSectionsWithIdentifiers:#[main]];
[snapshot appendItemsWithIdentifiers:items intoSectionWithIdentifier:main];
[self.diffDataSource applySnapshot:snapshot animatingDifferences:NO];
}
And here is prefetch method:
- (void)tableView:(nonnull UITableView *)tableView prefetchRowsAtIndexPaths:(nonnull NSArray<NSIndexPath *> *)indexPaths {
for (NSIndexPath *indexPath in indexPaths) {
TCHChannel *channel = [self channelForIndexPath:indexPath];
NSMutableSet *currentChannelIds = [NSMutableSet new];
for (ConversationListViewModelUpdateOperation *op in self.modelQueue.operations) {
[currentChannelIds addObject:[op channelId]];
}
if ([currentChannelIds containsObject:channel.sid]) {
continue;
}
NSParameterAssert(channel != nil);
ConversationListViewModelUpdateOperation *op = [[ConversationListViewModelUpdateOperation alloc] initWithChannel:channel cache:self.channelViewModelsCache];
op.completionBlock = ^{
dispatch_async(dispatch_get_main_queue(), ^(void){
[self reloadViews];
});
};
[self.modelQueue addOperation:op];
}
}
Model queue is just operation queue:
- (NSOperationQueue*)modelQueue {
if (_modelQueue == nil) {
_modelQueue = [[NSOperationQueue alloc] init];
_modelQueue.maxConcurrentOperationCount = 4;
}
return _modelQueue;
}
Is there a way to use prefetching with diffable data sources without apply asking for more indexes?
EDIT:
So calling reloadData in prefetch methods makes infinite loop.. According to https://andreygordeev.com/2017/02/20/uitableview-prefetching/
WARNING: do not call tableView.reloadData() or
tableView.reloadRows(...) from tableView(_ tableView: UITableView,
prefetchRowsAt indexPaths: [IndexPath]) method! These methods provoke
UITableView to call prefetchRowsAt... and thus lead to infinity loop.
Soo.. how has Apple intended for prefetching to be used with Diffable Data Sources? ... -.-
When I create a form with FXForms, it is very fluid, memory is ok. The problem is that the more you scroll down and up, the more memory is increasing which make the scroll very slow, very bad.
I read in a ticket and another ticket that the tableview of that FXForms don't use cells recycling.
How can I find the way to resolve that problem?
- (UITableViewCell *)cellForField:(FXFormField *)field
{
//FIXME: memory leak recycle cells
//don't recycle cells - it would make things complicated
Class cellClass = field.cellClass ?: [self cellClassForField:field];
NSString *nibName = NSStringFromClass(cellClass);
if ([nibName rangeOfString:#"."].location != NSNotFound)
{
nibName = nibName.pathExtension; //Removes Swift namespace
}
if ([field.mandatory isKindOfClass:[NSString class]])
{
if ([field.mandatory isEqualToString:#"YES"])
{
NSString *string = [field.title stringByReplacingOccurrencesOfString:#" " withString:#""];
BOOL isNotEmpty = ![string isEqualToString:#""];
if (isNotEmpty)
{
if (![[string substringToIndex:1] isEqualToString:mandatoryCharacter])
{
[field setValue: [NSString stringWithFormat:#"%#%#", mandatoryCharacter, field.title] forKey:#"title"];
}
}
}
}
if ([[NSBundle mainBundle] pathForResource:nibName ofType:#"nib"])
{
//load cell from nib
return [[[NSBundle mainBundle] loadNibNamed:nibName owner:nil options:nil] firstObject];
}
else
{
//hackity-hack-hack
UITableViewCellStyle style = UITableViewCellStyleDefault;
if ([field valueForKey:#"style"])
{
style = [[field valueForKey:#"style"] integerValue];
}
else if (FXFormCanGetValueForKey(field.form, field.key))
{
style = UITableViewCellStyleValue1;
}
//don't recycle cells - it would make things complicated
return [[cellClass alloc] initWithStyle:style reuseIdentifier:NSStringFromClass(cellClass)];
}
}
Thanks in advance.
Put your code in autoreleasepool and check
e.g:
-(UITableViewCell *)cellForField:(FXFormField *)field {#autoreleasepool {}}
News feed are not shown in table viewcontroller.BuyerSocialPage that is linked with Newsfeed Viewcontroller has BuyerSocialPage.h file
#interface BuyerSocialPage : UIViewController <UITableViewDataSource,UITableViewDelegate>
#end
#implementation BuyerSocialPage
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.tableView.delegate=self;
UINib * firstNib = [UINib nibWithNibName:#"BSPFirstCell" bundle:nil];
[self.tableView registerNib:firstNib forCellReuseIdentifier:#"BSPFirstCell"];
UINib * secondNib = [UINib nibWithNibName:#"BSPSecondCell" bundle:nil];
[self.tableView registerNib:secondNib forCellReuseIdentifier:#"BSPSecondCell"];
UINib * thirdNib = [UINib nibWithNibName:#"BSPThirdCell" bundle:nil];
[self.tableView registerNib:thirdNib forCellReuseIdentifier:#"BSPThirdCell"];
UINib * fourthNib = [UINib nibWithNibName:#"BSPFourthCell" bundle:nil];
[self.tableView registerNib:fourthNib forCellReuseIdentifier:#"BSPFourthCell"];
self.view.backgroundColor = [UIColor whiteColor];
[self getBuyerSocialPage];
if (self.revealViewController) {
[_sidebarButton addTarget:self.revealViewController action:#selector(revealToggle:) forControlEvents:UIControlEventTouchUpInside];
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
}
}
-(void)getBuyerSocialPage {
}
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
int row = (int)indexPath.row;
if (row == 0) {
return 324;
}
else if (row == 1)
{
return 152;
}
else if (row == 2)
{
return 152;
}
else
{
return 152;
}
}
#end
After login you will see home screen. From side menu bar at the top select the "news feed" and it should display the news feed.but it is not displaying newsfeeds.Api is running correctly on postman
How I can get news feed in the table view ?
Page Number is missing in your url &pageno=1.
Your url looks like this:
http://api.shoclef.com/api/NewsFeed?user_id=1164
It should be like this:
http://api.shoclef.com/api/NewsFeed?user_id=1164&pageno=1
try this in you API Manager class. Working fine for me.
NSString * url = [NSString stringWithFormat:#"%#NewsFeed?user_id=%I&pageno=1",API_BASE_URL,userID];
Update For Image
Update this code in your cellForRowAtIndexPath function in NewsFeedNew class
NSString *strUrl = [self.images objectAtIndex:indexPath.row].image;
strUrl = [strUrl stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];
[cell.image sd_setImageWithURL:[NSURL URLWithString:strUrl]];
You need to set tableview delegate and dataSource.
Also put a break point in numberOfRowsInSection method to verify that tableview is set with datasource and delegate.
You need to reload data of tableview when you get response - [self.tableView reloadData];
-(void)getBuyerSocialPage {
NSLog(#"getBuyerSocialPage");
UserDao * profileID = [[DatabaseManager sharedManager]getLoggedInUser];
ApiManager * manager = [ApiManager sharedManager];
[manager socialPageWithProfileID:profileID.userID withCompletionBlock:^(BOOL error, NSDictionary *socialPage) {
// NSMutableArray * details = [[NSMutableArray alloc]init];
for (NSDictionary * temp in socialPage ) {
[self.socialPageArray addObject:temp];
}
[self.tableView reloadData];
if (!error) {
self.profileImages=self.socialPageArray;
}
}];
}
Few things to debug here,
Your API response might be nil or having error check and log appropriate response.
If the server response is correct then get on the main thread and reload the TableView
Set the UITableViewDataSource and UITableViewDelegate to self if you haven't done in storyboard.
- (void)getBuyerSocialPage {
NSLog(#"getBuyerSocialPage");
UserDao *profileID = [[DatabaseManager sharedManager] getLoggedInUser];
ApiManager *manager = [ApiManager sharedManager];
__weak BuyerSocialPage *weakSelf = self;
[manager socialPageWithProfileID:profileID.userID withCompletionBlock:^(BOOL error, NSDictionary *socialPage) { [weak self]
if (error) {
NSLog("Error fetching data");
return;
}
for (NSDictionary *temp in socialPage ) {
[weakSelf.socialPageArray addObject:temp];
}
if ([weakSelf.socialPageArray count] > 0) {
// update UI on the main thread
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.tableView.reloadData()
}
}
}]
}
I am attempting to show a button in the selected state when based on a boolean off of JSON. Here is my code for my custom UITableViewCell:
TwitterCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"TwitterCell"];
if (cell == nil) {
cell = [[TwitterCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"TwitterCell"];
}
NSDictionary *data = tweets[indexPath.row];
id favorited = data[#"favorited"];
NSLog(#"%#",favorited);
id retweeted = data[#"retweeted"];
NSLog(#"%#",retweeted);
if ((int)favorited == 1) {
[cell.favoriteButton select];
} else {
[cell.favoriteButton deselect];
}
if ((int)retweeted == 1) {
[cell.retweetButton select];
} else {
[cell.retweetButton deselect];
}
Here is a possible point of issue in my custom TableViewCell class. Where I prepare for reuse:
- (void)prepareForReuse
{
[super prepareForReuse];
self.favoriteButton.selected = NO;
self.tweetLabel.text = nil;
self.profilePicture.image = nil;
self.nameLabel.text = nil;
self.retweetButton.selected = NO;
self.usernameLabel.text = nil;
}
There are a couple of things wrong with the code you have provided.
1 - Casting NSNumber to int
Retrieving favorited, which is presumably a number, from the dictionary will return an NSNumber which is a wrapper class for numbers. When you NSLog this it will print the result of it's description method, essentially printing out the underlying number.
When you cast an NSNumber to int you don't get the underlying number but the memory address in integer format.
See this code and some example output:
NSNumber *favorited = #(1);
NSLog(#"%#", favorited);
NSLog(#"%d", (int)favorited);
favorited = #(0);
NSLog(#"%#", favorited);
NSLog(#"%d", (int)favorited);
Outputs
2015-08-19 07:04:36.235 xctest[589:7545] 1
2015-08-19 07:04:36.236 xctest[589:7545] 18
2015-08-19 07:04:36.236 xctest[589:7545] 0
2015-08-19 07:04:50.720 xctest[589:7545] 2
To retrieve the underlying number it is necessary to use one of the appropriate *value methods such as integerValue or longValue.
2 - Calling select and deselect
Neither of these methods exist on UIButton unless you have created a custom subclass. To properly adjust the selected state of a button you need to use the selected property as you have done in the prepareForReuse method.
button.selected = YES; // or NO
Putting it all together
Taking the above information we can change part of the cell creation method as follows:
if ([favorited integerValue] == 1) {
cell.favoriteButton.selected = YES;
} else {
cell.favoriteButton.selected = NO;
}
if ([retweeted integerValue] == 1) {
cell.retweetButton.selected = YES;
} else {
cell.retweetButton.selected = NO;
}
I think the issue is with
(int)favorited == 1
Just use [favorited intvalue] things will be fine.
I'm facing problem with saving UITableViewCell's state and can't figure out how to solve it. Hope somebody can help me.
Explanation:
There is an API on server and I get data from it and then store it inside NSMutableArray. Each object of an array contains property ready which can be 1 or 0. So I've no problems with populating UITableView with this data but not every data object is ready (i.e 0) and I need to get progress of completion at server and after that to show it in each cell is need it. I've UIProgressView in dynamic prototype of UITableViewCell and set progress after getting. There is no problem if such "not ready" object is only one. But if there are many objects I can't show progress and I don't understand why.
So here is my code.
cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"readyCell";
AVMMovieCell *cell = [self.readyTable dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
if (cell == nil) {
cell = (AVMMovieCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
}
AVMFilmsStore *oneItem;
oneItem = [readyArray objectAtIndex:indexPath.row];
NSNumber *rowNsNum = [NSNumber numberWithUnsignedInt:(unsigned int)indexPath.row];
if (oneItem.ready==1){
cell.progressLabel.hidden = YES;
cell.progressLine.hidden = YES;
if ([selecedCellsArray containsObject:[NSString stringWithFormat:#"%#",rowNsNum]] )
{
if (![cell.progressLabel.text isEqualToString:#""]&& ![cell.progressLabel.text isEqualToString:#"Success"] && ![cell.progressLabel.text isEqualToString:#"Creating"]){
cell.progressLabel.hidden = NO;
cell.progressLine.hidden = NO;
} else {
cell.progressLabel.hidden = YES;
cell.progressLine.hidden = YES;
}
}
else{
if(!oneItem.isProcessing && !cell.selected){
cell.progressLabel.hidden = YES;
cell.progressLine.hidden = YES;
}
}
} else { //if processing
if (![processingCellsArray containsObject:[NSString stringWithFormat:#"%#",rowNsNum]]){
[processingCellsArray addObject:[NSString stringWithFormat:#"%#",rowNsNum]];
if (!cell.isSelected){
[cell setSelected:YES];
}
cell.progressLabel.hidden = NO;
cell.progressLine.hidden = NO;
NSArray * arrayOfThingsIWantToPassAlong =
[NSArray arrayWithObjects: cell, oneItem, indexPath, nil];
if(!isMaking){
[self performSelector:#selector(getProgress:)
withObject:arrayOfThingsIWantToPassAlong
afterDelay:0];
} else{
[self performSelector:#selector(getProgress:)
withObject:arrayOfThingsIWantToPassAlong
afterDelay:0.5];
}
isMaking = YES;
} else {
if (!cell.isSelected){
[cell setSelected:YES];
}
cell.progressLabel.hidden = NO;
cell.progressLine.hidden = NO;
NSArray * arrayOfThingsIWantToPassAlong =
[NSArray arrayWithObjects: cell, oneItem, indexPath, nil];
if(!isMaking){
[self performSelector:#selector(getProgress:)
withObject:arrayOfThingsIWantToPassAlong
afterDelay:0];
} else{
[self performSelector:#selector(getProgress:)
withObject:arrayOfThingsIWantToPassAlong
afterDelay:0.3];
}
isMaking = YES;
}
}
return cell;
}
and getProgress method:
-(void)getProgress:(NSArray*)args{
if (progManager == nil && !progStop){
__block AVMFilmsStore * oneItem = args[1];
if(!oneItem.isLocal){
__block AVMMovieCell * cell = args[0];
__block NSIndexPath *indexPath = args[2];
progManager = [AFHTTPRequestOperationManager manager];
__block NSString *token = [defaults objectForKey:#"token"];
__block NSString *header = [NSString stringWithFormat:#"Bearer %#",token];
__block NSDictionary *params = #{#"lang": NSLocalizedString(#"lang",nil),#"project":oneItem.fileId};
__block NSString *oneHundredPercent;
__block NSString *progIsText;
progManager.responseSerializer = [AFJSONResponseSerializer serializer];
[progManager.requestSerializer setValue:header forHTTPHeaderField:#"Authorization"];
if(cell.selected || isMaking) { //if I just check for "cell.selected" is always "NO"
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[progManager POST:#"http://example.com/api/project/get-progress" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
if ([[responseObject objectForKey:#"result"]isEqualToString:#"success"]){
progCreate = [responseObject objectForKey:#"progress"];
oneHundredPercent = #"100";
if ([progCreate intValue]==[oneHundredPercent intValue]){
if([processingCellsArray containsObject:[NSString stringWithFormat:#"%ld",(long)indexPath.row]]){
[processingCellsArray removeObject:[NSString stringWithFormat:#"%ld",(long)indexPath.row]];
[cell setSelected:NO];
}
[readyArray removeAllObjects];
[defaults setObject:#"false" forKey:#"isSomethingInSort"];
isMaking = NO;
[self getReadyMovies:progIsText nameLabel:oneItem.fileName];
} else{
if([progCreate intValue]>=50){
if([progCreate intValue]>=60){
self.navigationController.navigationItem.leftBarButtonItem.enabled = YES;
createMainButton.enabled = YES;
}
[[NSNotificationCenter defaultCenter] postNotificationName:#"gotFiftyNote" object:#"50"];
[cell.progressLine setProgress:[progCreate floatValue]/100 animated:YES];
} else {
[cell.progressLine setProgress:progUploadLimit];
}
progManager = nil;
progManager.responseSerializer = nil;
progManager.requestSerializer = nil;
token = nil;
header = nil;
params = nil;
progIsText = nil;
oneItem = nil;
cell = nil;
indexPath = nil;
isMaking = YES;
progCreate = nil;
oneHundredPercent = nil;
[self getProgress:args];
}
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(#"Error: %#", error.localizedDescription);
}];
}
}
}
}
Any suggestions will be helpful for me. I've a headache for two weeks with this problem.
I see your code but is kind of difficult to follow with those large methods. I wouldn't keep track of the processing cells in an array. Each cell has an object to represent, those object have a bool value of ready and a progress value, right?. So try something like this:
Make sure each of your cells have a progressView as a subview.
Your cell class should have a public method named styleForReady:(bool)isReady andProgress:(nsinteger)progress
Make the service call to see if they are done or not, for each model. Whenever that service call comes back, you just update the model objects in the array, and after they have the new progress values you do [self.tableView reloadData]. This would trigger numberOfRows (which should return arrayOfObjects.count) and cellForRowAtIndexPath:(which should dequeue the cell for that indexPath, grab the model representing that cell, something like arrayOfObjects[indexPath.row], and finally, call the cell to style itself based on that model doing [cell styleForReady:objectModel.ready andProgress:objectModel.progress])
Keep in mind that the controller should just keep track of the model objects, dequeue the cell and tell the cell to style passing the model. Don't put all the logic in the controller.