I am having trouble with an application. It runs in the simulator, but when I try to run it on a device, it crashes.
I tested it and it worked before submitting it to Apple for the review, but now, when I tried to take another look at it, it keeps crashing. Also, it doesn't crash right at the start, but when I try to navigate to a second view. Please let me know if you can help me to figure it out. Thanks!
(I have already tried setting NSZombieEnable, as I found this suggestion/answer in different posts but it does not work for me)
OS Version: iPhone OS 5.1.1 (9B206)
Report Version: 104
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x6f466874
Crashed Thread: 0
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 libobjc.A.dylib 0x335b2f7e objc_msgSend + 22
1 Foundation 0x34d24d04 _NSDescriptionWithLocaleFunc + 44
2 CoreFoundation 0x3597496e __CFStringAppendFormatCore + 7998
3 CoreFoundation 0x358ef1d8 _CFStringCreateWithFormatAndArgumentsAux + 68
4 Foundation 0x34d24c2e +[NSString stringWithFormat:] + 54
5 Sustain 0x00082148 +[HTMLParser parseDataForRequest:error:] (HTMLParser.m:169)
6 Sustain 0x00085a5a -[ProxyRequestResponseHandler requestFinished:] (ProxyRequestResponseHandler.m:251)
7 CoreFoundation 0x358f31f4 -[NSObject performSelector:withObject:] + 36
8 Sustain 0x00054364 -[ASIHTTPRequest reportFinished] (ASIHTTPRequest.m:2004)
9 CoreFoundation 0x358f31f4 -[NSObject performSelector:withObject:] + 36
10 Foundation 0x34dc3740 __NSThreadPerformPerform + 344
11 CoreFoundation 0x35968acc __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 8
12 CoreFoundation 0x35968298 __CFRunLoopDoSources0 + 208
13 CoreFoundation 0x3596703e __CFRunLoopRun + 646
14 CoreFoundation 0x358ea49e CFRunLoopRunSpecific + 294
15 CoreFoundation 0x358ea366 CFRunLoopRunInMode + 98
16 GraphicsServices 0x33685432 GSEventRunModal + 130
17 UIKit 0x330c2cce UIApplicationMain + 1074
18 Sustain 0x00019c26 main (main.m:16)
19 Sustain 0x00019bc0 start + 32
Thread 0 crashed with ARM Thread State:
r0: 0x00128a98 r1: 0x325894f6 r2: 0x359eccd5 r3: 0x6f46687c
r4: 0x32588417 r5: 0x00000000 r6: 0x3f3078c8 r7: 0x2fe0cb70
r8: 0x2fe0cc13 r9: 0x0c96253d r10: 0x359730b6 r11: 0x00000000
ip: 0x3f2e26f0 sp: 0x2fe0cb5c lr: 0x34d24d0b pc: 0x335b2f7e
cpsr: 0x200f0030
Here is the mathod you requested in HTMLParser
+ (BOOL)parseDataForRequest:(ASIHTTPRequest *)request error:(NSError **)error
{
NSStringEncoding encoding = [request responseEncoding];
NSString *string = [[NSString alloc] initWithContentsOfFile:[request downloadDestinationPath] usedEncoding:&encoding error:NULL];
[string release];
NSURL *baseURL = [request url];
xmlInitParser();
xmlDocPtr doc;
if ([request downloadDestinationPath]) {
doc = htmlReadFile([[request downloadDestinationPath] cStringUsingEncoding:NSUTF8StringEncoding], [self encodingNameForStringEncoding:encoding], HTML_PARSE_RECOVER | HTML_PARSE_NONET | HTML_PARSE_NOWARNING | HTML_PARSE_NOERROR);
} else {
NSData *data = [request responseData];
doc = htmlReadMemory([data bytes], (int)[data length], "", [self encodingNameForStringEncoding:encoding], HTML_PARSE_RECOVER | HTML_PARSE_NONET | HTML_PARSE_NOWARNING | HTML_PARSE_NOERROR);
}
if (doc == NULL) {
[super parseDataForRequest:request error:error];
return YES;
}
// Create xpath evaluation context
xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
if(xpathCtx == NULL) {
if (error) {
*error = [NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:#"Error: unable to create new XPath context",NSLocalizedDescriptionKey,nil]];
}
return NO;
}
// Evaluate xpath expression
xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx);
if(xpathObj == NULL) {
xmlXPathFreeContext(xpathCtx);
if (error) {
*error = [NSError errorWithDomain:NetworkRequestErrorDomain code:101 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:#"Error: unable to evaluate XPath expression!",NSLocalizedDescriptionKey,nil]];
}
return NO;
}
// Now loop through our matches
xmlNodeSetPtr nodes = xpathObj->nodesetval;
int size = (nodes) ? nodes->nodeNr : 0;
int i;
for(i = size - 1; i >= 0; i--) {
assert(nodes->nodeTab[i]);
NSString *parentName = [NSString stringWithCString:(char *)nodes->nodeTab[i]->parent->name encoding:encoding];
NSString *nodeName = [NSString stringWithCString:(char *)nodes->nodeTab[i]->name encoding:encoding];
xmlChar *nodeValue = xmlNodeGetContent(nodes->nodeTab[i]);
NSString *value = [NSString stringWithCString:(char *)nodeValue encoding:encoding];
xmlFree(nodeValue);
// Here we add a <base> element to the header to make the end result play better with javascript
// (UIWebView seemed to ignore the Content-Base http header when I tried)
if ([[nodeName lowercaseString] isEqualToString:#"head"]) {
xmlNodePtr node = xmlNewNode(NULL, (xmlChar *)"base");
xmlNewProp(node, (xmlChar *)"href", (xmlChar *)[[baseURL absoluteString] cStringUsingEncoding:encoding]);
node = xmlDocCopyNode(node, doc, 1);
xmlAddChild(nodes->nodeTab[i], node);
// Our xpath query matched all <link> elements, but we're only interested in stylesheets
// We do the work here rather than in the xPath query because the query is case-sensitive, and we want to match on 'stylesheet', 'StyleSHEEt' etc
} else if ([[parentName lowercaseString] isEqualToString:#"link"]) {
xmlChar *relAttribute = xmlGetNoNsProp(nodes->nodeTab[i]->parent,(xmlChar *)"rel");
if (relAttribute) {
NSString *rel = [NSString stringWithCString:(char *)relAttribute encoding:encoding];
xmlFree(relAttribute);
if ([[rel lowercaseString] isEqualToString:#"stylesheet"] || [[rel lowercaseString] isEqualToString:#"alternate stylesheet"]) {
xmlNodeSetContent(nodes->nodeTab[i], (xmlChar *)[[self localURLForURL:value withBaseURL:baseURL] cStringUsingEncoding:encoding]);
}
}
// Parse the content of <style> tags and style attributes to find external image urls or external css files
} else if ([[nodeName lowercaseString] isEqualToString:#"style"]) {
xmlNodeSetContent(nodes->nodeTab[i], (xmlChar *)[[CSSParser replaceURLsInCSSString:value withBaseURL:baseURL] cStringUsingEncoding:encoding]);
// Parse the content of <source src=""> tags (HTML 5 audio + video)
// We explictly disable the download of files with .webm, .ogv and .ogg extensions, since it's highly likely they won't be useful to us
} else if ([[parentName lowercaseString] isEqualToString:#"source"] || [[parentName lowercaseString] isEqualToString:#"audio"]) {
NSString *fileExtension = [[value pathExtension] lowercaseString];
if (![fileExtension isEqualToString:#"ogg"] && ![fileExtension isEqualToString:#"ogv"] && ![fileExtension isEqualToString:#"webm"]) {
xmlNodeSetContent(nodes->nodeTab[i], (xmlChar *)[[self localURLForURL:value withBaseURL:baseURL] cStringUsingEncoding:encoding]);
}
// For all other elements matched by our xpath query (except hyperlinks), add the content as an external url to fetch
} else if (![[parentName lowercaseString] isEqualToString:#"a"]) {
xmlNodeSetContent(nodes->nodeTab[i], (xmlChar *)[[self localURLForURL:value withBaseURL:baseURL] cStringUsingEncoding:encoding]);
}
if (nodes->nodeTab[i]->type != XML_NAMESPACE_DECL) {
nodes->nodeTab[i] = NULL;
}
}
xmlXPathFreeObject(xpathObj);
xmlXPathFreeContext(xpathCtx);
// We'll use the xmlsave API so we can strip the xml declaration
xmlSaveCtxtPtr saveContext;
if ([request downloadDestinationPath]) {
// Truncate the file first
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
[fileManager createFileAtPath:[request downloadDestinationPath] contents:nil attributes:nil];
saveContext = xmlSaveToFd([[NSFileHandle fileHandleForWritingAtPath:[request downloadDestinationPath]] fileDescriptor],[self encodingNameForStringEncoding:NSUTF8StringEncoding],2|8); // 2 == XML_SAVE_NO_DECL, this isn't declared on Mac OS 10.5
xmlSaveDoc(saveContext, doc);
xmlSaveClose(saveContext);
} else {
#if TARGET_OS_MAC && MAC_OS_X_VERSION_MAX_ALLOWED <= __MAC_10_5
// xmlSaveToBuffer() is not implemented in the 10.5 version of libxml
NSString *tempPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]];
[[[[NSFileManager alloc] init] autorelease] createFileAtPath:tempPath contents:nil attributes:nil];
saveContext = xmlSaveToFd([[NSFileHandle fileHandleForWritingAtPath:tempPath] fileDescriptor],[self encodingNameForStringEncoding:NSUTF8StringEncoding],2|8); // 2 == XML_SAVE_NO_DECL, this isn't declared on Mac OS 10.5
xmlSaveDoc(saveContext, doc);
xmlSaveClose(saveContext);
[request setRawResponseData:[NSMutableData dataWithContentsOfFile:tempPath]];
#else
xmlBufferPtr buffer = xmlBufferCreate();
saveContext = xmlSaveToBuffer(buffer,[self encodingNameForStringEncoding:NSUTF8StringEncoding],2|8); // 2 == XML_SAVE_NO_DECL, this isn't declared on Mac OS 10.5
xmlSaveDoc(saveContext, doc);
xmlSaveClose(saveContext);
[request setRawResponseData:[[[NSMutableData alloc] initWithBytes:buffer->content length:buffer->use] autorelease]];
xmlBufferFree(buffer);
#endif
}
NSString *contentType = [[[request responseHeaders] objectForKey:#"Content-Type"] lowercaseString];
contentType = [[contentType componentsSeparatedByString:#";"] objectAtIndex:0];
if (!contentType) {
contentType = #"text/html";
}
[[request responseHeaders] setValue:[NSString stringWithFormat:#"%#; charset=utf-8"] forKey:#"Content-Type"];
[request setResponseEncoding:NSUTF8StringEncoding];
xmlFreeDoc(doc);
doc = nil;
[super parseDataForRequest:request error:error];
return YES;
}
In the second view I load a webView that gets cached after being loaded.
I used this project in order to obtain this:
https://github.com/pokeb/ProxyingUIWebView
What's weird is that it used to work, but now it doesn't anymore.
I have tried to test it on another device and I get the same crash.
This is what I have in my secondarry view controller:
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSString *urlString = [NSString stringWithFormat:#"%#", request.URL];
NSBundle *mainBundle = [NSBundle mainBundle];
NSString *baseUrl = [mainBundle objectForInfoDictionaryKey:#"testUrl"];
if ([urlString rangeOfString:baseUrl].location != NSNotFound) //Check if URL is in-app.
{
NSURLRequest *testRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://127.0.0.1:8080/?url=http.somelink.net"]];
NSString *requestUrlString = [NSString stringWithFormat:#"%#",request.URL];
NSString *testUrlString = [NSString stringWithFormat:#"%#",testRequest.URL];
if ([requestUrlString isEqualToString:testUrlString]) //First view load
{
return YES;
}
if (navigationType == UIWebViewNavigationTypeLinkClicked ||
navigationType == UIWebViewNavigationTypeFormSubmitted ||
navigationType == UIWebViewNavigationTypeFormResubmitted ||
navigationType == UIWebViewNavigationTypeReload ||
navigationType == UIWebViewNavigationTypeOther)
{
if ([requestUrlString rangeOfString:#"Id="].location != NSNotFound) //Navigate to
{ //secondary view.
SecondaryTopTenSwapsViewController *secondaryController = [[SecondaryTopTenSwapsViewController alloc] init];
secondaryController.urlRequest = request;
[self.navigationController pushViewController:secondaryController animated:YES];
}
return NO;
}
return YES;
}
else //Not in-app URL. Check if user wants to leave application and open Safari.
{
UIAlertView *leaveApplicationAlert = [[UIAlertView alloc] initWithTitle:#"Open link?" message:#"Are you sure you want to exit the application and open the link in Safari?" delegate:self cancelButtonTitle:#"NO" otherButtonTitles:#"YES", nil];
leaveApplicationAlert.tag = 1;
[leaveApplicationAlert show];
externalUrl = request.URL;
return NO;
}
}
Also, I found that in my secondary view controller it crashes right after
-(void)webViewDidStartLoad:(UIWebView *)webView
Also, it can't be a memory issue, as if I receive a memory warning, I pop to the root view controller and release all the subviews.
You are trying to access an object by casting it's format type incorrectly.
For example, you are trying to access an integer value by using the format type %# rather than %i or %d.
NSInteger someInteger = 255;
NSString *string = [NSString stringWithFormat:#"Hello, my favourite number is %#", someInteger"];
If you post some code, I can outline where this is occurring.
From your stack trace, it looks like the string where the issue is arising is being passed into a method where the HTMLParser object is the receiver.
Edit---
Another possibility is that one of the arguments passed to the NSString has already been released and cannot be accessed as it has been deallocated and furthermore removed from memory.
Edit----
I believe that the problem is on this line:
[[request responseHeaders] setValue:[NSString stringWithFormat:#"%#; charset=utf-8"] forKey:#"Content-Type"];
You use the format string %#, yet do not provide an NSString as an argument.
I believe that you meant to code the following:
[[request responseHeaders] setValue:[NSString stringWithFormat:#"%#; charset=utf-8", contentType] forKey:#"Content-Type"];
Turn on Zombies and Malloc Scribble (scheme diagnostics) and debug your app (either simulator or device or both). Likely you have a deallocated object you are working with. Random memory accesses may succeed or fail when you read (or write) via a deallocated object or pointer. That's the most common reason for such inconsistent behavior.
Related
I am using the YouTube API in UIWebView.
I have created a NSString with the HTML5 player that I load in the UIWebView. Everything works perfectly on iPhone 5 and iPad.
But, if I test the app using an iPhone 4, the player returns the buffering state all the time. Only if I explicitly press the play button, the player starts playing, without stopping again for buffering. It seems that although the video has been buffered, the player still gives me this state.
Is anyone aware of this problem? Any idea?
Thank you very much in advance!!
In LBYouTubePlayerViewController.m file
Replace Following method on yr old Method....
then test...
-(NSURL*)_extractYouTubeURLFromFile:(NSString *)html error:(NSError *__autoreleasing *)error {
NSString *JSONStart = nil;
// NSString *JSONStartFull = #"ls.setItem('PIGGYBACK_DATA', \")]}'";
NSString *JSONStartFull = #"bootstrap_data = \")]}'";
NSString *JSONStartShrunk = [JSONStartFull stringByReplacingOccurrencesOfString:#" " withString:#""];
if ([html rangeOfString:JSONStartFull].location != NSNotFound)
JSONStart = JSONStartFull;
else if ([html rangeOfString:JSONStartShrunk].location != NSNotFound)
JSONStart = JSONStartShrunk;
if (JSONStart != nil) {
NSScanner* scanner = [NSScanner scannerWithString:html];
[scanner scanUpToString:JSONStart intoString:nil];
[scanner scanString:JSONStart intoString:nil];
NSString *JSON = nil;
[scanner scanUpToString:#"}\";" intoString:&JSON];
JSON = [NSString stringWithFormat:#"%#}",JSON]; // Add closing bracket } to get vallid JSON again
// [scanner scanUpToString:#"\");" intoString:&JSON];
JSON = [self _unescapeString:JSON];
NSError* decodingError = nil;
NSDictionary* JSONCode = nil;
// First try to invoke NSJSONSerialization (Thanks Mattt Thompson)
id NSJSONSerializationClass = NSClassFromString(#"NSJSONSerialization");
SEL NSJSONSerializationSelector = NSSelectorFromString(#"dataWithJSONObject:options:error:");
if (NSJSONSerializationClass && [NSJSONSerializationClass respondsToSelector:NSJSONSerializationSelector]) {
JSONCode = [NSJSONSerialization JSONObjectWithData:[JSON dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:&decodingError];
}
else {
JSONCode = [JSON objectFromJSONStringWithParseOptions:JKParseOptionNone error:&decodingError];
}
if (decodingError) {
// Failed
*error = decodingError;
}
else {
// Success
NSDictionary *dict = [JSONCode objectForKey:#"content"];
NSDictionary *dictTemp = [dict objectForKey:#"video"];
NSArray* videos = [dictTemp objectForKey:#"fmt_stream_map"];
NSString* streamURL = nil;
if (videos.count) {
NSString* streamURLKey = #"url";
if (self.quality == LBYouTubePlayerQualityLarge) {
streamURL = [[videos objectAtIndex:0] objectForKey:streamURLKey];
}
else if (self.quality == LBYouTubePlayerQualityMedium) {
unsigned int index = MAX(0, videos.count-2);
streamURL = [[videos objectAtIndex:index] objectForKey:streamURLKey];
}
else {
streamURL = [[videos lastObject] objectForKey:streamURLKey];
}
}
if (streamURL) {
return [NSURL URLWithString:streamURL];
}
else {
*error = [NSError errorWithDomain:kLBYouTubePlayerControllerErrorDomain code:2 userInfo:[NSDictionary dictionaryWithObject:#"Couldn't find the stream URL." forKey:NSLocalizedDescriptionKey]];
}
}
}
else {
*error = [NSError errorWithDomain:kLBYouTubePlayerControllerErrorDomain code:3 userInfo:[NSDictionary dictionaryWithObject:#"The JSON data could not be found." forKey:NSLocalizedDescriptionKey]];
}
return nil;
}
I am new to iphone - objC et al. I wanted to know if there is a way by which I could get all the NSURL and filename of the images files in an iphone without making use of ALAsset ?
In the current code - it is done like below. And I see the time it takes to loop 1100 images is like 14 seconds. Is there a better way to get url,filename quickly, please let me know.
ALAssetsLibrary* assetLibrary = [[ALAssetsLibrary alloc] init];
ALAssetsGroupType type = m == 2 || m == 1 ? ALAssetsGroupAll : ALAssetsGroupLibrary;
[assetLibrary enumerateGroupsWithTypes:type usingBlock:^(ALAssetsGroup* group, BOOL* stop)
{
if (group)
{
[group setAssetsFilter:m == 1 ? [ALAssetsFilter allVideos] : [ALAssetsFilter allPhotos]];
[group enumerateAssetsUsingBlock:^(ALAsset* asset, NSUInteger index, BOOL* innerstop)
{
if (asset)
{
#autoreleasepool
{
if (!initialized)
{
*innerstop = YES;
return;
}
/***************************************************************************************/
ALAssetRepresentation* defaultRepresentation = [asset defaultRepresentation];
if(defaultRepresentation)
{
//NSLog(#"defaultRepresentation for %#", [[defaultRepresentation url] absoluteString]);
long long size = [defaultRepresentation size];
NSURL* url = [defaultRepresentation url];
NSString* fileName = [defaultRepresentation filename];
I keep getting the following memory leak using the "Leaks" tool in Xcode. As this is a library, I'm just wondering what would be the best way to fix such a leak. Any help would be greatly appreciated. I am happy to share more code if needed.
UPDATE: I found this article, which doesn't seem promising. Has anyone got any suggestions as to how to fix this?
http://code.google.com/p/json-framework/issues/detail?id=13
This is how I'm using the library.
- (void)getFacebookProfileFinished:(ASIHTTPRequest *)request {
NSString *responseString = [request responseString];
NSMutableDictionary *responseJSON = [responseString JSONValue]; //memory leak 100%
NSString *username;
NSString *firstName = [responseJSON objectForKey:#"first_name"];
NSString *lastName = [responseJSON objectForKey:#"last_name"];
NSString *facebookId = [responseJSON objectForKey:#"id"];
if (firstName && lastName) {
username = [NSString stringWithFormat:#"%# %#", firstName, lastName];
} else {
username = #"";
}
UIAppDelegate.userSessionId = facebookId;
UIAppDelegate.userFullName = username;
if (UIAppDelegate.userSessionId != nil) {
Service1 *service = [[Service1 alloc] init];
[service UserExists:self action:#selector(handlerUserExists:) facebookUserId:UIAppDelegate.userSessionId];
[service release];
} else {
[Utility displayAlertMessage:#"There has been an error. Please try again later." withTitle:#"Error"];
[self logoutCompletely];
}
}
By commenting out the body of your if (line 50) you've made your release (line 51) conditional. Comment out the if (line 49) as well.
However, having said that your previous method has the same issue but apparently no warning, or maybe it was never used?
As CRD said above. You have the same leak in your JSONFragmentValue. Here is a correct non leaking version.
- (id) JSONFragmentValue
{
SBJasonParser *jsonParser = [SBJasonParser new];
id repr = [jsonParser fragmentWithString:self];
if (repr == nil)
{
NSLog(#"JSonFragmentValue failed:%#", [jsonParser ErrorTrace]);
}
[jsonparser release], jsonParser = nil;
return repr;
}
Or if you prefer autorelease pools.
- (id) JSONFragmentValue
{
SBJasonParser *jsonParser = [SBJasonParser new] autorelease];
id repr = [jsonParser fragmentWithString:self];
if (repr == nil)
{
NSLog(#"JSonFragmentValue failed:%#", [jsonParser ErrorTrace]);
}
return repr;
}
I am getting a potential leak in these methods..can anyone please help me..Leak in method 1 is in line 5..I am referencing this method from another class as [sync loginHandler] where sync is an object of the class which has the method loginHandler..
-(void) loginHandler
{
1 SCRMsugarsoap* service = [[SCRMsugarsoap alloc] initWithUrl:serverURL];
2 service.logging = YES;
3 service.username = userName;
4 service.password = password;
5 [service login:self action:#selector(sessionIdHandler:) user_auth: [[[SCRMuser_auth alloc] initWithUsername:userName andPassword:password]autorelease] application_name: #""];
6 [service release];
}
And another method where I have problems with leaks is
-(NSMutableArray *)searchContacts:(NSString *)tableName bySearchString:(NSString *)searchString
{
1 NSString *sid=#"";
2 NSString *firstname=#"";
3 NSString *lastname=#"";
4 NSString *qsql;
//NSArray *contactArray=[[NSArray alloc]init];
5 searchArray=[[NSMutableArray alloc]init];
6 qsql=[NSString stringWithFormat:#"SELECT DISTINCT sugar_id,first_name,last_name FROM CONTACTS where last_name LIKE '%%%#%%' OR first_name LIKE '%%%#%%' GROUP BY sugar_id ORDER BY last_name",searchString,searchString];
7 sqlite3_stmt *statement;
8 if (sqlite3_prepare_v2( db, [qsql UTF8String], -1, &statement, nil) == SQLITE_OK) {
9 while (sqlite3_step(statement) == SQLITE_ROW)
10 {
//TODO: alloc Contact object
11 Contact *contacts=[[Contact alloc]init];
12 sid = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
13 firstname = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 1)];
14 lastname = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 2)];
15
16 if ([firstname isEqualToString:#"(null)"]) {
lastname=[lastname stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[lastname substringToIndex:1] uppercaseString]];
17 contacts.lastName=lastname;
18 contacts.sugarId=sid;
19 contacts.firstName=#"";
}
20 else {
21 firstname=[firstname stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[firstname substringToIndex:1] uppercaseString]];
22 lastname=[lastname stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[lastname substringToIndex:1] uppercaseString]];
23 contacts.firstName=firstname;
24 contacts.lastName=lastname;
25 contacts.sugarId=sid;
}
26 [searchArray addObject:contacts];
//searchArray=[NSMutableArray arrayWithObjects:contacts];
//TODO: Release contacts variable
27 [contacts release];
28 [sid release]; //not sure about releasing these objects..just gave a try
29 [firstname release];
30 [lastname release];
31 firstname = nil;
32 lastname = nil;
33 sid=nil;
}
34 sqlite3_reset(statement);
}
35 sqlite3_finalize(statement);
36 return searchArray;
}
I am releasing searchArray in dealloc method. The leaks are between lines 5,11-14,16,21,22.These lines vary whenever I try to fiddle with the code..please help me guys..waiting for your suggestions..
I tried using instruments and these are the areas figured out using it..Can I also use build and analyze in xcode..I used that and made some changes to the code..
EDIT (Added methods that code 1 refers)
- (id) initWithUsername: (NSString*) username andPassword: (NSString*) pass
{
if(self = [super init])
{
Soap *converter = [[Soap alloc] init];
SCRMsugarsoap *service = [[SCRMsugarsoap alloc] init];
[service get_server_version:self action:#selector(get_server_versionHandler:)];
self.user_name = username;
self.password = [converter tomd5:pass];
[converter release];
[service release];
}
return self;
}
-(NSString*)tomd5:(NSString*)value{
const char *cStr = [value UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(cStr, strlen(cStr), result);
return [NSString stringWithFormat: #"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7],
result[8], result[9], result[10], result[11], result[12], result[13], result[14], result[15]
];
}
If searchArray is an instance variable, and you call searchContacts more than once, you will leak the previous value stored in searchArray.
You need to do something like...
[searchArray release];
searchArray=[[NSMutableArray alloc] init];
Sending messages to nil objects has no effect, so if searchArray hasn't been set, calling release will do nothing. On subsequent calls, you will release search array before letting go of the pointer to it.
Edit: Also, you are over releasing sid, firstName and lastName. Objects returned by class convenience methods like that are almost always returned autoreleased. Take a look at the Memory Management Guide
Well, from in the first method you allocate an SCRMuser_auth that you don't hold a pointer to so that object will definitely leak.
I am not quite sure in your second section of code but I will keep looking over it.
I am trying to call iPhone zLib to decompress the zlib stream from our HTTP based server, but the code always stop after finishing the first zlib block.
Obviously, iPhone SDK is using the standard open Zlib. My doubt is that the parameter for inflateInit2 is not appropriate here.
I spent lots of time reading the zlib manual, but it isn't that helpful.
Here is the details, your help is appreciated.
(1) the HTTP request:
NSURL *url = [NSURL URLWithString:#"http://192.168.0.98:82/WIC?query=getcontacts&PIN=12345678&compression=Y"];
(2) The data I get from server is something like this (if decompressed). The stream was compressed by C# zlib class DeflateStream:
$REC_TYPE=SYS
Status=OK
Message=OK
SetID=
IsLast=Y
StartIndex=0
LastIndex=6
EOR
......
$REC_TYPE=CONTACTSDISTLIST
ID=2
Name=CTU+L%2EA%2E
OnCallEnabled=Y
OnCallMinUsers=1
OnCallEditRight=
OnCallEditDLRight=D
Fields=
CL=
OnCallStatus=
EOR
(3) However, I will only get the first Block. The code for decompression on iPhone (copied from a code piece from somewhere here) is as follow.
The loop between Line 23~38 always break the second time execution.
+ (NSData *) uncompress: (NSData*) data
{
1 if ([data length] == 0) return nil;
2 NSInteger length = [data length];
3 unsigned full_length = length;
4 unsigned half_length =length/ 2;
5 NSMutableData *decompressed = [NSMutableData dataWithLength: 5*full_length + half_length];
6 BOOL done = NO;
7 int status;
8 z_stream strm;
9 length=length-4;
10 void* bytes= malloc(length);
11 NSRange range;
12 range.location=4;
13 range.length=length;
14 [data getBytes: bytes range: range];
15 strm.next_in = bytes;
16 strm.avail_in = length;
17 strm.total_out = 0;
18 strm.zalloc = Z_NULL;
19 strm.zfree = Z_NULL;
20 strm.data_type= Z_BINARY;
21 // if (inflateInit(&strm) != Z_OK) return nil;
22 if (inflateInit2(&strm, (-15)) != Z_OK) return nil; //It won't work if change -15 to positive numbers.
23 while (!done)
24 {
25 // Make sure we have enough room and reset the lengths.
26 if (strm.total_out >= [decompressed length])
27 [decompressed increaseLengthBy: half_length];
28 strm.next_out = [decompressed mutableBytes] + strm.total_out;
29 strm.avail_out = [decompressed length] - strm.total_out;
30
31 // Inflate another chunk.
32 status = inflate (&strm, Z_SYNC_FLUSH); //Z_SYNC_FLUSH-->Z_BLOCK, won't work either
33 if (status == Z_STREAM_END){
34
35 done = YES;
36 }
37 else if (status != Z_OK) break;
38 }
39 if (inflateEnd (&strm) != Z_OK) return nil;
40 // Set real length.
41 if (done)
42 {
43 [decompressed setLength: strm.total_out];
44 return [NSData dataWithData: decompressed];
45 }
46 else return nil;
47 }
I had this issue and sorted it out. The code is slightly buggy as it breaks if Z_BUF_ERROR is returned, yet on reading the zlib Documentation it turns out that Z_BUF_ERROR should not be checked on inflation, as it can be thrown even if the resulting output is fine.
Changing the code thus worked:
// Inflate another chunk.
status = inflate (&strm, Z_SYNC_FLUSH);
if ( (status == Z_STREAM_END) || (status == Z_BUF_ERROR) )
done = YES;
Hope this works for you.
EDIT: (18th June 2011)
Here is the full inflation method, as requested. It is implemented as a category on NSData:
#interface NSData (NSDataExtension)
- (NSData *) zlibInflate;
#end
#implementation NSData (NSDataExtension)
- (NSData *)zlibInflate
{
if ([self length] == 0) return self;
unsigned full_length = [self length];
unsigned half_length = [self length] / 2;
NSMutableData *decompressed = [NSMutableData dataWithLength: full_length + half_length];
BOOL done = NO;
int status;
z_stream strm;
strm.next_in = (Bytef *)[self bytes];
strm.avail_in = [self length];
strm.total_out = 0;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
if (inflateInit (&strm) != Z_OK) return nil;
while (!done)
{
// Make sure we have enough room and reset the lengths.
if (strm.total_out >= [decompressed length])
[decompressed increaseLengthBy: half_length];
strm.next_out = [decompressed mutableBytes] + strm.total_out;
strm.avail_out = [decompressed length] - strm.total_out;
// Inflate another chunk.
status = inflate (&strm, Z_SYNC_FLUSH);
if (
(status == Z_STREAM_END) || (status == Z_BUF_ERROR)
)
done = YES;
else if (status != Z_OK) break;
}
if (inflateEnd (&strm) != Z_OK) return nil;
// Set real length.
if (done)
{
[decompressed setLength: strm.total_out];
return [NSData dataWithData: decompressed];
}
else return nil;
}
#end
Carlos