when it steps into NSString dataUsingEncoding method, crash happens very infrequently.
source code:
NSData *latin1Data = [appName dataUsingEncoding:NSUTF8StringEncoding];
call stack:
MACH_Exception Crashed with mach exception EXC_BAD_ACCESS
Thread 0 name: (null)
0 libobjc.A objc_object::release() (in libobjc.A.dylib)
1 CoreFoundation _common_removeAllObjects (in CoreFoundation) 188
2 CoreFoundation -[__NSArrayM dealloc] (in CoreFoundation) 28
3 libobjc.A (anonymous namespace)::AutoreleasePoolPage::pop(void*) (in libobjc.A.dylib) 704
4 libdispatch __dispatch_root_queue_drain (in libdispatch.dylib) 1148
5 libdispatch __dispatch_worker_thread3 (in libdispatch.dylib) 124
6 libsystem_pthread __pthread_wqthread (in libsystem_pthread.dylib) 1288
7 libobjc.A _objc_msgSend (in libobjc.A.dylib) 40
8 Foundation -[NSConcreteMutableData initWithLength:] (in Foundation) 316
9 Foundation -[NSString(NSStringOtherEncodings) dataUsingEncoding:allowLossyConversion:] (in Foundation)
10 xxxApp -[ xxxClass xxxMethod] xxxFile.mm line:300
line 300 of xxxFile.mm is:
NSData *latin1Data = [appName dataUsingEncoding:NSUTF8StringEncoding];
Edit, copied from comment:
295 -(NSString *)userAgentString {
296 NSBundle *bundle = [NSBundle bundleForClass:[self class]];
297 // Attempt to find a name for this application
298 NSString *appName = [bundle objectForInfoDictionaryKey:#"CFBundleName"];
299
300 NSData *latin1Data = [appName dataUsingEncoding:NSUTF8StringEncoding];
crashed at line 300 when called function userAgentString.
You should pull that information from the mailBundle of your application.
NSString *buildNumber = [[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleVersion"]
p.s:
Im surprised a private Class works. Seems you get a nil reference occasionally.
(Guessing here: Your class has an initialisation as well. If that one didn't finish in time, the runtime doesn't know the bundle the class belongs to?)
Related
This code seems to be causing a segmentation fault from time to time:
[[NSFileManager defaultManager] performSelectorOnMainThread:#selector(removeItemAtPath:error:) withObject:filePath waitUntilDone:YES];
I want to perform all operations on files in the main thread to avoid conflicts like removing a file while the whole folder is iterated.
It produces this error:
Exception Type: SIGSEGV
Exception Codes: SEGV_ACCERR at 0x1084
Application Specific Information:
objc_msgSend() selector name: release
This is the stack trace of the crashed main thread:
Thread 0 Crashed:
0 libobjc.A.dylib 0x39fc8636 objc_msgSend + 22
1 Foundation 0x30214c67 __NSThreadPerformPerform + 452
2 CoreFoundation 0x2f7f6fef __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 12
3 CoreFoundation 0x2f7f64b7 __CFRunLoopDoSources0 + 204
4 CoreFoundation 0x2f7f4ca7 __CFRunLoopRun + 628
5 CoreFoundation 0x2f75f769 CFRunLoopRunSpecific + 522
6 CoreFoundation 0x2f75f54b CFRunLoopRunInMode + 104
7 GraphicsServices 0x346bc6d3 GSEventRunModal + 136
8 UIKit 0x320be891 UIApplicationMain + 1134
9 Pocket3 0x00050243 main (main.m:4)
10 libdyld.dylib 0x3a4bcab7 start + 0
What am I doing wrong?
It looks like the NSFileManager is deallocated too early, but how can it be if it is a singleton?
Could it have something to do with the method [NSFileManager defaultManager] which is said to not be thread safe?
Update: new answer
NSFileManager is threadsafe (as long as you are not using its delegate, which you don't, and which you shouldnt do with the -defaultManager anyways). You can just call [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error] on whatever thread you are currently on. There is no advantage on doing it on the main thread only. In fact, performance will probably better if you update the filesystem in a background thread, because the UI will not block if the operation takes longer than expected.
Old answer (why the crash did happen)...
The method -removeItemAtPath:error: wants two objects, but you are providing only one. So the second paramter (NSError **) that the -removeItemAtPath:error: method will see, is just some garbage that lies next to the filePath pointer in memory.
There is no version of -performSelectorOnMainThread:... that takes two objects. You may use dispatch_sync instead:
dispatch_sync(dispatch_get_main_queue(), ^() {
NSError *error = nil;
BOOL ok = [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
if(!ok) {
NSLog(#"an error happened: %#", error);
}
}
I'm currently banging my head around this problem:
I have two views on the same entity. The first one lets the user CRUD the Entity (TouchModelVariable), the second one lets the user assign it to a another entity (TouchModelConstraintTerm). The second view is only for selection. But when I delete entities via the first view, upon scrolling in the second view the app crashes with an "index out of bounds" error.
Detailed explanation: First the first controller, the CRUD one.
MSPUIManagedDocument *doc = self.document;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:MODEL_ENTITY_TOUCH_MODEL_VARIABLE inManagedObjectContext:doc.managedObjectContext];
fetchRequest.entity = entityDescription;
fetchRequest.fetchBatchSize = 20;
//[NSComparisonPredicate predicateWithLeftExpression:[NSExpression expressionForKeyPath:#"touchModel.active"] rightExpression:[NSExpression expressionForConstantValue:YES] modifier:NSDirectPredicateModifier type:nil options:nil];
// touchModel.active == 1
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"touchModel == %#", self.touchModel, nil];
NSSortDescriptor *sortDescriptior = [NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES selector:#selector(caseInsensitiveCompare:)];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptior];
fetchRequest.sortDescriptors = sortDescriptors;
// nameSectionIndex
NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:doc.managedObjectContext sectionNameKeyPath:#"name" cacheName:#"MSPVariablesManagementTableViewController"];
fetchedResultsController.delegate = self;
NSError *error = nil;
[NSFetchedResultsController deleteCacheWithName:#"MSPVariablesManagementTableViewController"];
if(![fetchedResultsController performFetch:&error]) {
NSLog(#"Error while fetching <%#>, <%#>", error, [error userInfo]);
}
return fetchedResultsController;
The TableView is bound to that controller, as it's described in the book "Pro CoreData for iOS".
The second view uses nearly the same code, but the CacheKeys are different. If I delete entities with the first view, and then navigate through the app to the second view (which is re-instantiated every time) the app crashes upon scrolling, because it assumes that the deleted records are there.
I also tried to save the ManagedObjectContext, before entering the second view.
CRASH: *** -[_PFArray objectAtIndex:]: index (8) beyond bounds (8)
2012-03-17 11:36:48.953 MSPLPSolve[38685:fb03] Stack Trace: (
0 CoreFoundation 0x0192503e __exceptionPreprocess + 206
1 libobjc.A.dylib 0x01dc2cd6 objc_exception_throw + 44
2 CoreFoundation 0x018cda48 +[NSException raise:format:arguments:] + 136
3 CoreFoundation 0x018cd9b9 +[NSException raise:format:] + 57
4 CoreData 0x003ffc23 -[_PFArray objectAtIndex:] + 131
5 CoreData 0x004ec260 -[NSFetchedResultsController objectAtIndexPath:] + 448
6 MSPLPSolve 0x0005d820 -[MSPUtilitiesVariablesSelectionTableViewController configureCell:cellForRowAtIndexPath:] + 128
7 MSPLPSolve 0x0003057b -[MSPFetchedResultsTableViewController tableView:cellForRowAtIndexPath:] + 283
8 UIKit 0x008efc54 -[UITableView(UITableViewInternal) _createPreparedCellForGlobalRow:withIndexPath:] + 494
9 UIKit 0x008f03ce -[UITableView(UITableViewInternal) _createPreparedCellForGlobalRow:] + 69
10 UIKit 0x008dbcbd -[UITableView(_UITableViewPrivate) _updateVisibleCellsNow:] + 1350
11 UIKit 0x008ea6f1 -[UITableView layoutSubviews] + 242
12 UIKit 0x00893d21 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 145
... a load of other stuff not in my code ...
BUT when I save the document completly (closing, reopening) between deleting entities via the first controller and navigating to the second controller - it doesn't crash. Is NSFetchedResultsController caching a loads of stuff in the background? And is there a in depth guide how the caching works and how I have to use it?
Puuuh, thanks for reading this far! Regardless if you have an idea or not!
Mark
Did you do a performFetch on your results controller after you altered the model? Also I'm assuming your results controllers delegate methods are implemented correctly.
So I have an application which uses an NSTimer. The problem is that when the NSTimer runs, my application will crash with EXC_BAD_ACCESS. I only just started with objective-c so I don't know how to properly debug it. If I thought call the -(void)logIn{} with [self logIn]; the application will work.
My code:
.h
#interface DJ_WAppDelegate : NSObject {
NSTimer *loginTimer;
}
-(void)logIn;
#end
.m
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[self logIn]; // this works
loginTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(logIn) userInfo:nil repeats:YES]; // this fails
}
- (void)logIn {
NSLog(#"Logging in...");
// if I comment out these 2 lines it works with the NSTimer!?... (I've would have more code below)
NSURL *loginConn = [NSURL URLWithString:[NSString stringWithFormat:#"some-website.com"]];
NSInteger loginReturn = [[NSString stringWithContentsOfURL:loginConn encoding:NSASCIIStringEncoding error:nil] intValue];
// when "loginReturn" return "OK" the timer (loginTimer) will be stopped with: [loginTimer invalidate];
// more code would be below... (which works!)
}
So the problem is with the NSURL it think.
Thanks for helping.
EDIT 1:
Here's the crash stack:
EException Type: EXC_BAD_ACCESS (SIGBUS)
Exception Codes: KERN_PROTECTION_FAILURE at 0x0000000000000020
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Application Specific Information:
objc_msgSend() selector name: respondsToSelector:
Thread 0 Crashed: Dispatch queue: com.apple.main-thread
0 libobjc.A.dylib 0x9603bed7 objc_msgSend + 23
1 com.apple.CoreFoundation 0x922ed5f2 _CFStringAppendFormatAndArgumentsAux + 3138
2 com.apple.CoreFoundation 0x922ec979 _CFStringCreateWithFormatAndArgumentsAux + 105
3 com.apple.Foundation 0x9656ebfb -[NSPlaceholderString initWithFormat:locale:arguments:] + 163
4 com.apple.Foundation 0x9656eaae +[NSString stringWithFormat:] + 88
5 com.who.DJ-W 0x00001d56 -[DJ_WAppDelegate logIn] + 116 (DJ_WAppDelegate.m:108)
6 com.apple.Foundation 0x965b08d4 __NSFireTimer + 141
7 com.apple.CoreFoundation 0x922ffadb __CFRunLoopRun + 8059
8 com.apple.CoreFoundation 0x922fd464 CFRunLoopRunSpecific + 452
9 com.apple.CoreFoundation 0x922fd291 CFRunLoopRunInMode + 97
10 com.apple.HIToolbox 0x91646e04 RunCurrentEventLoopInMode + 392
11 com.apple.HIToolbox 0x91646bb9 ReceiveNextEventCommon + 354
12 com.apple.HIToolbox 0x91646a3e BlockUntilNextEventMatchingListInMode + 81
13 com.apple.AppKit 0x9265378d _DPSNextEvent + 847
14 com.apple.AppKit 0x92652fce -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 156
15 com.apple.AppKit 0x92615247 -[NSApplication run] + 821
16 com.apple.AppKit 0x9260d2d9 NSApplicationMain + 574
17 com.who.DJ-W 0x00001c92 start + 54
hope this helps... to find the error
EDIT 2:
With the Zombie Mode on I get this: *** -[CFString respondsToSelector:]: message sent to deallocated instance 0x46d550 I hope this helps.
EDIT 3:
To Ball: Here is the original URL (took away the domain here) /DJW/work.php?user=iBlackbirdi&udid=00000000-0000-1000-80005&key=660e5744e&cmd=slocau&type=get
There are several problems here:
djwLog is a class method so you should call it on the class not the instance
like this: [[self class] djwLog:#"foo bar"]
The URLFromString: method needs the string to contain a valid URL as specified by RFC 1808. Something along the lines of [NSURL URLFromString:#"http://example.com/foo"]
stringWithContentsOfURL:url… is a syncornous method. Unless you have this code running in a separate thread you should not use this. Look at NSURLConnection for a class to asynchronously load data from a URL. Using synchronized calls for this is a bad idea. Always.
intValue returns a signed integer. To get a NSInteger use integerValue. Also if you use stringWithContentsOfURL make sure to check if it's result is nil before calling
integerValue otherwise you might get a result of 0 if the URL call failed or did not return data. A real parser for the API you are calling would be a good idea in any case.
You're calling a class method as if it was an instance method:
[self djwLog:#"Logging in..."];
Since there is no instance-method named djwLog the application crashes. You should either call NSLog directly, make it an instance-method - or preferably make a macro for logging:
#ifdef DEBUG
# define DLog(...) NSLog(#"%s %#", __PRETTY_FUNCTION__, [NSString stringWithFormat:__VA_ARGS__])
#else
# define DLog(...) do { } while (0)
#endif
If you instead of NSLog write DLog - it will only be logging when DEBUG-flag has been defined. In addition to this, it will log the origin of the log message - so you can see which class/method the log entry came from.
The following code for initialization of array works ::
NSArray *array = [[NSArray alloc] initWithObjects:#"Toy Story 3",#"Inception",nil];
self.list = [array sortedArrayUsingSelector:#selector(compare:)];
[array release];
[super viewDidLoad];
But the following code doesnt. The iPhone Simulator Terminates as soon as I try to scroll the Table View which i used to view the array. (Only after i scroll onto empty tableViewCells)
NSBundle *bundle = [NSBundle mainBundle];
NSString *plistPath = [bundle pathForResource:#"MovieList" ofType:#"plist"];
NSMutableArray *array = [[NSMutableArray alloc] initWithContentsOfFile:plistPath];
NSLog([array objectAtIndex:1]);
self.list = [array sortedArrayUsingSelector:#selector(compare:)];
[array release];
[super viewDidLoad];
This was an example app from the Book "Beginning iPhone Development" by Dave Mark. In the example , they have initialized the array within the code, while i have tried to initialize it from a external file.
The console Log ::
2010-12-22 20:57:43.772 Nav[2474:40b] WARNING: Using legacy cell layout due to delegate implementation of tableView:accessoryTypeForRowWithIndexPath: in <RootViewController: 0x9908870>. Please remove your implementation of this method and set the cell properties accessoryType and/or editingAccessoryType to move to the new cell layout behavior. This method will no longer be called in a future release.
2010-12-22 20:58:12.480 Nav[2474:40b] WARNING: Using legacy cell layout due to delegate implementation of tableView:accessoryTypeForRowWithIndexPath: in <DisclosureButtonController: 0x9b32ab0>. Please remove your implementation of this method and set the cell properties accessoryType and/or editingAccessoryType to move to the new cell layout behavior. This method will no longer be called in a future release.
2010-12-22 20:59:13.299 Nav[2474:40b] -[UIDeviceRGBColor length]: unrecognized selector sent to instance 0x9b3d900
2010-12-22 20:59:13.301 Nav[2474:40b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIDeviceRGBColor length]: unrecognized selector sent to instance 0x9b3d900'
*** Call stack at first throw:
(
0 CoreFoundation 0x00db2be9 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x00f075c2 objc_exception_throw + 47
2 CoreFoundation 0x00db46fb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x00d24366 ___forwarding___ + 966
4 CoreFoundation 0x00d23f22 _CF_forwarding_prep_0 + 50
5 UIKit 0x0051a9ca -[UITableViewCellLayoutManager layoutSubviewsOfCell:] + 3424
6 UIKit 0x00482e02 -[UITableViewCell layoutSubviews] + 95
7 QuartzCore 0x01c70451 -[CALayer layoutSublayers] + 181
8 QuartzCore 0x01c7017c CALayerLayoutIfNeeded + 220
9 QuartzCore 0x01c6937c _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 310
10 QuartzCore 0x01c690d0 _ZN2CA11Transaction6commitEv + 292
11 QuartzCore 0x01c997d5 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 99
12 CoreFoundation 0x00d93fbb __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 27
13 CoreFoundation 0x00d290e7 __CFRunLoopDoObservers + 295
14 CoreFoundation 0x00cf1bd7 __CFRunLoopRun + 1575
15 CoreFoundation 0x00cf1240 CFRunLoopRunSpecific + 208
16 CoreFoundation 0x00cf1161 CFRunLoopRunInMode + 97
17 GraphicsServices 0x016e7268 GSEventRunModal + 217
18 GraphicsServices 0x016e732d GSEventRun + 115
19 UIKit 0x002ca42e UIApplicationMain + 1160
20 Nav 0x00002598 main + 102
21 Nav 0x00002529 start + 53
)
terminate called after throwing an instance of 'NSException'
enter code here
It sounds like this is a perfect job for the debugger, doesn't it? Why not set a breakpoint on the first line and make sure nothing is unexpectedly nil or out of bounds as you step through and inspect your variables? Perhaps paying attention to the error that's undoubtedly logged to the console might be helpful, too?
Given you've mentioned neither the line on which it terminates nor any log messages, this is about as specific as anyone can get.
The first argument to NSLog needs to be an NSString. The object you're passing to it appears to be part of the UIColor cluster. I suggest you change to:
NSLog(#"%#", [array objectAtIndex:1]);
So the first argument is definitely a string and it says just to print a description of whichever object is the next argument.
Instrument reports leak for this simple use of NSURLConnection:
#import <Foundation/Foundation.h>
int main (int argc, char ** argv)
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSURLRequest *theRequest = [NSURLRequest
requestWithURL:[NSURL URLWithString:#"https://gmail.com/"]
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:60.0];
[NSURLConnection connectionWithRequest:theRequest delegate:nil];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:5]];
[pool drain];
[NSThread sleepForTimeInterval:10]; // wait for Instruments to check
}
Leak stack trace:
0 CoreFoundation __CFBasicHashRehash
1 CoreFoundation CFDictionaryCreate
2 CFNetwork _getConnectionInfoForProxy
3 CFNetwork HTTPProtocol::createStream()
4 CFNetwork HTTPProtocol::createAndOpenStream()
5 CFNetwork executionContextPerform(void*)
6 CoreFoundation __CFRunLoopDoSources0
7 CoreFoundation __CFRunLoopRun
8 CoreFoundation CFRunLoopRunSpecific
9 CoreFoundation CFRunLoopRunInMode
10 Foundation +[NSURLConnection(NSURLConnectionReallyInternal) _resourceLoadLoop:]
11 Foundation -[NSThread main]
12 Foundation __NSThread__main__
13 libSystem.B.dylib _pthread_start
14 libSystem.B.dylib thread_start
It doesn't leak if the URL is just normal http and it doesn't redirect to a https site.
How do I fix the leak?
I'm using Snow Leopard and I have proxies on for both http and https.
I think you're asking the wrong questions. Here's what you should be asking:
Am I following the memory management rules?
If I am, do I need to worry about this?
In your case, the answers are (respectively) "Yes" and "No". It's quite possible that you have found a memory leak in the Cocoa frameworks. However in this case, I don't think you have. You see, the NSRunLoop for the current thread retains the NSURLConnection, so it's possible that you're just not giving the run loop enough time to release the connection or something.
The point is, you're not doing anything wrong, so Don't Panic.