Hell everyone :)
My experience with the UITablewView Controller in iOS is unfortunately quite limited. What I need in my application is a UI table view which contains one custom cell for each active upload currently being uploaded to a webserver (videos, audio, etc).
Each of these uploads run asynchrounously in the background, and should all be able to update things such as UILabels in their respective cells saying something about the update progress in percentage, etc.
Now I have found a solution which works. The problem is I do not know if it is actually secure or not. Based on my own conclusion I don't really think that it is. What I do is simply to retrieve a reference of the UIViews from a cell which is getting created, and then store those references in the upload objects, so they can change label text and so on themselves.
My Own Solution
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CustomCellIdentifier = @"CustomCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CustomCellIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"UploadCellView" owner:self options:nil];
if ([nib count] > 0)
{
cell = customCell;
}
else
{
NSLog(@"Failed to load CustomCell nib file!");
}
}
NSUInteger row = [indexPath row];
UploadActivity *tempActivity = [[[ApplicationActivities getSharedActivities] getActiveUploads] objectAtIndex:row];
UILabel *cellTitleLabel = (UILabel*)[cell viewWithTag:titleTag];
cellTitleLabel.text = tempActivity.title;
UIProgressView *progressbar = (UIProgressView*)[cell viewWithTag:progressBarTag];
[progressbar setProgress:(tempActivity.percentageDone / 100) animated:YES];
UILabel *cellStatusLabel = (UILabel*)[cell viewWithTag:percentageTag];
[cellStatusLabel setText:[NSString stringWithFormat:@"Uploader - %.f%% (%.01fMB ud af %.01fMB)", tempActivity.percentageDone, tempActivity.totalMBUploaded, tempActivity.totalMBToUpload]];
tempActivity.referencingProgressBar = progressbar;
tempActivity.referencingStatusTextLabel = cellStatusLabel;
return cell;
}
As you can see, this is where I think I'm doing something which isn't quite good enough: tempActivity.referencingProgressBar = progressbar; tempActivity.referencingStatusTextLabel = cellStatusLabel;
The upload activities get a reference to the controls stored in this cell, and can then update them themselves. The problem is that I do not know whether this is safe or not. What if the cell they are refering to gets re-used or deleted from memory, and so on?
Is there another way in which you can simply update the underlying model (my upload activites) and then force the UI table view to redraw the changed cells? Could you eventually subclass the UITableViewCell and let them continously check up against an upload and then make them upload themselves?
EDIT
This is how the upload activity objects calls their referencing UI controls:
- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten
totalBytesWritten:(NSInteger)totalBytesWritten
totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite
{
if (referencingProgressBar != nil)
{
[referencingProgressBar setProgress:(percentageDone / 100) animated:YES];
}
if (referencingStatusTextLabel != nil)
{
[referencingStatusTextLabel setText:[NSString stringWithFormat:@"Uploader - %.f%% (%.01fMB ud af %.01fMB)", percentageDone, totalMBUploaded, totalMBToUpload]];
}
}
My only concern is that, since these objects run asynchrounously, what if at some given point the UI table view decides to remove or re-use the cells which these upload objects are pointing to? It doesn't seem very secure at all.
There are two possibilities, assuming you have a background process that is uploading:
The second is easier to implement, just put the listeners start/stop in viewdidappear/viewdiddissappear. Then in your upload you can track progress and emit a notification with attached userinfo that gives an integer value to progress. The table has a function that handles this notification being received and redraws the cells. Here is how to add data to the userinfo part of an NSNotification.
If you wanted to be fancier you could have an upload id and map this to a cell index, and only redraw that particular cell. Here's a question and answers that explain how to do this.
Disgusting Pseudocode Since I don't have access to my IOS dev env right now
upload function:
uploadedStuff{
upload_id = ... // unique i, maps to row in table somehow
byteswritten = ...
bytestotal = ....
userinfo = new dict
userinfo["rowid] = upload_id
userinfo["progress"] = (int)byteswritten/bytestotal
sendNotification("uploadprogress",userinfo)
}
tableview.m:
viewdidappear{
listenForNotification name:"uploadprogress" handledBy:HandleUploadProgress
}
viewdiddisappear{
stoplisteningForNotification name:"uploadprogess"
}
HandleUploadProgess:NSNotification notification {
userinfo = [notification userinfo]
rowId = [userinfo getkey:"rowId"]
progress = [userinfo getkey:"rowId"]
// update row per the link above
}