question on displaying UIProgressView in each table cell - iphone

I'm trying to upload a few files to a server. The files are listed on the UItableview. My question is:
What should i do to display UIProgressView in each table cell and show the progress of each file being uploaded.
My current code is able to show the UIProgressView in each cell but when i try to upload, the progress bar did not move. The program is suppose to upload 1 file at a time which after the first file is completed, the second will start to upload. In response, when the first file is done, the progress bar of the first file will stop and the progress bar for the secong file will start to move. Hope this is clear. I really need some help on this and i can't find it on the web.Thanks in advance. Thanks

You will have to maintain the progress value of each cell in an array.
I guess you must be setting the progress value of UIProgressView object at cellForRowAtIndexPath method, so you need to call [self.tableView reloadData] whenever you get callback from you network code which is uploading file to server with current upload size...

Possible solution (could be optimized): (Sorry for the formatting, could not get it working)
Create UIProgressView for each cell in your tableView
Create a field in your view controller, where you will store number of bytes already uploaded (bytesAlreadyUploaded) - you should repeatidly receive such info from your uploader.
Create a field where you will store number of bytes to be uploaded for the current upload (bytesToUpload)
Create a field where you will assign pointer to the progress view currently used (progressViewCurrentlyUsed)
Create a method in which you will refresh your progress:
(void) refreshProgress {
progressViewCurrentlyUsed.progress =
bytesAlreadyUploaded /
(CGFloat)bytesToUpload;
}
Create a NSTimer, which will call this refreshProgress method several times a second:
refreshTimer = [NSTimer
timerWithTimeInterval:0.1 target:self
selector:#selector(refreshProgress)
userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop]
addTimer:refreshTimer
forMode:NSDefaultRunLoopMode];
When you change the file being uploaded, change progressViewCurrentlyUsed, bytesToUpload and zero bytesAlreadyUploaded

Related

Use UIProgressView for image editing

In my app I apply filters for the image. I want to add UIProgressView as it takes about couple of seconds to complete the editing. How to add a UIProgressView for such method and also update how many percent it is completed? I have gone through many examples for UIProgressView but they are for Http request and loading network data. How to implement that for custom method ?
I guess you need to use Operation Queue for this.
[NSThread detachNewThreadSelector:#selector(showProgressView:) toTarget:self withObject:nil];
This has worked for me I hope it works for you too.. Have a happy Coding.!!
If you have control over how much of the editing is completed, like any delegate events you can update the progress just like network calls or others. Even if you don't have such events, you might be having some inner methods, which can give you a delta of the total progress happened.
Then you can have a method which takes in this delta, add it to existing progress.
- (void)updateProgress:(CGFloat)delta
{
[self.progressView setProgress:self.progressView.progress+delta];
self.progressLabel.text = [NSString stringWithFormat:#"Completed : %.0f",self.progressView.progress*100];
}
It's difficult to answer this without knowing what data you have available to you, but essentially, you need to have a method that gets called at a consistent periodic time interval until the image filter gets applied. A trick for doing this would be if you could come up with a time estimate for a filter and then just use an NSTimer to fire a method until that time is complete. Although if you could figure out an exact time for it to filter, that would obviously be preferable.
From there you need to set the progress of the progress view to that time over the amount of time total like so...
self.progressView.progress = (float) progress
Keep in mind though that the progress view is a percent, so you will need to store two values to compare (divide over each other) 1) the total amount of time 2) the total amount of time passed. You can just do this though by setting up a float progress in your user #interface.

Core data edit function

