I have a class with a property
#property (nonatomic, copy) MyObject *currentObject;
and a function that looks like this:
- (void)handleExternalChange {
#synchronized (self) {
MyObject *newObject = [self.externalStore getObject];
//Business logic...
self.currentObject = newObject;
}
}
I am seeing a crash objc_msgSend() selector name: copyWithZone: occasionally when i hit the self.currentObject = newObject line.
I presume this is because the externalStore released the object returned by getObject on another thread and by the time it got down to the setter it was gone.
Does this conclusion seem right? If so is there a recommended way to fix this?
UPDATE:
Here's some of the stack trace
Application Specific Information:
objc_msgSend() selector name: copyWithZone:
0 libobjc.A.dylib 0x000000018149ef30 objc_msgSend + 16
1 libobjc.A.dylib 0x000000018149c2d4 objc_setProperty_nonatomic_copy + 44
2 MyApp 0x0000000100115cb4 -[MyClass handleExternalChange] (MyClass.m:117)
3 CoreFoundation 0x00000001829ee22c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 16
4 CoreFoundation 0x00000001829ed930 _CFXRegistrationPost + 396
5 CoreFoundation 0x00000001829ed6ac ___CFXNotificationPost_block_invoke + 56
6 CoreFoundation 0x0000000182a5cb9c -[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1500
7 CoreFoundation 0x000000018292fbf4 _CFXNotificationPost + 372
8 Foundation 0x00000001834366bc -[NSNotificationCenter postNotificationName:object:userInfo:] + 64
MyObject *newObject = [self.externalStore getObject];
That method shouldn't be named get* anything, but that isn't likely to be the cause of the issue. Nor is it likely to be a threading issue (at least not directly).
This sounds more like there is some state related to the copyWithZone: that isn't handled correctly. How is the copy method implemented? Specifically, is it correctly copying all state and bumping reference counts or does it try to cheat by doing some kind of a byte copy?
Related
Fabric found that the NSMutableArray found crash when calling removeAllObjects.
Most of the crash happened in iOS9. This is my code, crash in [self.recommentGoodsArray removeAllObjects]:
- (void)clickColorWithIndex:(NSUInteger)index {
[self.recommentGoodsArray removeAllObjects];
[self.tableView reloadData];
GoodsInfo *gInfo = [self.goodsInfo.relatedGoodsArray objectAt:index];
self.goods_id = gInfo.goods_id;
[self loadGoodsDetail];
}
Fabric Latest Session
Crashed: com.apple.main-thread
0 libobjc.A.dylib 0x22d2a94e realizeClass(objc_class*) + 25
1 libobjc.A.dylib 0x22d2aa15 realizeClass(objc_class*) + 224
2 libobjc.A.dylib 0x22d2aa15 realizeClass(objc_class*) + 224
3 libobjc.A.dylib 0x22d2d91b lookUpImpOrForward + 158
4 libobjc.A.dylib 0x22d2d873 _class_lookupMethodAndLoadCache3 + 34
5 libobjc.A.dylib 0x22d33cfb _objc_msgSend_uncached + 26
6 CoreFoundation 0x2357e523 -[__NSArrayM removeAllObjects] + 266
7 ZZKKO 0x19f781 -[GoodsDetailVC clickColorWithIndex:] (GoodsDetailVC.m:825)
You have a crash in _objc_msgSend_uncached. It's likely that you are addressing deallocated object. It cat either be recommentGoodsArray, or self.
You need to check following:
Is recommentGoodsArray declared strong or weak? It has to be
strong.
Is it possible for this method to be called after VC was destroyed (example: from a timer or in a callback from an UIAlertView). If so, you have to retain self until the moment your function is done working with self.
You can try if self.recommentGoodsArray has objects before removing it.
if ([self.recommentGoodsArray count]){
[self.recommentGoodsArray removeAllObjects];
}
I have a legacy app which utilizes Apple's example SimplePing. There is a source file SimplePing.m which contains the next method:
- (void)sendPingWithData:(NSData *)data {
id<SimplePingDelegate> strongDelegate;
...
strongDelegate = self.delegate;
if (...) {
[strongDelegate simplePing:self didSendPacket:...];
}
self.nextSequenceNumber += 1; // CRASH
if (self.nextSequenceNumber == 0) {
self.nextSequenceNumberHasWrapped = YES;
}
}
Crashlytics reports dozens of crashes with stack trace:
Crashed: com.apple.main-thread
EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0x00000009de3bbeb8
libobjc.A.dylib objc_msgSend + 16
MyApp SimplePing.m line 313 -[SimplePing sendPingWithData:]
Foundation __NSFireTimer + 88
CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 28
CoreFoundation __CFRunLoopDoTimer + 856
CoreFoundation __CFRunLoopDoTimers + 244
CoreFoundation __CFRunLoopRun + 1484
CoreFoundation CFRunLoopRunSpecific + 424
GraphicsServices GSEventRunModal + 100
UIKit UIApplicationMain + 208
MyApp main.swift line 10
libdyld.dylib start + 4
I have not managed to reprodice it yet, and I know a little about this app so far. But I have to begin researching it somehow. I looked through realization of delegates (btw, they are in Swift - if it's relevant), bit did not find anything criminal so far.
As I know, EXC_BAD_ACCESS normally fires when one tries to access deallocated memory. In this concrete case it could mean that [strongDelegate simplePing:self didSendPacket:...] has somehow deallocated self. But as self is a strong reference, it just could not happen at all - am I right?
May you guys drop me some probable scenarios on how could it crash with EXC_BAD_ACCESS on that line? The only my idea is that some memory overwrite have happened.
UPDATE
I was completely wrong with my assumption "But as self is a strong reference ...". self in nether strong, nor weak. It is just unsafe_unretained, as a smart guy explained: https://stackoverflow.com/a/18011581/674548.
I recently received a crash report that looks like this:
0 libobjc.A.dylib 0x0000000193dfea88 object_cxxDestructFromClass(objc_object*, objc_class*) + 0
1 libobjc.A.dylib 0x0000000193e0bf34 objc_destructInstance + 88
2 libobjc.A.dylib 0x0000000193e0bf8c object_dispose + 24
3 My App 0x00000001000d88fc -[CCAction dealloc] + 44
4 My App 0x00000001000e6bf8 -[CCActionSequence .cxx_destruct] + 36
5 libobjc.A.dylib 0x0000000193dfeb18 object_cxxDestructFromClass(objc_object*, objc_class*) + 144
6 libobjc.A.dylib 0x0000000193e0bf34 objc_destructInstance + 88
7 libobjc.A.dylib 0x0000000193e0bf8c object_dispose + 24
8 My App 0x00000001000d88fc -[CCAction dealloc] + 44
9 My App 0x00000001000e6bf8 -[CCActionSequence .cxx_destruct] + 36
10 libobjc.A.dylib 0x0000000193dfeb18 object_cxxDestructFromClass(objc_object*, objc_class*) + 144
11 libobjc.A.dylib 0x0000000193e0bf34 objc_destructInstance + 88
12 libobjc.A.dylib 0x0000000193e0bf8c object_dispose + 24
13 My App 0x00000001000d88fc -[CCAction dealloc] + 44
14 My App 0x00000001000e6bf8 -[CCActionSequence .cxx_destruct] + 36
...and it continues on like this forever. Some kind of infinite recursion happening in dealloc that is causing a stack overflow.
There are only 2 method calls that are visible to me and one of them is .cxx_destruct which is an internal private method used by ARC. The other is the dealloc method of CCAction which only has a log statement in it:
-(void) dealloc {
CCLOGINFO(#"cocos2d: deallocing %#", self);
}
The crash is really hard to reproduce; I've only seen it once. However my app has not been released to the public yet so I'd really like to figure out what is causing it. Any help debugging this would be greatly appreciated.
I am using Cocos2D 3.3.0 and iOS 8.1
If you are using ARC, sending messages to self in dealloc doesn't work like how it used to in manual memory management. ARC does all of the cleanup/disposing in .cxx_destruct BEFORE calling dealloc, so sending messages to self in dealloc will cause undefined behavior - most probably crashes. Unlike in manual memory management where you can send messages to self in dealloc before calling [super dealloc].
From your code, it looks like CCLogInfo is sending a message to self, most probably [self description] (assuming CCLogInfo parameters are just a format string with arguments). This will cause a crash, but I'm not sure why it is causing recursion - can you share the code to CCLogInfo?
I have a very simple class:
#interface WORef : NSObject
#property(nonatomic,weak) NSObject * object;
#end
Instances are stored in an NSArray and from time to time (only on the main thread) this array is iterated and I access the "object" property.
All works fine when testing or debugging, but in the production version of my app on the store I sometimes get crash reports when dereferencing the "object" property (the stack trace actually shows the line number of the property definition).
Here is an example of such a call stack:
Thread : Crashed: com.apple.main-thread
0 libsystem_platform.dylib 0x35180518 _os_lock_recursive_abort + 18446744073709552000
1 libsystem_platform.dylib 0x3518050f _os_lock_handoff_lock_slow + 90
2 libobjc.A.dylib 0x34adac3f objc_object::sidetable_release_slow((anonymous namespace)::SideTable*, bool) + 22
3 libobjc.A.dylib 0x34adad2f objc_object::sidetable_release(bool) + 118
4 Foundation 0x27f56f01 -[NSOperationQueue dealloc] + 72
5 libobjc.A.dylib 0x34adad5f objc_object::sidetable_release(bool) + 166
6 libobjc.A.dylib 0x34ac14d9 _class_initialize + 536
7 libobjc.A.dylib 0x34ac705f lookUpImpOrForward + 254
8 libobjc.A.dylib 0x34ac6f1b lookUpImpOrNil + 26
9 libobjc.A.dylib 0x34abfab3 class_getMethodImplementation + 34
10 libobjc.A.dylib 0x34ada583 weak_read_no_lock + 58
11 libobjc.A.dylib 0x34ada871 objc_loadWeakRetained + 92
12 MyApp 0x000c5983 -[WORef object] (WeakRef.m:12)
Anyone know what might be causing this?
// consider this method
-(void)populateArray {
WORef *ref = [WORef new];
ref.object = [YourObject new];
return #[ref];
// once you get out of this scope, the memory space occupied by [YourObject new]
// can be re-allocate to something else and your ref.object would still point at
// that memory space. You would get random crashes depending on when this memory space get re-allocated.
// The reason being is that ref.object hold a weak reference to [YourObject new]
// so it reference count doesn't get incremented.
// Change your property declaration to (nonatomic,strong) instead
}
I know similar questions have been asked but they all have different answers and none seem to help me.
So, I've got an app called TherapistScheduler, which has therapistScheduler.xcdatamodel in a /Data folder at the root of the project. Inside that folder is a Session.h and Session.m file, which match up with my Session entity in my data model.
My app delegate has the functions managedObjectContext, managedObjectModel, and persistantStoreCoodinator in it.
Inside my applicationDidFinishLaunching method, I've added a view controller (loginViewController) over the top of my rootViewController (which is a tabBarController), and I'm trying to access my Session entity from there.
I'm using the following code to try and save a value - this is throwing the error:
// create session
Session *session = (Session *) [NSEntityDescription insertNewObjectForEntityForName:#"Session" inManagedObjectContext:self.managedObjectContext];
[session setSessionHash:strUserhash];
The loginViewController.h file contains:
NSManagedObjectContext *managedObjectContext; // in the interface declaration
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext; // after the interface
The loginViewController.m file contains
#synthesize managedObjectContext;
Do I need to do something in the loginViewController viewDidLoad to initialise the managedObjectContext? I'm a bit lost as to how this all works. I want to be able to access the data stored in the managedObjectContext from any view I switch to on the tab bar.
I know I'll probably need to add more code to the question, but I don't know what else is needed.
The error I'm getting is this:
TherapistScheduler[40752:207] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+entityForName: could not locate an NSManagedObjectModel for entity name 'Session''
*** Call stack at first throw:
(
0 CoreFoundation 0x02581919 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x0295b5de objc_exception_throw + 47
2 CoreData 0x0004525b +[NSEntityDescription entityForName:inManagedObjectContext:] + 187
3 CoreData 0x0007cd8b +[NSEntityDescription insertNewObjectForEntityForName:inManagedObjectContext:] + 59
4 TherapistScheduler 0x000030ce -[LoginViewController processLoginForUserhash:andType:] + 142
5 TherapistScheduler 0x000039fa -[LoginViewController connectionDidFinishLoading:] + 330
6 Foundation 0x01f91666 -[NSURLConnection(NSURLConnectionReallyInternal) sendDidFinishLoading] + 108
7 Foundation 0x01f915bf _NSURLConnectionDidFinishLoading + 133
8 CFNetwork 0x02b8d9f1 _ZN19URLConnectionClient23_clientDidFinishLoadingEPNS_26ClientConnectionEventQueueE + 285
9 CFNetwork 0x02c56c72 _ZN19URLConnectionClient26ClientConnectionEventQueue33processAllEventsAndConsumePayloadEP20XConnectionEventInfoI12XClientEvent18XClientEventParamsEl + 402
10 CFNetwork 0x02c570ea _ZN19URLConnectionClient26ClientConnectionEventQueue33processAllEventsAndConsumePayloadEP20XConnectionEventInfoI12XClientEvent18XClientEventParamsEl + 1546
11 CFNetwork 0x02c570ea _ZN19URLConnectionClient26ClientConnectionEventQueue33processAllEventsAndConsumePayloadEP20XConnectionEventInfoI12XClientEvent18XClientEventParamsEl + 1546
12 CFNetwork 0x02b82dfe _ZN19URLConnectionClient13processEventsEv + 100
13 CFNetwork 0x02b82c95 _ZN17MultiplexerSource7performEv + 247
14 CoreFoundation 0x02562d7f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
15 CoreFoundation 0x024c11dd __CFRunLoopDoSources0 + 333
16 CoreFoundation 0x024c07c6 __CFRunLoopRun + 470
17 CoreFoundation 0x024c0280 CFRunLoopRunSpecific + 208
18 CoreFoundation 0x024c01a1 CFRunLoopRunInMode + 97
19 GraphicsServices 0x02de62c8 GSEventRunModal + 217
20 GraphicsServices 0x02de638d GSEventRun + 115
21 UIKit 0x00215b58 UIApplicationMain + 1160
22 TherapistScheduler 0x00001f3d main + 125
23 TherapistScheduler 0x00001eb5 start + 53
24 ??? 0x00000001 0x0 + 1
)
terminate called after throwing an instance of 'NSException'
I had to refer to the managedObjectContext as a property of the app delegate not self. So it looked like appDelegate.managedObjectContext.
When you passed the managedObjectContext, I think what you did is like this:
TimelineTableViewController * timelineTableViewController;
timelineTableViewController = [TimelineTableViewController alloc];
[timelineTableViewController initWithStyle:UITableViewStylePlain];
timelineTableViewController.managedObjectContext = self.managedObjectContext;
//...
and then in TimelineTableViewController's viewDidLoad: method, you wanted to fetch the data by managedObjectContext, huh?
I debugged this issue and found that TimelineTableViewController's viewDidLoad: will be dispatched quicker than timelineTableViewController.managedObjectContext = self.managedObjectContext; (where you passed the managedObjectContext from parent (or the AppDelegate) to child). So when you were trying to fetch the data, the managedObjectContext is nil actually. That's why you got this issue:
'+entityForName: could not locate an NSManagedObjectModel for entity name 'Session''
WORKAROUND:
What you have to do is to make sure that the managedObjectContext is not nil when you need to fetch the data:
TimelineTableViewController * timelineTableViewController;
timelineTableViewController = [TimelineTableViewController alloc];
timelineTableViewController.managedObjectContext = self.managedObjectContext;
[timelineTableViewController initWithStyle:UITableViewStylePlain];
// ...
I just solved this issue by this way (no need to use AppDelegate's managedObjectContext directly).