Stuck/leak when allocating data for NSData? - iphone

I'm stuck at this method and I don't know why!
Can anyone point me to some source code?
Thank you so much!
This is my source code:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
.......
readData = [readFileHandle readDataOfLength:defaultLen]
NSData *decryptedData = nil;
//check is last buffer of file
NSUInteger exLen = [readData length] % 16;
NSUInteger decryptionLen = [readData length] - exLen;
NSData *dataForDecryption = nil;
if(exLen != 0)
{
stuck at here-> [readData getBytes:dataForDecryption length:decryptionLen];
//
decryptedData = [dataForDecryption AES256DecryptWithKey:KEY];
self.isEndOfFile = YES;
}
else
decryptedData = [readData AES256DecryptWithKey:KEY];
[readFileHandle closeFile];
.......
[pool drain];
I've used some functions such as:
NSData *dataForDecryption = [[[NSData alloc] initWithBytes:readData length:decryptionLen]autorelease];
NSData *dataForDecryption = [NSData dataWithBytes:readData length:decryptionLen];
But I get the same error.
When i'm using
dataForDecryption = [readFileHandle readDataOfLength:decryptionLen];
it's stuck at pos above and the size read is 0, although it's not EOF.
Thanks

stuck at here-> [readData getBytes:dataForDecryption length:decryptionLen];
You're passing dataForDecryption, which is a NSData*, but the parameter is supposed to be a buffer, i.e. void*. If you want a NSData*, you should instead use a method like subdataWithRange:.
dataForEncryption = [readData subdataWithRange:NSRangeMake(0, decryptionLen)];

Related

execute addObject, but NSMutableArray has no object

I try to use to codes below to add object to NSMutableArray
NSMutableArray* multipartData;
- (void)processDataChunk:(NSData *)postDataChunk
{
if (!postHeaderOK)
{
UInt16 separatorBytes = 0x0A0D;
NSData* separatorData = [NSData dataWithBytes:&separatorBytes length:2];
for (int i = 0; i < [postDataChunk length] - l; i++)
{
NSRange searchRange = {i, l};
if ([[postDataChunk subdataWithRange:searchRange] isEqualToData:separatorData])
{
NSRange newDataRange = {dataStartIndex, i - dataStartIndex};
dataStartIndex = i + l;
i += l - 1;
NSData *newData = [postDataChunk subdataWithRange:newDataRange];
if ([newData length])
{
[multipartData addObject:newData]; //A:set break point here
}
}
}
}
}
I set breakpoint at A:, and found that newData is not nil.
What is wrong with my codes?
Welcome any comment
You declare multipartData but do not allocate or initialize it. Somewhere before adding objects you must have
NSMutableArray *multipartData = [[NSMutableArray alloc] init];
or possibly
NSMutableArray *multipartData = [[[NSMutableArray alloc] init] autorelease];
as your needs dictate. But you must allocate and initialize multipartData before adding to or accessing anything in it.

NSData memory leak...pointing to NSConcreteData!

I am having a memory leak, and can't figure it out. Basically, what I am doing here is pulling in images to a Mutable Dictionary and returning the dictionary.
- (NSMutableDictionary *)loadImageDataGroup:(NSUInteger)index {
int lim = 5;
int sta = 0;
if (index > lim) {
sta = index-lim;
}
int fin = (((lim*2)+1)+sta);
if (fin > [self imageCount]) {
sta = ([self imageCount]-((lim*2)-1));
fin = [self imageCount];
}
BOOL firstTime = NO;
if ([imagesLoaded count] == 0) {
firstTime = YES;
}
NSMutableDictionary *tempDict = [[[NSMutableDictionary alloc] init] autorelease];
for (int i = sta; i < fin; i++) {
NSString *imageName = [self imageNameAtIndex:i];
if ([imagesLoaded valueForKey:imageName] == nil) {
// This is the Memory Leak...at least that is where Leaks is pointing me.
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageName]];
[tempDict setObject:imageData forKey:imageName];
} else {
[tempDict setObject:[imagesLoaded valueForKey:imageName] forKey:imageName];
}
}
return tempDict;
}
The leak is in the NSData = *imageData spot, and when I pull it up in leaks, it points to NSConcreteData.
Looking at your code, I'm not seeing anything obviously wrong. Be aware that Instruments can produce false positives.
See the following:
Instruments showing false leak?

