Getting length of NSMutableData - iphone

I have managed to NSInputStream and read some data to NSMutableData object. I am able to put this data into string and NSLog it, however when I try to access its length(I am assuming this is its size in bytes) my app crashes.
NSString *stringData=[[NSString alloc]initWithData:self.data encoding:NSUTF8StringEncoding];
NSLog(#"%# thats data",stringData);//logs out content of data
NSLog(#"%# thats data length",[self.data length]);//crashes
So my question is if I call copy on NSMutableDate do I get immutable copy ?
Am I tying to access the length in a wrong manner ?

It's because you are trying to log the length as an object using %#. It's not an object, it's an integer, so log it with %i instead:
NSLog(#"%i thats data length",[self.data length]);
Logging an object with %# tries to call the [... description] method on whatever is passed in. You can imagine the horrors that occur in the application memory when it tries to call that method on a random integer, thinking that it's a pointer to an object.

Related

Obj-C/iOS: How to retrieve contents of NSData and interact?

I'm retrieving a unix timestamp from a Bluetooth LE peripheral, which is stored in an NSData object. If I print the contents of the NSData object to the debug console, they appear correct, however if I try to convert the NSData object to an integer value, the integer value appears to keep changing.
NSData *refinedData = [mfrData subdataWithRange:range];
Which yields a value of 386d5e9a on the debug console.
I then convert to an integer:
uint32_t unixTimeStamp = refinedData;
Initially, this yields a value of 342162144 on the debug console. However, this value keeps growing, despite the NSData not changing. Can anybody help me understand what's going on?
If it's not already very apparent, I'm a newbie.
Thanks.
refinedData is a pointer to an instance of NSData. You want to access its contents:
uint32_t unixTimeStamp = *(uint32_t *)[refinedData bytes];
Note that this is simplified, and assumes that the bytes returned by the Bluetooth peripheral are the same endianness as the processor in your device, that range is correct, etc.

Object is deallocated - why? where?

Ok, I spent the last 8 hours fighting with it - it just seems beyond me. Here's my complete (relevant) code:
- (void)updateUserDefaults
{
NSMutableDictionary *viewControllerDetails = [[NSMutableDictionary alloc] initWithCapacity:4];
[viewControllerDetails setObject:[NSNumber numberWithInt:OOVenueClassControllerType] forKey:#"classType"];
[viewControllerDetails setObject:self.searchTerm forKey:#"searchTerm"];
[viewControllerDetails setObject:self.searchLocation forKey:#"searchLocation"];
//----- the next two lines cause the problem
NSString *res = [[NSString stringWithFormat:#"%#",[searchResults xmlString]] retain];
[viewControllerDetails setObject:res forKey:#"searchresults"];
//-----
NSMutableArray *viewControllersList = [NSMutableArray array] ;
[viewControllersList addObject:viewControllerDetails];
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
//the following line causes the error
[defs setObject:viewControllersList forKey:kViewControllersKey];
[defs synchronize];
[res release];
}
Note the block with the next two lines cause the problem. At first I didn't create another string, but added it later while trying to solve the problem.
If I comment out those two lines, everything works fine. If I put them back in, I get
- [CFString class]: message sent to deallocated instance 0xa1a9000
Is something is wrong with the string that I'm trying to put into the userdefaults? That string is rather large (about 200,000 characters), but I had stored even longer strings in user defaults in the past.
It's also worth noting that if I uninstall the app, then everything works fine. But on subsequent runs the problem exhibits itself.
So, how and why and where is the string getting deallocated? I have explicitly added retain - but that still doesn't help. What am I missing?
Edit: just realised I forgot to say that the error is thrown on line
[defs setObject:viewControllersList forKey:kViewControllersKey];
Also, for general information, method - (NSString *)xmlString on searchResults does exactly what the name means: creates an XML string with the information from that object.
Edit 2: I tried doing something else with that string - convert it to NSData, compress using zlib - but regardless of data type, that particular object gets deallocated. Does it have to do something with the size of the string?
NSString *res = [[NSString stringWithFormat:#"%#",[searchResults xmlString]] retain];
Is auto released. You don't need to release it at the end of your method. You are over-releasing it.
Further, you don't need to retain the [searchResults xmlString]. The stringWithFormat method already does it for you.
Good Luck!
Ok, not sure what exactly the problem was, but it was somewhere in the searchResults and/or xmlString method. searchResults object is originally created from XML received from the server (XML is parsed into the object structure). When xmlString was called, for some reason the string I was getting back was different from the original XML (I'm not talking about formatting, of course) - of 200,000 char-long string, within the first 500 chars or so there were some differences. I haven't been able to figure out why. So, instead of recreating the xml from object structure, I instead stored the original XML in a field in that object and, when xmlString was called, simply returned the original string. Now everything worked fine.
Thank you all for your support through this painful process.

Objective C - Populate Array From Exceedingly large PList

I am having some trouble populating a large plist into an array. Here is the snippet of code giving me problems:
// Populate the routes.
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"routes" ofType:#"plist"];
NSMutableArray *routes = [NSMutableArray arrayWithContentsOfFile:filePath];
NSLog(#"Routes: %#", routes);
// Populate the trips.
NSString *filePath2 = [[NSBundle mainBundle] pathForResource:#"trips" ofType:#"plist"];
NSMutableArray *trips = [NSMutableArray arrayWithContentsOfFile:filePath2];
NSLog(#"Trips: %#", trips);
My issue is that after displaying each mutable array in the logs, the log for the routes array displays just fine, but the log for the trips array simply doesn't appear at all. Usually when an issue occurs then the log will show something like "Trips: ( )", but that line doesn't appear at all in this case. The only difference I can see between the two instances is that the routes plist is an array with about 1000 dictionary objects and the trips plist has nearly 92,000 objects. Is there some sort of limit on the size of plists?
Thanks in advance.
"Is there some sort of limit on the size of plists?"
There isn't a limit to to the size of plists, but there is a limit to the amount of data that you can feed to an NSLog() command.
If trips were actually nil, the NSLog() call would succeed, and simply print out (null). The trips array is populated, however, which is why it's not printing out at all: NSLog() is saying, "sorry, there's no way I'm going to let you to print out all that".
I believe this has likely changed in more recent versions of OS X due to possible security concerns or performance issues. (In the past, users' hard drives would fill up with log files that were GB in size, caused by one process logging an error message hundreds of times a second; that is now limited to 500 logs per second). It's kind of confusing why nothing is printed out and you get no feedback from Xcode or anything, but I guess the system has no way of knowing whether your use of NSLog() is with good intentions or not.
According to the doc, if there is a parse problem or there is an issue with opening the file, nil will be returned. Is it possible in that massive file there is a bad character or a typo that might break the xml?
"
Return Value -->
An array containing the contents of the file specified by aPath. Returns nil if the file can’t be opened or if the contents of the file can’t be parsed into an array.

Convert NSData [UIImage] to a NSString

I am aware this question has been asked several times, but I was unable to find a definate answer that would best fit my situation.
I want the ability to have the user select an image from the library, and then that image is converted to an NSData type. I then have a requirement to call a .NET C# webservice via a HTTP get so ideally I need the resulting string to be UTF8 encoded.
This is what I have so far:
NSData *dataObj = UIImageJPEGRepresentation(selectedImage, 1.0);
[picker dismissModalViewControllerAnimated:YES];
NSString *content = [[NSString alloc] initWithData:dataObj encoding:NSUTF8StringEncoding];
NSLog(#"%#", content);
The NSLog statement simply produces output as:
2009-11-29 14:13:33.937 TestUpload2[5735:207] (null)
Obviously this isnt what I hoped to achieve, so any help would be great.
Kind Regards
You can't create a UTF-8 encoded string out of just any arbitrary binary data - the data needs to actually be UTF-8 encoded, and the data for your JPEG image obviously is not. Your binary data doesn't represent a string, so you can't directly create a string from it - -[NSString initWithData:encoding:] fails appropriately in your case.
Assuming you're using NSURLConnection (although a similar statement should be true for other methods), you'll construct your NSMutableURLRequest and use -setHTTPBody: which you need to pass an NSData object to. I don't understand why you would be using a GET method here since it sounds like you're going to be uploading this image data to your web service - you should be using POST.

NSString contains a number, why does it crash my App?

I'm having some difficulty with NSString in my application. Basically, I have an NSString called o1string which contains the value "602". I want to output this in a UIAlertView alongside some other text.
votedmessage = [ NSString stringWithFormat:#"The current standings are as follows:\n\n%#: %# votes", b1title, o1string ];
UIAlertView *votedAlert = [[UIAlertView alloc] initWithTitle:#"Thank you for voting" message:votedmessage delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
I have used NSLog and verified that the value inside the NSString is definitely 602, and the other variable (b1title) used in the message outputs fine on its own. I cannot work out why the app is crashing when I add the o1votes variable to the alert message though, is it something to do with a conflict in holding just a number inside an NSString?
This is how o1string is set. It definitely contains "602", grabbed from an XML file.
o1string = [[options objectAtIndex:3] objectForKey: #"votes"];
o1string = [o1string stringByReplacingOccurrencesOfString:#"\n" withString:#""];
o1string = [o1string stringByReplacingOccurrencesOfString:#" " withString:#""];
Unless that assignment of o1string is in the same method where votedmessage is created (since you don't say, I'm assuming not), it will be gone by the time you get to the code where votedmessage needs it.
Unless you're using garbage collection, you need to retain objects that you want to keep around past the current method. See the Objective-C memory management guide for complete details.
You need to post more code. In particular it's not clear whether the two pieces you posted are in the same function or different places.
If they're in different places you must call [o1string retain] (and later [o1string release]). The easiest way to do this would be to make olstring a property with retain semantics.
stringByReplacingOccurrencesOfString returns a temporary instance that will be auto-released sometime after the function exists.
I would guess the reason b1Title works is that it's stored in your dictionary so is persistent. o1string is created from the stringByXXX functions and is temporary.