Is there any way I can convert the value of a [NSData bytes] to a float so that I can add it to a progress bar?
Thanks,
Kevin
In a nutshell: [data length]
Here is the snippet of how the download bar I use works.
// Can get called numerous times during download process
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Accumulate incoming data into mutable data object
[fileData appendData:data];
byteCount += [data length];
float progress = byteCount/(mapToDownload.fileSize);
[self performSelectorOnMainThread:#selector(updateProgress:) withObject:[NSNumber numberWithFloat:progress] waitUntilDone:NO];
}
Let me know if you need more information.
[Added Oct 26 to address your other question:]
I have not worked with NSStream. My example is from an asynchronous NSURLConnection example. Therefore, let's ignore my previous code example.
You mentioned that you have [NSData bytes]. [NSData length] should return you how much data you have. Assuming you know the size to be downloaded then:
float progressPercentage = [yourNSData length]/knownFileSize;
should give you the percentage needed to update the progress bar. You could then set your progress bar:
[yourProgressBar setProgress:progressPercentage];
Related
i need to download large pdf from web and i created a progress bar controller.
But, how i set max progress value it i don't know the pdf size before downloading?
Is there a way to get file size and use it to increment progress bar?
I'm using
myPDFremoteUrl = "http://www.xasdaxxssxx.pdf";
- (float) getFileSize {
NSFileManager *man = [[NSFileManager alloc] init];
NSDictionary *attrs = [man attributesOfItemAtPath: myPDFremoteUrl error: NULL];
UInt32 result = [attrs fileSize];
return (float)result;
}
but i don't able to check remote size in this way...
any idea?
Thanks
I would use ASIHTTPRequest for your data retrieval. It has progress monitoring built in.
If you really want to stick with what you've got, you can look at the HTTP header. It has a property called "Content-Length" that will help you out.
Good luck.
ASIHTTPRequest has a downloadProgressDelegate that can handle this for you- its very easy to use.
Solved.
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
dimensione = (float)[response expectedContentLength];
NSLog(#"content-length: %f bytes", dimensione);
}
I forget didReceiveResponse!
good.
I've been using NSURLConnection to do a HTTP post to establish the connection. I've also implemented the didReceiveData delegate to process incoming bytes as they become available.
As incoming data comes in via didReceiveData, I add the NSData to a data buffer and try parsing the bytesteam if enough data has come in to complete a message segment. I'm having a hard time managing the data buffer (NSMutableData object) to remove bytes that have been parsed to structs. Was curious if there's an easier way. My didReceiveData delegate is below.
It works, but I don't think I'm managing memory correctly after I copy the message segment (currMsg) out of the responseData buffer and call processMsg. I get double free errors when running under the Simulator -- the program doesn't crash.
NSMutableData/NSData provide methods for appending bytes to the end but I didn't see any methods for removing bytes from the beginning (bytes representing whats already been parsed. I would appreciate some advice on how to best remove the parsed bytes from the responseData buffer. I come from a mostly C background so I'm not sure if there are better ways of manipulating the NSData bytes pointer. I'd like to avoid copying if possible -- just want to process a portion of the responseData buffer and leave the rest in responseData for next time enough bytes are in it for parsing.
Thanks
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSData *tmpBuffer = nil;
NSInteger currMsgSize = 10;
[responseData appendData:data];
NSInteger rspDataLen = [responseData length];
while(rspDataLen >= 10) {
currMsg = [[NSData alloc] initWithBytesNoCopy:(void *)[responseData bytes] length:currMsgSize];
[self processMsg:currMsg];
[currMsg release];
[responseData getBytes:tmpBuffer range:NSMakeRange(currMsgSize, rspDataLen - currMsgSize)];
[responseData release];
responseData = [[NSMutableData alloc] initWithBytesNoCopy:(void *)tmpBuffer length:rspDataLen - currMsgSize];
rspDataLen = rspDataLen - currMsgSize;
}
}
Where do you allocate the first responseData?
What is [self processMsg:currMsg] doing with the data? If it is expecting the data to be around after -processMsg: returns, and it isn't explicitly making a copy, then you are in trouble.
Infact, unless you have finished with the received data before didReceiveData: returns, you need to make a copy of it somewhere, which isn't visible in the code shown.
You need to allocate the storage for tempBuffer, not pass in an uninitialised pointer;
You should look probably for a pre-rolled implementation of a simple ring buffer. There are plenty around.
I am developing an app in which I have a table. In the table cell I have an imageview ( the images are displayed via url ) and a textview/webview. I start threads for each row to get the images in the
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
method ( if image is not already got ) and set the text of textview/webview from an array.
The problem arises when the images are being received and I pop the view, the application crashes giving the following message:
bool _WebTryThreadLock(bool), 0x1a0670: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
Now the situation becomes more weird if I don't release the textview/webview that I added to the cell, then every thing works fine.
Edit: the crash does not happens when I replace textview/webview with a label
Hoping I am clear in my question. If any thing is confusing please comment. I need to resolve this.
Thanks,
Nikhil
That's a huge mistake to use threads. Try to avoid using threads if you have other solutions !
In your case, just use an asynchronous NSURLConnection which will take care of downloading your image while not slowing your app ;)
Here is part of the code :
- (void) startDownload {
self.activeDownload = [NSMutableData data];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:
[NSURLRequest requestWithURL:
[NSURL URLWithString:#"blablabla"]] delegate:self];
self.imageConnection = conn;
[conn release];
}
#pragma mark -
#pragma mark Download support (NSURLConnectionDelegate)
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.activeDownload appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"ERROR DOWNLOADING");
// Clear the activeDownload property to allow later attempts
self.activeDownload = nil;
// Release the connection now that it's finished
self.imageConnection = nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"FINISH DOWNLOAD");
UIImage *image = [[UIImage alloc] initWithData:self.activeDownload];
self.activeDownload = nil;
self.imageConnection = nil;
//do whatever you want with your image
[image release];
}
I am saving arrays of doubles in an NSData* object that is persisted as a binary property in a Core Data (SQLite) data model. I am doing this to store sampled data for graphing in an iPhone app. Sometimes when there are more than 300 doubles in the binary object not all the doubles are getting saved to disk. When I quit and relaunch my app there may be as few as 25 data points that have persisted or as many as 300.
Using NSSQLitePragmasOption with synchronous = FULL and this may be making a difference. It is hard to tell, as bug is intermittent.
Given the warnings about performance problems as a result of using synchronous = FULL, I am seeking advice and pointers.
Thanks.
[[Edit: here is code.]]
The (as yet unrealized) intent of -addToCache: is to add each new datum to the cache but only flush (fault?) Data object periodically.
From Data.m
#dynamic dataSet; // NSData * attribute of Data entity
- (void) addDatum:(double_t)datum
{
DLog(#"-[Data addDatum:%f]", datum);
[self addToCache:datum];
}
- (void) addToCache:(double_t)datum
{
if (cache == nil)
{
cache = [NSMutableData dataWithData:[self dataSet]];
[cache retain];
}
[cache appendBytes:&datum length:sizeof(double_t)];
DLog(#"-[Data addToCache:%f] ... [cache length] = %d; cache = %p", datum, [cache length], cache);
[self flushCache];
}
- (void) wrapup
{
DLog(#"-[Data wrapup]");
[self flushCache];
[cache release];
cache = nil;
DLog(#"[self isFault] = %#", [self isFault] ? #"YES" : #"NO"); // [self isFault] is always NO.
}
- (void) flushCache
{
DLog(#"flushing cache to store");
[self setDataSet:cache];
DLog(#"-[Data flushCache:] [[self dataSet] length] = %d", [[self dataSet] length]);
}
- (double*) bytes
{
return (double*)[[self dataSet] bytes];
}
- (NSInteger) count
{
return [[self dataSet] length]/sizeof(double);
}
- (void) dump
{
ALog(#"Dump Data");
NSInteger numDataPoints = [self count];
double *data = (double*)[self bytes];
ALog(#"numDataPoints = %d", numDataPoints);
for (int i = 0; i
I was trying to get behavior as if my Core Data entity could have an NSMutableData attribute. To do this my NSManagedObject (called Data) had an NSData attribute and an NSMutableData ivar. My app takes sample data from a sensor and appends each data point to the data set - this is why I needed this design.
On each new data point was appended to the NSMutableData and then the NSData attribute was set to the NSMutableData.
I suspect that because the NSData pointer wasn't changing (though its content was), that Core Data did not appreciate the amount of change. Calling -hasChanged on the NSManagedObjectContext showed that there had been changes, and calling -updatedObjects even listed the Data object as having changed. But the actual data that was being written seems to have been truncated (sometimes).
To work around this I changed things slightly. New data points are still appended to NSMutableData but NSData attribute is only set when sampling is completed. This means that there is a chance that a crash might result in truncated data - but for the most part this work around seems to have solved the problem.
Caveat emptor: the bug was always intermittent, so it is possible that is still there - but just harder to manifest.
I'm trying to code up an async image downloader. I use NSURLConnection to get the data into an NSMutableData and use that data once it is complete to initialize a UIImage.
I checked the bytes and it downloads the entire image correctly (right number of bytes at least), however; when I call
[UIImage imageWithData:data]
and then check the properties of the image, it is zero width and a garbage number for height, in fact, same number no matter what the image is. I tried with bunch of different images, png, jpg, different urls, it always downloads the image completely but UIImage can't initialize with that data. What could I be doing wrong here?
Thanks.
Code is really as you'd expect it to look like:
Connection Delegate:
-(void)connectionDidFinishLoading:(NSURLConnection*)theConnection {
[[ImageManager sharedInstance] dataDownloadedBy:self]; }
ImageManager:
-(void)dataDownloadedBy:(WebConnection *)connection{
WebImage *image = [[WebImage alloc] initWithLink:connection.url];
[image setImageFromData:connection.data];
[images addObject:image];
[connection release];}
WebImage:
-(void)setImageFromData:(NSMutableData *)data{
image = [[UIImage alloc] initWithData:data];}
First, I'm sure the UIImage will not initialize with garbage data. The constructor initWithData analyzes the data to determine the file format. If your data is corrupted, the image returned will be nil. Check this at first.
-(void)dataDownloadedBy:(WebConnection *)connection{
WebImage *image = [[WebImage alloc] initWithLink:connection.url];
[image setImageFromData:connection.data];
if (image.image != nil) { [images addObject:image]; }
[connection release];
}
Second, make sure you append the data during the download process. Here is the callback method:
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.receivedData appendData:data];
}
Finally, your code must absolutely includes the second case: a download failure.
- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[connection release];
}
Your problem description lacks some important pieces of code.
The URLCache demo from Apple is a very good project to understand async image download.
http://developer.apple.com/iphone/library/samplecode/URLCache/Introduction/Intro.html
I hope this will help you!
I can't tell what is wrong, it could be you don't use the release properly, say i don't know why you release connection at the end of dataDownloadedBy, it is supposed to be image ?
it could help if you post more your code here.
I used to do the same thing, you can have a look the post here
http://blog.163.com/lionyue#126/blog/static/1079307120096895433277/
Hope it helps
If initWithData is failing, most likely the image data you're getting is corrupt. You should save it to a file like this:
[data writeToFile:#"/tmp/foo.jpg" atomically:NO];
and then try to open it in Preview.app.
a different problem, but that gives teh same painful error is if You ask for a file that is not reachable: HTTP server will give back error 404 message, your code read that bytes (they are NOT valid bytes for an image, AND You will got NIL.