Memory Leak according to Instruments

Been running instruments on my app. Its says i am leaking 864bytes & 624bytes from 2 NSCFString and the library responsible is Foundation.
So that leads me to believe thats its not a leak caused by me? Or is it?
Here is the offending method according to instruments. It seems to be a
substringWithRange
that is leaking.
-(void) loadDeckData
{
deckArray =[[NSMutableArray alloc] init];
NSString* path = [[NSBundle mainBundle] pathForResource:#"rugby" ofType:#"txt"
inDirectory:#""];
NSString* data = [NSString stringWithContentsOfFile:path encoding:
NSUTF8StringEncoding error: NULL];
NSString *newString = #"";
NSString *newline = #"\n";
NSString *comma = #",";
int commaCount = 0;
int rangeCount = 0;
NSString *nameHolder = #"";
NSString *infoHolder = #"";
NSMutableArray *statsHolder = [[NSMutableArray alloc] init];
for (int i=0; i<data.length; i++)
{
newString = [data substringWithRange:NSMakeRange(i, 1)];
if ([newString isEqualToString: comma]) //if we find a comma
{
if (commaCount == 0)// if it was the first comma we are parsing the
NAME
{
nameHolder = [data substringWithRange:NSMakeRange(i-
rangeCount, rangeCount)];
}
else if (commaCount == 1)//
{
infoHolder = [data substringWithRange:NSMakeRange(i-
rangeCount, rangeCount)];
//NSLog(infoHolder);
}
else // if we are on to 2nd,3rd,nth comma we are parsing stats
{
NSInteger theValue = [[data
substringWithRange:NSMakeRange(i-rangeCount,rangeCount)]
integerValue];
NSNumber* boxedValue = [NSNumber
numberWithInteger:theValue];
[statsHolder addObject:boxedValue];
}
rangeCount=0;
commaCount++;
}
else if ([newString isEqualToString: newline])
{
NSInteger theValue = [[data substringWithRange:NSMakeRange(i-
rangeCount,rangeCount)] integerValue];
NSNumber* boxedValue = [NSNumber numberWithInteger:theValue];
[statsHolder addObject:boxedValue];
commaCount=0;
rangeCount=0;
Card *myCard = [[Card alloc] init];
myCard.name = nameHolder;
myCard.information = infoHolder;
for (int x = 0; x < [statsHolder count]; x++)
{
[myCard.statsArray addObject:[statsHolder
objectAtIndex:x]];
}
[deckArray addObject:myCard];
[myCard autorelease];
[statsHolder removeAllObjects];
}
else
{
rangeCount++;
}
}
[statsHolder autorelease];
}
Thanks for your advice.
-Code
As Gary's comment suggests this is very difficult to diagnose based on your question.
It's almost certainly a leak caused by you however, I'm afraid.
If you go to the View menu you can open the Extended Detail. This should allow you to view a stack trace of exactly where the leak occurred. This should help diagnose the problem.
When to release deckArray? If deckArray is a class member variable and not nil, should it be released before allocate and initialize memory space?

How to Create UIImage from NSData and Avatar Data of XMPP?

This question is related to Iphone SDK, NSData and UIImage.
I am trying to create an image from the Avatar Data returned from the xmpp like the following:
<presence from='yyy#184.73.164.51/spark' to='ken#184.73.164.51/424978324712783686768453' id='Oj02v-45'><status>Away due to idle.</status><priority>0</priority><show>away</show><x xmlns='vcard-temp:x:update'><photo>a3f549fa9705e7ead2905de0b6a804227ecdd404</photo></x><x xmlns='jabber:x:avatar'><hash>a3f549fa9705e7ead2905de0b6a804227ecdd404</hash></x></presence>
So in this case, I assume that a3f549fa9705e7ead2905de0b6a804227ecdd404 is the photo data.
So How can I transfer this into NSData?
I think if I can get the NSData object,
I can easily create the UIImage, right?
I think "a3f549fa9705e7ead2905de0b6a804227ecdd404" is the photo data
this is my codes:
NSString* command = #"a3f549fa9705e7ead2905de0b6a804227ecdd404";
command = [command stringByReplacingOccurrencesOfString:#" " withString:#""];
NSMutableData *commandToSend= [[NSMutableData alloc] init];
unsigned char whole_byte;
char byte_chars[3] = {'\0','\0','\0'};
int i;
for (i=0; i < [command length]/2; i++) {
byte_chars[0] = [command characterAtIndex:i*2];
byte_chars[1] = [command characterAtIndex:i*2+1];
whole_byte = strtol(byte_chars, NULL, 16);
[commandToSend appendBytes:&whole_byte length:1];
}
UIImage *image = [UIImage imageWithData: commandToSend];
However,
it doesn't work.
Anyone knows what's wrong with it?
In XMPPPresence.m add this method
-(NSString *)photo {
NSXMLElement *xElement = [self elementForName:#"x" xmlns:#"vcard-temp:x:update"];
NSString *photoHash = [[xElement elementForName:#"photo"]stringValue];
return photoHash;
}
// In XMPPStream's delegate:
- (void)xmppStream:(XMPPStream *)stream didReceivePresence:
(XMPPPresence *)presence {
NSString *photoHash = [presence photo];
if ([photoHash length] > 0) { // in case when there's no photo hash
XMPPJID *rosterJID = [presence from];
BOOL requestPhoto = ... // determine if you need to request new
photo or nor
if (requestPhoto) {
NSXMLElement *iqAvatar = [NSXMLElement elementWithName:#"iq"];
NSXMLElement *queryAvatar = [NSXMLElement elementWithName:#"vCard"
xmlns:#"vcard-temp"];
[iqAvatar addAttributeWithName:#"type" stringValue:#"get"];
[iqAvatar addAttributeWithName:#"to" stringValue:[rosterJID full]];
[iqAvatar addChild:queryAvatar];
XMPPIQ *avatarRequestIQ = [XMPPIQ iqFromElement:iqAvatar];
[stream sendElement:avatarRequestIQ];
}
}
}
// And when buddy will send photo, it will be in vcard BASE64-encoded.
// You will receive it as IQ:
- (BOOL)xmppStream:(XMPPStream *)stream didReceiveIQ:(XMPPIQ *)iq {
XMPPElement *vCardPhotoElement = (XMPPElement *)[[iq
elementForName:#"vCard"] elementForName:#"PHOTO"];
if (vCardPhotoElement != nil) {
// avatar data
NSString *base64DataString = [[vCardPhotoElement
elementForName:#"BINVAL"] stringValue];
NSData *imageData = [NSData
dataFromBase64String:base64DataString]; // you need to get NSData
BASE64 category
UIImage *avatarImage = [UIImage imageWithData:imageData];
XMPPJID *senderJID = [iq from];
[self xmppStream:stream didReceiveImage:avatarImage
forBuddy:senderJID]; // this is my custom delegate method where I
save new avatar to cache
}
return NO;
}
Hope this will help you.
That is the picture hash you now have to send a vcard request which will contain the same hash for verification and binval containing the picture data in base64

NSData to NString conversion problem

I'm getting an HTML file as NSData and need to extract some parts of it. For that I need to convert it to NSString with UTF8 encoding. The thing is that this conversion fails, probably because the NSData contains bytes that are invalid for UTF8. I have tried to get the byte array of the data and go over it, but each time I come across non ASCII character (hebrew letters for example) I get jibrish.
Help will be appreciated.
UPDATE:
To Gordon - the NSData generated like that:
NSData *theData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&theResponse error:&theError];
When I say that the conversion fails I mean that
[[NSString alloc] initWithData:temp encoding:NSUTF8StringEncoding]
returns nil
To Ed - Here is my code (I got the Byte array from NSData, found what I need, and constructed another Byte array from that - turned it to NSData and then attempted to convert it to NSString... sounds kinda complicated...)
-(NSString *)UTF8StringFromData:(NSData *)theData{
Byte *arr = [theData bytes];
NSUInteger begin1 = [self findIndexOf:#"<li>" bArr:arr size:[theData length]]+4;
NSUInteger end1 = [self findIndexOf:#"</li></ol>" bArr:arr size:[theData length]];
Byte *arr1 = (Byte *)malloc(sizeof(Byte)*((end1-begin1+1)));
NSLog(#"%d %d",begin1, end1);
int j = 0;
for (int i = begin1; i < end1; i++){
arr1[j] = arr[i];
j++;
}
arr1[j]='\0';
NSData *temp = [NSData dataWithBytes:arr1 length:j];
return [[NSString alloc] initWithData:temp encoding:NSUTF8StringEncoding];
}
I know this is an old topic but it came up when I was looking for the solution today. I've solved it now so I'm just posting it for others who might run into this page looking for a solution.
Here's what I do in an asynchronous request:
I first store the text encoding name in connection:didReceiveResponse using
encodingName = [[NSString alloc] initWithString:[response textEncodingName]];
Then later in my connectionDidFinishLoading method I used
NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef) encodingName));
NSString *payloadAsString = [[NSString alloc] initWithData:receivedData encoding:encoding];
To Gordon - the NSData generated like that:
NSData *theData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&theResponse error:&theError];
When I say that the conversion fails I mean that
[[NSString alloc] initWithData:temp encoding:NSUTF8StringEncoding]
returns nil
To Ed - Here is my code (I got the Byte array from NSData, found what I need, and constructed another Byte array from that - turned it to NSData and then attempted to convert it to NSString... sounds kinda complicated...)
-(NSString *)UTF8StringFromData:(NSData *)theData{
Byte *arr = [theData bytes];
NSUInteger begin1 = [self findIndexOf:#"<li>" bArr:arr size:[theData length]]+4;
NSUInteger end1 = [self findIndexOf:#"</li></ol>" bArr:arr size:[theData length]];
Byte *arr1 = (Byte *)malloc(sizeof(Byte)*((end1-begin1+1)));
NSLog(#"%d %d",begin1, end1);
int j = 0;
for (int i = begin1; i < end1; i++){
arr1[j] = arr[i];
j++;
}
arr1[j]='\0';
NSData *temp = [NSData dataWithBytes:arr1 length:j];
return [[NSString alloc] initWithData:temp encoding:NSUTF8StringEncoding];
}
have you checked the charset= in the HTTP headers and/or the document itself? The most likely reason for the conversion to fail is because the bytes don't represent a valid UTF-8 string.
I'm not sure if you're aware, you don't really need to copy the array to another array before putting it into the new NSData object.
-(NSString *)UTF8StringFromData:(NSData *)theData {
Byte *arr = [theData bytes];
NSUInteger begin1 = [self findIndexOf:#"<li>" bArr:arr size:[theData length]]+4;
NSUInteger end1 = [self findIndexOf:#"</li></ol>" bArr:arr size:[theData length]];
Byte *arr1 = arr + begin1;
NSData *temp = [NSData dataWithBytes:arr1 length:end1 - begin1];
return [[NSString alloc] initWithData:temp encoding:NSUTF8StringEncoding];
}
As for your particular problem, I would try looking through the data manually using the debugger. Put a breakpoint after you have your array (arr1). When you hit it, open up the GDB console and try this:
print (char *)arr1
With your code, it should print out the string you're trying to get. (With the code I gave above, it won't stop after the . It'll just keep going).
If the result is not what you expect, then there's something wrong with the data, or perhaps with your begin1 and end1 boundaries.