Hey this may be a stupid question but I couldn't find the answer anywhere, apologies if the answer is easily found and if my research skills are pants.
anyway is it possible to generate a crash report when an app doesn't crash? so say if a user encounters a bug could there be an option to allow them to generate a crash report which can then be sent to me? also how would I go about doing this?
Thanks for any help :)
I have used it couple of times when I had to print stack trace:
+ (NSArray *)backtrace
{
void* callstack[128];
int frames = backtrace(callstack, 128);
char **strs = backtrace_symbols(callstack, frames);
int i;
NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames];
for (
i = UncaughtExceptionHandlerSkipAddressCount;
i < UncaughtExceptionHandlerSkipAddressCount +
UncaughtExceptionHandlerReportAddressCount;
i++)
{
[backtrace addObject:[NSString stringWithUTF8String:strs[i]]];
}
free(strs);
return backtrace;
}
"When an application crashes on the iPhone, it disappears without telling the user what happened. However, it is possible to add exception and signal handling to your applications so that an error message can be displayed to the user or you can save changes. It is even possible to try to recover from this situation without crashing at all."
Look at http://cocoawithlove.com/2010/05/handling-unhandled-exceptions-and.html
Here's what I use for my stacktraces:
NSArray *callStackArray = [exception callStackReturnAddresses];
int frameCount = [callStackArray count];
void *backtraceFrames[frameCount];
for (int i=0; i < frameCount; i++) {
backtraceFrames[i] = (void *)[[callStackArray objectAtIndex:i] unsignedIntegerValue];
}
char **strs = backtrace_symbols(backtraceFrames, frameCount);
NSMutableArray *backtraceArray = [NSMutableArray arrayWithCapacity:frameCount];
for (int i = 0; i < frameCount; i++) {
NSString *entry = [NSString stringWithUTF8String:strs[i]];
[backtraceArray addObject:entry];
}
free(strs);
You just have to make sure you don't do any harm to your app: http://landonf.bikemonkey.org/2011/09/14. You could also use PLCrashReporter to handle all your crashes or if you're lazy like me, use a service like Crittercism
I used to use backtrace_symbols for handling my crashes too, but then I found out that it could be dangerous since the method is not async-safe. I've since looked at a bunch of crash reporting solutions and went with Crittercism for my apps and it's been pretty sweet!
I suggest you check out TestFlight SDK released a few days ago. It has some awesome features like remote logging and even live crash reports.
For an ad hoc version, you could just call the function abort(), or throw and exception of some kind.
An App Store version will not be allowed to ship if it crashes at all during testing.
Related
So I'm working on a simple calculator program to get used to cocoa and objective C. I've redone the whole thing multiple times and every time I finish coding, the first time i build it, it works fine, but every time after that the window wont launch and it gives me these errors:
2013-01-11 10:32:14.760 Visual Caluclator Fix[39892:403] *** Assertion failure in -[NSTextFieldCell _objectValue:forString:errorDescription:], /SourceCache/AppKit/AppKit-1138.47/AppKit.subproj/NSCell.m:1564
2013-01-11 10:32:14.762 Visual Caluclator Fix[39892:403] Ignoring exception raised in __-[NSPersistentUIManager restoreAllPersistentStateWithTalagentWindows:registeringAsReadyWhenDone:completionHandler:]_block_invoke_3: Invalid parameter not satisfying: aString != nil
I've concluded that the problem lies in my textEdited method, because when I comment the code inside of it out, the program has no issues running; however, I have no idea why this is, or why it would run the first time and not any subsequent times. When I put in an exception breakpoint, it points me to the one line in the updateUI method and the call to [self updateUI] in the textEdited method. The following code is the textEdited method and the other methods it references.(I'm fairly sure there's nothing wrong with the solve method because I used it in a command prompt calculator and it worked great. Also, I know this is a pretty convoluted way to program a calculator, with the strings and everything, but I was just trying to integrate the code I already had for the command prompt program into a cocoa program.)
In the AppDelegate class:
- (void)updateUI{
[self.calculationView setStringValue: self.calculation.calcString];//Exception breakpoint points here
}
- (IBAction)textEdited:(id)sender {
self.calculation.calcString = self.calculationView.stringValue;
[self.calculation solve];
[self updateUI];//Exception breakpoint points here
}
In the Calculation class:
- (NSString*)solve{
for (int i = 0; i < [self.calcString length]; i++) {
NSRange nextChar = NSMakeRange(i, 1);
if ([[self.calcString substringWithRange: nextChar] isEqualToString: #"*"]||
[[self.calcString substringWithRange: nextChar] isEqualToString: #"/"])
[self calcTerm: i];
}
for (int i = 0; i < [self.calcString length]; i++) {
NSRange nextChar = NSMakeRange(i, 1);
if ([[self.calcString substringWithRange: nextChar] isEqualToString: #"+"]||
[[self.calcString substringWithRange: nextChar] isEqualToString: #"-"])
[self calcTerm: i];
}
return self.calcString;
}
This might help with your problem:
http://www.raywenderlich.com/10505/my-app-crashed-now-what-part-2
The site explains how assertion errors work and demonstrate how you would fix an error like that.
It sounds to me like something in calcTerm: is setting calcString to nil. Thus, when you retrieve it later to set the field's string value to it, you end up setting the field's string value to nil, which it doesn't like.
You can check this by logging the value of calcString just before the end of solve. Then, start stringing up log statements and/or breakpoints in calcTerm: to find out how you're swapping out your string for nil.
I use simpleFTP to request document information. I detect memory-leak with instrument as below:
And in the call tree I find out where is the memory leak happened:
The method "_parseListData" as below:
- (void)_parseListData
{
NSMutableArray * newEntries;
NSUInteger offset;
// We accumulate the new entries into an array to avoid a) adding items to the
// table one-by-one, and b) repeatedly shuffling the listData buffer around.
newEntries = [NSMutableArray array];
assert(newEntries != nil);
offset = 0;
do {
CFIndex bytesConsumed;
CFDictionaryRef thisEntry;
thisEntry = NULL;
assert(offset <= self.listData.length);
bytesConsumed = CFFTPCreateParsedResourceListing(NULL, &((const uint8_t *) self.listData.bytes) [offset], self.listData.length - offset, &thisEntry);
if (bytesConsumed > 0) {
........
}
I don't know how to fix this problem.
The method "CFFTPCreateParsedResourceListing" is a system method and it create __NSDate (look at the second pic).
This is where the memory-leak happen.
The CFFTPCreateParsedResourceListing function returns a CFDictionary into the thisEntry variable, which presumably contains the NSDate objects.
The code should call CFRelease on thisEntry once it is finished with it:
// once we're done with thisEntry
if (thisEntry) {
CFRelease(thisEntry);
}
Old post, but useful solution. You can find the answer here BlackRaccoon ftp client.
According to the creator the CFFTPCreateParsedResourceListing method retains twice the NSDate, to override the issue add the next code, be aware of the comments here:
FAQ section
"Actually, in WhiteRaccoon, if you list a directory you will leak NSDate's. The function CFFTPCreateParsedResourceListing in Apple's SDK has a leak in it. I've attempted to "patch" this, however it isn't guaranteed to work. For OS 5.1 it does work."
........
if (parsedBytes > 0)
{
if (listingEntity != NULL)
{
//----- July 10, 2012: CFFTPCreateParsedResourceListing had a bug that had the date over retained
//----- in order to fix this, we release it once. However, just as a precaution, we check to see what
//----- the retain count might be (this isn't guaranteed to work).
id date = [(__bridge NSDictionary *) listingEntity objectForKey: (id) kCFFTPResourceModDate];
if (CFGetRetainCount((__bridge CFTypeRef) date) >= 2)
CFRelease((__bridge CFTypeRef) date);
this works for me
I am new to IPhone programming and am I having trouble solving the following memory leak.
while(numDeckCounter < numDecks){
int cardCounter=1;
for (int i =1; i<=52; i++) {
tempCard = [Card new]; //leaks tool says that this is leaking object
if(i>=1 && i<=13)
{
tempCard.suit = CLUBS;
tempCard.faceValue = cardCounter;
[deckArr addObject:tempCard]; //reference count 2
cardCounter++;
}
else if(i>=14 && i<=26)
{
tempCard.suit = DIAMONDS;
tempCard.faceValue = cardCounter;
[deckArr addObject:tempCard];
cardCounter++;
}
else if(i>=27 && i<=39)
{
tempCard.suit = HEARTS;
tempCard.faceValue = cardCounter;
[deckArr addObject:tempCard];
cardCounter++;
}
else
{
tempCard.suit = SPADES;
tempCard.faceValue = cardCounter;
[deckArr addObject:tempCard];
cardCounter++;
}
if(cardCounter ==14){
cardCounter=1;
}
[tempCard release]; //this causes an EXC_BAD_ACCESS -reference count should be 1
}
numDeckCounter++;
}
I was under the impression that adding an object to the array would increase its reference count by one, then it would be safe to release the object you just added because it would not be deallocated until the array was released bumping which would then release each object in the array. This is when the object should finally be deallocated.
When I add the [tempCard release]; it crashes my app because it can't access the memory location because it has already been deallocated.
From everything I have read, I think what I said above is true. Someone please correct me if I am wrong. Thanks.
I don't see any leaks in the code you presented. (There are some opportunities to slim it down, though, say by moving the identical operations out of the conditionals).
The Leaks tool output is pretty tricky to read. Is it possible that the Card object is leaking one of it's ivars?
Instead of leaks, run static analysis on your product (Product->Analyze). I think it will flag a different part of your code.
Perhaps try [[Card alloc] init] instead of [Card new]. This is just a guess. However trying the IMO more common method of object creation could be helpful.
Check this out: Use of alloc init instead of new
You could also try removing all the code for adding the Cards to the array. So you'd essentially have:
card = [Card new];
[card release];
This could help you find memory issues associated w/ the array retaining the object perhaps?
I am programming an iPhone App which is supposed to parse a flat-file from the web, create managed objects from the flat-file and later on should display them in an UITableView.
There are no problems with the saving and the displaying, but I just can't get the hang of a good Parser.
Thats the file I want to parse: Flat-file
AS far as I know, I can't use the NSXMLParser for this task (because obviously there are no tags).
So I at first tried to programm a NSScanner which should get me the interesting properties --> didn't work out
Now I am using this method:
- (void) parseMemberDataWithURL: (NSString *)urlString
{
self.memberTempCounter = 1;
//Get data from web
self.downloadedText = [NSString stringWithContentsOfURL: [NSURL URLWithString: urlString] encoding:NSUTF8StringEncoding error:nil ];
memberArray = [downloadedText componentsSeparatedByString:#";"];
while (self.memberTempCounter<[memberArray count])
{
[[ExhibitorController sharedController] createExhibitorWithName:[memberArray objectAtIndex:self.memberTempCounter]
street:[memberArray objectAtIndex:self.memberTempCounter+2]
zip:[memberArray objectAtIndex:self.memberTempCounter+3]
city:[memberArray objectAtIndex:self.memberTempCounter+4]
email:[memberArray objectAtIndex:self.memberTempCounter+7]
phone:[memberArray objectAtIndex:self.memberTempCounter+5]
website:[memberArray objectAtIndex:self.memberTempCounter+8]
produktbereiche:[[memberArray objectAtIndex:self.memberTempCounter+9] componentsSeparatedByString:#","]];
self.memberTempCounter= self.memberTempCounter+13;
}
}
I am using the memberTempCounter to identify the property.
The problems are:
This only works out in like 3 of 4 times.1 of 4 times the App crashes and I have no Idea why...
The method has a performance like a 1962 VW Beetle. Parsing the whole chunk of data takes up to 3 Minutes on my iPhone 3G
Any Ideas or a simpler way to do this?
I would be really gratefull. Thanks in advance: -)
You might as well do all the parsing in the background, and then display as the information gets parsed.
As for memory issues, try doing temporary autorelease pools and release every 50 or so iterations through the loop.
int count = 0;
NSAutoreleasePool * loopPool = [[NSAutoreleasePool alloc] init];
while(someInsanelyLargeCondition){
// Do your stuff here
// .............
count++;
if (count > 50) {
count = 0;
[loopPool release];
loopPool = [[NSAutoreleasePool alloc] init];
}
}
Recursive-descent (LL1) parsers are pretty simple, light on memory, and for speed they go almost as fast as you can run a pointer through characters. Building your data structure would probably be the dominant time-taker.
I was finally able to fix my performance problem.
I have a method in another class, which ads Tags for the different Exhibitors. Therefore it first checks if the Tag already is stored in the database or else creates it.
With an growing Set of Tags in my database the search-process took longer and longer and this led to the long parsing time.
Anyone else having this problem: Take a look at the Performance Core Data Programming guide of apple in the "Implementing Find-or-Create Efficiently"-section:
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CoreData/Articles/cdImporting.html
I want my app to do something when the last NSLog has a certain string. I thought I could realize this with an if-query and isEqualtoString, but how can I make this?
Sorry for my bad English ;)
Maybe I don't understand what you're trying to do, but you can just create the string somewhere, log it, and then test it:
NSInteger _someInt = 2;
NSString *_someString = #"bananas";
NSString *_stringToBeLogged = [NSString stringWithFormat:#"%d %#", _someInt, _someString];
NSLog(#"%#", _stringToBeLogged);
if ([_stringToBeLogged isEqualToString:#"2 bananas"]) {
NSLog(#"I logged two bananas...");
}
You could consider creating your own custom log function which calls NSLog() after checking for your string constant. This would keep your code a bit cleaner if you want this functionality in multiple places and also allows you to easily extend the logging function further if desired.