I already have a tableView with data in it. IF you tap a cell/row it pushes to an edit type of view. Is there anyway to edit core data's data other than: By edit, i mean i already have data inserted into my context. I have loaded my data into my view, the user can change the existing data, and re save it.
.h
//Below is the entity/entity's class name 'Amm'
Amm *amm;
.m
-(IBAction)save
{
[self.amm setValue:self.nameField.text forKey:#"name"];
[self.amm setValue:self.nicknameField.text forKey:#"nickname"];
[self.navigationController popViewControllerAnimated:YES];
NSError *error;
if (![self.managedObjectContext save:&error]) {
//Handle Error
}
}
I want this code to work, however the design pattern of my app isnt allowing this code to work for me as it does in other parts of my app. Thank you very much for any and all help!
I assume from what you've said you have:
A table view listing your managed objects
A view where you can edit the values of a managed object
A save button bound to the save method
What's the actual issue? I'm assuming when you tap save that:
The values in self.nameField.text isn't setting self.amm.name
The values in self.nicknameField.text isn't setting self.amm.nickname
Is that right? If so perhaps try the following code to set the managed object values:
self.amm.name = self.nameField.text
self.amm.nickname = self.nicknameField.text
If that's not the issue and you are actually setting the managed object values properly, is it that you just need to refresh the table-view? Perhaps use some NSLog commands to log every step of the applications progress.

Why isn't my update function for my UISlider working to set current playback time in MPMusicPlayerController?

Setup
I'm currently developing a music app and I'm having problems with the progress bar slider.
self.musicPlayer is the [MPMusicPlayerController applicationMusicPlayer]
self.currentlyPlayingTotalDuration is an NSNumber
self.currentlyPlayingTimeSlider is a UISlider
Overview
The below code is executed when a new song is picked in the MPMusicPlayerController. In this method (not all of which is shown), I set my music player to play the picked song (working) and play it (working). Then I set the total duration of the song to the maximum value of the slider (working)
self.currentlyPlayingTotalDuration = [[NSNumber alloc] initWithFloat:(int)[NSValue valueWithPointer:[self.musicPlayer.nowPlayingItem valueForKey:MPMediaItemPropertyPlaybackDuration]]];
[self.currentlyPlayingTimeSlider setMaximumValue:self.currentlyPlayingTotalDuration.floatValue];
I've logged the values to see if the values are setting correctly (they are)
NSLog(#"Number:%#", [NSNumber numberWithFloat:(int)[NSValue valueWithPointer:[self.musicPlayer.nowPlayingItem valueForKey:MPMediaItemPropertyPlaybackDuration]]]);
NSLog(#"Max:%f", self.currentlyPlayingTimeSlider.maximumValue);
Log output is below, looking as it should
2011-08-24 13:38:25.004 App [1241:707] Number:1107392
2011-08-24 13:38:25.009 App [1241:707] Max:1400544.000000
And then I set my currentlyPlayingTimeSlider value to 0 to start (working)
self.currentlyPlayingTimeSlider.value = 0.0;
Next, I set my updateSliderTime method to call once per second to move the progress bar farther by one second (working)
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateSliderTime:) userInfo:nil repeats:YES];
Problems
The full method code is below for the updateSliderTime method, which is not working, even though it is being called every second
- (void)updateSliderTime:(NSTimer *)timer {
[self.currentlyPlayingTimeSlider setValue:[[NSNumber numberWithDouble:self.musicPlayer.currentPlaybackTime] floatValue]];
}
Also, the method I call for a valueChanged event that I've setup in Interface Builder is below. It also is not working
- (IBAction)sliderChanged:(id)sender {
[self.musicPlayer setCurrentPlaybackTime:[[NSNumber numberWithFloat:self.currentlyPlayingTimeSlider.value] doubleValue]];
}
Can anyone help me figure out what I'm doing wrong? It has to be something in these last two methods, as the first one calls fine. I do no other customization/messing with the slider anywhere else.
Did you check your IBAction is being called (perhaps with NSLog)? If not, make sure you set the delegate of the Slider.
Otherwise, check my answer to this question which is very similar.
Figured it out. Everything was actually working how it should except setting the maximum value for the slider. I converted it oddly. Instead of:
self.currentlyPlayingTotalDuration = [[NSNumber alloc] initWithFloat:(int)[NSValue valueWithPointer:[self.musicPlayer.nowPlayingItem valueForKey:MPMediaItemPropertyPlaybackDuration]]];
I should be using:
self.currentlyPlayingTotalDuration = [self.musicPlayer.nowPlayingItem valueForKey:MPMediaItemPropertyPlaybackDuration];
The value is already a number. Thanks to Mundi for motivating me to log the value. When I did, I realized it was already a float. Silly me :)

why does "numberOrRowsInSection" get called mid-way through "viewDidLoad"?

BACKGROUND:
Within my viewDidLoad I am loading test calendar data (via EventKit) to the iPhone. I am noting that when the table view loads the first time it does not see this data.
When I look at the sequence of log messages I see that it goes something like this:
Logging here:
[AppointmentListController viewDidLoad] Starting
[AppointmentListController populateTestData] Populating the test data now
[AppointmentListController tableView:numberOfRowsInSection:] Number of rows = 0
[AppointmentListController viewDidLoad] Loading the existing calendar events
[AppointmentListController viewDidLoad] Ending
QUESTION(S)
Why does "numberOrRowsInSection" get called mid-way through "viewDidLoad"? I ask this as this is what I am seeing (is this what should happen?).
If this is normal that you can't be sure viewDidLoad will complete before numberOrRowsInSection, then this would imply you need a "[self.tableView reloadData]" at the end of your "viewDidLoad" method to make sure it does update?
The tableView:numberOfRowsInSection: method is likely called because you configured something on your table view (maybed you've added it to its superview) and it therefor needed to know its metrics. It does not magically trigger by itself out of the blue. Either make sure to prepare your data before you configure the UI elements or call reloadData near the end, but I'd find the former to be "cleaner".
This is perfectly normal....
Call [self.tableView reloadData]
; at the end of viewdidload

When are a methods GUI operations actually carried out?

I am working on a web-services data processing app and I am trying to make the app run as quickly as possible. When a certain 3 finger pan gesture is performed, I call a method that sends updated information off to the server to get a new batch of images to update the existing ones with.
So lets say there are 15 images in an array, I filter through them with a 2 finger gesture, and then if I want to change something about them, I can do the 3 finger gesture, and I get that same set back, just tweaked a bit (contrast/brightness, etc.).
Is what I want though is to be able to update the imageView that is displaying the images after the first image has been retrieved, so as to give the user a feel for what the rest in the series are going to look like. But no matter what I try, and no matter how many different threads I try and implement, I can't get the imageView to update before the entire download is complete. Once the batch download is done (which is handled on a separate thread) the imageView updates with the new images and everything is great.
The first step in the process is this:
if(UIGestureRecognizerStateEnded == [recognize state]){
[self preDownload:windowCounter Level:levelCounter ForPane:tagNumber];// Where this method is what gets the first image, and tries to set it to the imageView
[self downloadAllImagesWithWL:windowCounter Level:levelCounter ForPane:tagNumber]; //And this method goes and gets all the rest of the images
}
This is my preDownload method:
-(void)preDownload:(int)window Level:(int)level ForPane:(int) pane{
int guidIndex = [[globalGuids objectAtIndex:pane] intValue];
UIImage *img = [DATA_CONNECTION getImageWithSeriesGUID:[guids objectAtIndex:guidIndex] ImageID:counter Window:window Level:level];
if(pane==0){
NSLog(#"0");
[imageView3 setImage:img];
}else if(pane==1){
NSLog(#"1");
[imageView31 setImage:img];
}else if(pane==2){
NSLog(#"2");
[imageView32 setImage:img];
}else if(pane==3){
NSLog(#"3");
[imageView33 setImage:img];
}
}
So by separating this out into two different methods (there are no threads being implemented at this point, these methods are being called before all that) I was thinking that after the preDownload method completed, that the imageView would update, and then control would continue on down into the downloadAllImagesWithWL method, but that doesn't appear to be the case.
Am I missing something simple here? What can I do to update my GUI elements before that second method is through running?
You are right. However the viewn won't refresh until your code reaches runloop. You can do 2 things:
Make your downloadAllImagesWithWL method async, so it will return after you called it, your main thread reaches runloop, gui updates, and the download method will tell your logic through a callback when its done.
OR
A simplier hackier (and bad) solution would be to run runloop for some time before you call your download method. Something like this: [[NSRunloop currentRunLoop] runUnitlDate: [Date dateWithTimeIntervalSinceNow: 0.1]]; It will run runloop for 0.1 second.
When the image is set, the image view will mark itself as needing display. The actual display won't occur until the beginning of the next run loop. In OS X, you can use -display to draw the view immediately, but I don't think Apple created a public method to do this on iOS. However, if the next method simply creates the background thread, then it will return quickly and the display update will probably occur before the thread finishes.